mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-18 18:56:43 +00:00
[Clang][OpenMP] Add interchange directive (#93022)
Add the interchange directive which will be introduced in the upcoming OpenMP 6.0 specification. A preview has been published in [Technical Report 12](https://www.openmp.org/wp-content/uploads/openmp-TR12.pdf).
This commit is contained in:
parent
e6668b1be8
commit
5c93a94f5a
@ -2150,6 +2150,10 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_OMPReverseDirective = 307,
|
||||
|
||||
/** OpenMP interchange directive.
|
||||
*/
|
||||
CXCursor_OMPInterchangeDirective = 308,
|
||||
|
||||
/** OpenACC Compute Construct.
|
||||
*/
|
||||
CXCursor_OpenACCComputeConstruct = 320,
|
||||
|
@ -3035,6 +3035,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)); })
|
||||
|
||||
|
@ -1009,7 +1009,7 @@ public:
|
||||
static bool classof(const Stmt *T) {
|
||||
Stmt::StmtClass C = T->getStmtClass();
|
||||
return C == OMPTileDirectiveClass || C == OMPUnrollDirectiveClass ||
|
||||
C == OMPReverseDirectiveClass;
|
||||
C == OMPReverseDirectiveClass || C == OMPInterchangeDirectiveClass;
|
||||
}
|
||||
};
|
||||
|
||||
@ -5776,6 +5776,80 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/// 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
|
||||
|
@ -231,6 +231,7 @@ def OMPLoopTransformationDirective : StmtNode<OMPLoopBasedDirective, 1>;
|
||||
def OMPTileDirective : StmtNode<OMPLoopTransformationDirective>;
|
||||
def OMPUnrollDirective : StmtNode<OMPLoopTransformationDirective>;
|
||||
def OMPReverseDirective : StmtNode<OMPLoopTransformationDirective>;
|
||||
def OMPInterchangeDirective : StmtNode<OMPLoopTransformationDirective>;
|
||||
def OMPForDirective : StmtNode<OMPLoopDirective>;
|
||||
def OMPForSimdDirective : StmtNode<OMPLoopDirective>;
|
||||
def OMPSectionsDirective : StmtNode<OMPExecutableDirective>;
|
||||
|
@ -426,6 +426,12 @@ public:
|
||||
/// 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,
|
||||
SourceLocation EndLoc);
|
||||
/// Called on well-formed '\#pragma omp for' after parsing
|
||||
/// of the associated statement.
|
||||
StmtResult
|
||||
|
@ -1896,6 +1896,7 @@ enum StmtCode {
|
||||
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,
|
||||
|
@ -467,6 +467,26 @@ OMPReverseDirective *OMPReverseDirective::CreateEmpty(const ASTContext &C) {
|
||||
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<OMPInterchangeDirective>(
|
||||
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<OMPInterchangeDirective>(
|
||||
C, NumClauses, /*HasAssociatedStmt=*/true, TransformedStmtOffset + 1,
|
||||
SourceLocation(), SourceLocation(), NumLoops);
|
||||
}
|
||||
|
||||
OMPForSimdDirective *
|
||||
OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc,
|
||||
SourceLocation EndLoc, unsigned CollapsedNum,
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -225,6 +225,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
|
||||
case Stmt::OMPReverseDirectiveClass:
|
||||
EmitOMPReverseDirective(cast<OMPReverseDirective>(*S));
|
||||
break;
|
||||
case Stmt::OMPInterchangeDirectiveClass:
|
||||
EmitOMPInterchangeDirective(cast<OMPInterchangeDirective>(*S));
|
||||
break;
|
||||
case Stmt::OMPForDirectiveClass:
|
||||
EmitOMPForDirective(cast<OMPForDirective>(*S));
|
||||
break;
|
||||
|
@ -189,6 +189,9 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope {
|
||||
PreInits = Unroll->getPreInits();
|
||||
} else if (const auto *Reverse = dyn_cast<OMPReverseDirective>(&S)) {
|
||||
PreInits = Reverse->getPreInits();
|
||||
} else if (const auto *Interchange =
|
||||
dyn_cast<OMPInterchangeDirective>(&S)) {
|
||||
PreInits = Interchange->getPreInits();
|
||||
} else {
|
||||
llvm_unreachable("Unknown loop-based directive kind.");
|
||||
}
|
||||
@ -2770,6 +2773,13 @@ void CodeGenFunction::EmitOMPReverseDirective(const OMPReverseDirective &S) {
|
||||
EmitStmt(S.getTransformedStmt());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
@ -3821,6 +3821,7 @@ public:
|
||||
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);
|
||||
|
@ -2886,6 +2886,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
|
||||
break;
|
||||
}
|
||||
case OMPD_reverse:
|
||||
case OMPD_interchange:
|
||||
case OMPD_declare_target: {
|
||||
SourceLocation DTLoc = ConsumeAnyToken();
|
||||
bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end);
|
||||
|
@ -1467,6 +1467,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:
|
||||
|
@ -40,6 +40,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"
|
||||
@ -4406,6 +4407,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
|
||||
case OMPD_tile:
|
||||
case OMPD_unroll:
|
||||
case OMPD_reverse:
|
||||
case OMPD_interchange:
|
||||
break;
|
||||
default:
|
||||
processCapturedRegions(SemaRef, DKind, CurScope,
|
||||
@ -6290,6 +6292,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);
|
||||
@ -14048,6 +14054,8 @@ bool SemaOpenMP::checkTransformableLoopNest(
|
||||
DependentPreInits = Dir->getPreInits();
|
||||
else if (auto *Dir = dyn_cast<OMPReverseDirective>(Transform))
|
||||
DependentPreInits = Dir->getPreInits();
|
||||
else if (auto *Dir = dyn_cast<OMPInterchangeDirective>(Transform))
|
||||
DependentPreInits = Dir->getPreInits();
|
||||
else
|
||||
llvm_unreachable("Unhandled loop transformation");
|
||||
|
||||
@ -14853,6 +14861,158 @@ 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<int>(NumLoops)) {
|
||||
OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
|
||||
|
||||
assert(LoopHelper.Counters.size() == 1 &&
|
||||
"Single-dimensional loop iteration space expected");
|
||||
auto *OrigCntVar = cast<DeclRefExpr>(LoopHelper.Counters.front());
|
||||
|
||||
std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
|
||||
addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I],
|
||||
PreInits);
|
||||
}
|
||||
|
||||
SmallVector<VarDecl *> PermutedIndVars(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<int>(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<DeclRefExpr>(SourceHelper.Counters.front());
|
||||
|
||||
// Normalized loop counter variable: From 0 to n-1, always an integer type.
|
||||
DeclRefExpr *IterVarRef = cast<DeclRefExpr>(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.
|
||||
SmallString<64> PermutedCntName(".permuted_");
|
||||
PermutedCntName.append({llvm::utostr(TargetIdx), ".iv.", OrigVarName});
|
||||
auto *PermutedCntDecl = cast<VarDecl>(IterVarRef->getDecl());
|
||||
PermutedCntDecl->setDeclName(
|
||||
&SemaRef.PP.getIdentifierTable().get(PermutedCntName));
|
||||
PermutedIndVars[TargetIdx] = PermutedCntDecl;
|
||||
auto MakePermutedRef = [this, PermutedCntDecl, IVTy, OrigVarLoc]() {
|
||||
return buildDeclRefExpr(SemaRef, PermutedCntDecl, IVTy, OrigVarLoc);
|
||||
};
|
||||
|
||||
// For init-statement:
|
||||
// \code
|
||||
// auto .permuted_{target}.iv = 0
|
||||
// \endcode
|
||||
ExprResult Zero = SemaRef.ActOnIntegerConstant(OrigVarLoc, 0);
|
||||
if (!Zero.isUsable())
|
||||
return StmtError();
|
||||
SemaRef.AddInitializerToDecl(PermutedCntDecl, Zero.get(),
|
||||
/*DirectInit=*/false);
|
||||
StmtResult InitStmt = new (Context)
|
||||
DeclStmt(DeclGroupRef(PermutedCntDecl), OrigCntVar->getBeginLoc(),
|
||||
OrigCntVar->getEndLoc());
|
||||
if (!InitStmt.isUsable())
|
||||
return StmtError();
|
||||
|
||||
// For cond-expression:
|
||||
// \code
|
||||
// .permuted_{target}.iv < MakeNumIterations()
|
||||
// \endcode
|
||||
ExprResult CondExpr =
|
||||
SemaRef.BuildBinOp(CurScope, SourceHelper.Cond->getExprLoc(), BO_LT,
|
||||
MakePermutedRef(), MakeNumIterations());
|
||||
if (!CondExpr.isUsable())
|
||||
return StmtError();
|
||||
|
||||
// For incr-statement:
|
||||
// \code
|
||||
// ++.tile.iv
|
||||
// \endcode
|
||||
ExprResult IncrStmt = SemaRef.BuildUnaryOp(
|
||||
CurScope, SourceHelper.Inc->getExprLoc(), UO_PreInc, MakePermutedRef());
|
||||
if (!IncrStmt.isUsable())
|
||||
return StmtError();
|
||||
|
||||
SmallVector<Stmt *, 4> BodyParts(SourceHelper.Updates.begin(),
|
||||
SourceHelper.Updates.end());
|
||||
if (auto *SourceCXXFor = dyn_cast<CXXForRangeStmt>(SourceLoopStmt))
|
||||
BodyParts.push_back(SourceCXXFor->getLoopVarStmt());
|
||||
BodyParts.push_back(Inner);
|
||||
Inner = CompoundStmt::Create(Context, BodyParts, FPOptionsOverride(),
|
||||
Inner->getBeginLoc(), Inner->getEndLoc());
|
||||
Inner = new (Context) ForStmt(
|
||||
Context, InitStmt.get(), CondExpr.get(), nullptr, IncrStmt.get(), Inner,
|
||||
SourceHelper.Init->getBeginLoc(), SourceHelper.Init->getBeginLoc(),
|
||||
SourceHelper.Inc->getEndLoc());
|
||||
}
|
||||
|
||||
return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
|
||||
NumLoops, AStmt, Inner,
|
||||
buildPreInits(Context, PreInits));
|
||||
}
|
||||
|
||||
OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
|
||||
Expr *Expr,
|
||||
SourceLocation StartLoc,
|
||||
|
@ -9250,6 +9250,17 @@ TreeTransform<Derived>::TransformOMPReverseDirective(OMPReverseDirective *D) {
|
||||
return Res;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
StmtResult TreeTransform<Derived>::TransformOMPInterchangeDirective(
|
||||
OMPInterchangeDirective *D) {
|
||||
DeclarationNameInfo DirName;
|
||||
getDerived().getSema().OpenMP().StartOpenMPDSABlock(
|
||||
D->getDirectiveKind(), DirName, nullptr, D->getBeginLoc());
|
||||
StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
|
||||
getDerived().getSema().OpenMP().EndOpenMPDSABlock(Res.get());
|
||||
return Res;
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
StmtResult
|
||||
TreeTransform<Derived>::TransformOMPForDirective(OMPForDirective *D) {
|
||||
|
@ -2449,6 +2449,10 @@ void ASTStmtReader::VisitOMPReverseDirective(OMPReverseDirective *D) {
|
||||
VisitOMPLoopTransformationDirective(D);
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
|
||||
VisitOMPLoopTransformationDirective(D);
|
||||
}
|
||||
|
||||
void ASTStmtReader::VisitOMPForDirective(OMPForDirective *D) {
|
||||
VisitOMPLoopDirective(D);
|
||||
D->setHasCancel(Record.readBool());
|
||||
@ -3477,6 +3481,13 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
|
||||
break;
|
||||
}
|
||||
|
||||
case STMT_OMP_INTERCHANGE_DIRECTIVE: {
|
||||
unsigned NumLoops = Record[ASTStmtReader::NumStmtFields];
|
||||
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1];
|
||||
S = OMPInterchangeDirective::CreateEmpty(Context, NumClauses, NumLoops);
|
||||
break;
|
||||
}
|
||||
|
||||
case STMT_OMP_FOR_DIRECTIVE: {
|
||||
unsigned CollapsedNum = Record[ASTStmtReader::NumStmtFields];
|
||||
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields + 1];
|
||||
|
@ -2442,6 +2442,11 @@ void ASTStmtWriter::VisitOMPReverseDirective(OMPReverseDirective *D) {
|
||||
Code = serialization::STMT_OMP_REVERSE_DIRECTIVE;
|
||||
}
|
||||
|
||||
void ASTStmtWriter::VisitOMPInterchangeDirective(OMPInterchangeDirective *D) {
|
||||
VisitOMPLoopTransformationDirective(D);
|
||||
Code = serialization::STMT_OMP_INTERCHANGE_DIRECTIVE;
|
||||
}
|
||||
|
||||
void ASTStmtWriter::VisitOMPForDirective(OMPForDirective *D) {
|
||||
VisitOMPLoopDirective(D);
|
||||
Record.writeBool(D->hasCancel());
|
||||
|
@ -1813,6 +1813,7 @@ void ExprEngine::Visit(const Stmt *S, ExplodedNode *Pred,
|
||||
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
|
||||
case Stmt::OMPReverseDirectiveClass:
|
||||
case Stmt::OMPTileDirectiveClass:
|
||||
case Stmt::OMPInterchangeDirectiveClass:
|
||||
case Stmt::OMPInteropDirectiveClass:
|
||||
case Stmt::OMPDispatchDirectiveClass:
|
||||
case Stmt::OMPMaskedDirectiveClass:
|
||||
|
135
clang/test/OpenMP/interchange_ast_print.cpp
Normal file
135
clang/test/OpenMP/interchange_ast_print.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
// Check no warnings/errors
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++20 -fopenmp -fopenmp-version=60 -fsyntax-only -verify %s
|
||||
// expected-no-diagnostics
|
||||
|
||||
// Check AST and unparsing
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++20 -fopenmp -fopenmp-version=60 -ast-dump %s | FileCheck %s --check-prefix=DUMP
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++20 -fopenmp -fopenmp-version=60 -ast-print %s | FileCheck %s --check-prefix=PRINT
|
||||
|
||||
// Check same results after serialization round-trip
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++20 -fopenmp -fopenmp-version=60 -emit-pch -o %t %s
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++20 -fopenmp -fopenmp-version=60 -include-pch %t -ast-dump-all %s | FileCheck %s --check-prefix=DUMP
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++20 -fopenmp -fopenmp-version=60 -include-pch %t -ast-print %s | FileCheck %s --check-prefix=PRINT
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
// placeholder for loop body code.
|
||||
extern "C" void body(...);
|
||||
|
||||
// PRINT-LABEL: void foo1(
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} foo1
|
||||
void foo1() {
|
||||
// PRINT: #pragma omp interchange
|
||||
// DUMP: OMPInterchangeDirective
|
||||
#pragma omp interchange
|
||||
// PRINT: for (int i = 7; i < 17; i += 3)
|
||||
// DUMP-NEXT: ForStmt
|
||||
for (int i = 7; i < 17; i += 3)
|
||||
// PRINT: for (int j = 7; j < 17; j += 3)
|
||||
// DUMP: ForStmt
|
||||
for (int j = 7; j < 17; j += 3)
|
||||
// PRINT: body(i, j);
|
||||
// DUMP: CallExpr
|
||||
body(i, j);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// PRINT-LABEL: void foo3(
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} foo3
|
||||
void foo3() {
|
||||
// PRINT: #pragma omp for collapse(3)
|
||||
// DUMP: OMPForDirective
|
||||
// DUMP-NEXT: OMPCollapseClause
|
||||
// DUMP-NEXT: ConstantExpr
|
||||
// DUMP-NEXT: value: Int 3
|
||||
// DUMP-NEXT: IntegerLiteral {{.*}} 3
|
||||
// DUMP-NEXT: CapturedStmt
|
||||
// DUMP-NEXT: CapturedDecl
|
||||
#pragma omp for collapse(3)
|
||||
// PRINT: #pragma omp interchange
|
||||
// DUMP: OMPInterchangeDirective
|
||||
#pragma omp interchange
|
||||
// PRINT: for (int i = 7; i < 17; i += 1)
|
||||
// DUMP-NEXT: ForStmt
|
||||
for (int i = 7; i < 17; i += 1)
|
||||
// PRINT: for (int j = 7; j < 17; j += 1)
|
||||
// DUMP: ForStmt
|
||||
for (int j = 7; j < 17; j += 1)
|
||||
// PRINT: for (int k = 7; k < 17; k += 1)
|
||||
// DUMP: ForStmt
|
||||
for (int k = 7; k < 17; k += 1)
|
||||
// PRINT: body(i, j, k);
|
||||
// DUMP: CallExpr
|
||||
body(i, j, k);
|
||||
}
|
||||
|
||||
|
||||
// PRINT-LABEL: void foo6(
|
||||
// DUMP-LABEL: FunctionTemplateDecl {{.*}} foo6
|
||||
template<int Tile>
|
||||
void foo6() {
|
||||
// PRINT: #pragma omp interchange
|
||||
// DUMP: OMPInterchangeDirective
|
||||
#pragma omp interchange
|
||||
// PRINT-NEXT: for (int i = 0; i < 11; i += 2)
|
||||
// DUMP-NEXT: ForStmt
|
||||
for (int i = 0; i < 11; i += 2)
|
||||
// PRINT-NEXT: #pragma omp tile sizes(Tile)
|
||||
// DUMP: OMPTileDirective
|
||||
#pragma omp tile sizes(Tile)
|
||||
// PRINT-NEXT: for (int j = 0; j < 13; j += 2)
|
||||
// DUMP: ForStmt
|
||||
for (int j = 0; j < 13; j += 2)
|
||||
// PRINT-NEXT: body(i, j);
|
||||
// DUMP: CallExpr
|
||||
body(i, j);
|
||||
}
|
||||
|
||||
// Also test instantiating the template.
|
||||
void tfoo6() {
|
||||
foo6<32>();
|
||||
}
|
||||
|
||||
|
||||
// PRINT-LABEL: void foo7(
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} foo7
|
||||
void foo7() {
|
||||
double arr[128];
|
||||
// PRINT: #pragma omp interchange
|
||||
// DUMP: OMPInterchangeDirective
|
||||
#pragma omp interchange
|
||||
// PRINT-NEXT: for (double c = 42; auto &&v : arr)
|
||||
// DUMP-NEXT: CXXForRangeStmt
|
||||
for (double c = 42; auto &&v : arr)
|
||||
// PRINT-NEXT: for (int i = 0; i < 42; i += 2)
|
||||
// DUMP: ForStmt
|
||||
for (int i = 0; i < 42; i += 2)
|
||||
// PRINT-NEXT: body(c, v, i);
|
||||
// DUMP: CallExpr
|
||||
body(c, v, i);
|
||||
}
|
||||
|
||||
|
||||
// PRINT-LABEL: void foo8(
|
||||
// DUMP-LABEL: FunctionDecl {{.*}} foo8
|
||||
void foo8() {
|
||||
double arr[128];
|
||||
// PRINT: #pragma omp interchange
|
||||
// DUMP: OMPInterchangeDirective
|
||||
#pragma omp interchange
|
||||
// PRINT-NEXT: for (int i = 0; i < 42; i += 2)
|
||||
// DUMP-NEXT: ForStmt
|
||||
for (int i = 0; i < 42; i += 2)
|
||||
// PRINT-NEXT: for (double c = 42; auto &&v : arr)
|
||||
// DUMP: CXXForRangeStmt
|
||||
for (double c = 42; auto &&v : arr)
|
||||
// PRINT-NEXT: body(i, c, v);
|
||||
// DUMP: CallExpr
|
||||
body(i, c, v);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1990
clang/test/OpenMP/interchange_codegen.cpp
Normal file
1990
clang/test/OpenMP/interchange_codegen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
77
clang/test/OpenMP/interchange_messages.cpp
Normal file
77
clang/test/OpenMP/interchange_messages.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -std=c++17 -fopenmp -fopenmp-version=60 -fsyntax-only -Wuninitialized -verify %s
|
||||
|
||||
void func() {
|
||||
|
||||
// expected-warning@+1 {{extra tokens at the end of '#pragma omp interchange' are ignored}}
|
||||
#pragma omp interchange foo
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int j = 0; j < 13; ++j)
|
||||
;
|
||||
|
||||
// expected-error@+1 {{unexpected OpenMP clause 'collapse' in directive '#pragma omp interchange'}}
|
||||
#pragma omp interchange collapse(2)
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int j = 0; j < 13; ++j)
|
||||
;
|
||||
|
||||
{
|
||||
// expected-error@+2 {{expected statement}}
|
||||
#pragma omp interchange
|
||||
}
|
||||
|
||||
// expected-error@+2 {{statement after '#pragma omp interchange' must be a for loop}}
|
||||
#pragma omp interchange
|
||||
int b = 0;
|
||||
|
||||
// expected-error@+3 {{statement after '#pragma omp interchange' must be a for loop}}
|
||||
#pragma omp interchange
|
||||
for (int i = 0; i < 7; ++i)
|
||||
;
|
||||
|
||||
// expected-error@+2 {{statement after '#pragma omp interchange' must be a for loop}}
|
||||
#pragma omp interchange
|
||||
for (int i = 0; i < 7; ++i) {
|
||||
int k = 3;
|
||||
for (int j = 0; j < 7; ++j)
|
||||
;
|
||||
}
|
||||
|
||||
// expected-error@+3 {{expected loop invariant expression}}
|
||||
#pragma omp interchange
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int j = i; j < 7; ++j)
|
||||
;
|
||||
|
||||
// expected-error@+3 {{expected loop invariant expression}}
|
||||
#pragma omp interchange
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int j = 0; j < i; ++j)
|
||||
;
|
||||
|
||||
// expected-error@+3 {{expected loop invariant expression}}
|
||||
#pragma omp interchange
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int j = 0; j < i; ++j)
|
||||
;
|
||||
|
||||
// expected-error@+6 {{expected 3 for loops after '#pragma omp for', but found only 2}}
|
||||
// expected-note@+1 {{as specified in 'collapse' clause}}
|
||||
#pragma omp for collapse(3)
|
||||
#pragma omp interchange
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int j = 0; j < 13; ++j)
|
||||
;
|
||||
|
||||
// expected-error@+2 {{statement after '#pragma omp interchange' must be a for loop}}
|
||||
#pragma omp interchange
|
||||
#pragma omp for
|
||||
for (int i = 0; i < 7; ++i)
|
||||
;
|
||||
|
||||
// expected-error@+3 {{condition of OpenMP for loop must be a relational comparison ('<', '<=', '>', '>=', or '!=') of loop variable 'j'}}
|
||||
#pragma omp interchange
|
||||
for (int i = 0; i < 7; ++i)
|
||||
for (int j = 0; j/3<7; ++j)
|
||||
;
|
||||
}
|
||||
|
@ -2183,6 +2183,7 @@ public:
|
||||
void VisitOMPTileDirective(const OMPTileDirective *D);
|
||||
void VisitOMPUnrollDirective(const OMPUnrollDirective *D);
|
||||
void VisitOMPReverseDirective(const OMPReverseDirective *D);
|
||||
void VisitOMPInterchangeDirective(const OMPInterchangeDirective *D);
|
||||
void VisitOMPForDirective(const OMPForDirective *D);
|
||||
void VisitOMPForSimdDirective(const OMPForSimdDirective *D);
|
||||
void VisitOMPSectionsDirective(const OMPSectionsDirective *D);
|
||||
@ -3233,6 +3234,11 @@ void EnqueueVisitor::VisitOMPReverseDirective(const OMPReverseDirective *D) {
|
||||
VisitOMPLoopTransformationDirective(D);
|
||||
}
|
||||
|
||||
void EnqueueVisitor::VisitOMPInterchangeDirective(
|
||||
const OMPInterchangeDirective *D) {
|
||||
VisitOMPLoopTransformationDirective(D);
|
||||
}
|
||||
|
||||
void EnqueueVisitor::VisitOMPForDirective(const OMPForDirective *D) {
|
||||
VisitOMPLoopDirective(D);
|
||||
}
|
||||
@ -6104,6 +6110,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
|
||||
return cxstring::createRef("OMPUnrollDirective");
|
||||
case CXCursor_OMPReverseDirective:
|
||||
return cxstring::createRef("OMPReverseDirective");
|
||||
case CXCursor_OMPInterchangeDirective:
|
||||
return cxstring::createRef("OMPInterchangeDirective");
|
||||
case CXCursor_OMPForDirective:
|
||||
return cxstring::createRef("OMPForDirective");
|
||||
case CXCursor_OMPForSimdDirective:
|
||||
|
@ -676,6 +676,9 @@ CXCursor cxcursor::MakeCXCursor(const Stmt *S, const Decl *Parent,
|
||||
case Stmt::OMPReverseDirectiveClass:
|
||||
K = CXCursor_OMPReverseDirective;
|
||||
break;
|
||||
case Stmt::OMPInterchangeDirectiveClass:
|
||||
K = CXCursor_OMPTileDirective;
|
||||
break;
|
||||
case Stmt::OMPForDirectiveClass:
|
||||
K = CXCursor_OMPForDirective;
|
||||
break;
|
||||
|
@ -735,6 +735,10 @@ def OMP_For : Directive<"for"> {
|
||||
let association = AS_Loop;
|
||||
let category = CA_Executable;
|
||||
}
|
||||
def OMP_Interchange : Directive<"interchange"> {
|
||||
let association = AS_Loop;
|
||||
let category = CA_Executable;
|
||||
}
|
||||
def OMP_interop : Directive<"interop"> {
|
||||
let allowedClauses = [
|
||||
VersionedClause<OMPC_Depend>,
|
||||
|
216
openmp/runtime/test/transform/interchange/foreach.cpp
Normal file
216
openmp/runtime/test/transform/interchange/foreach.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
// RUN: %libomp-cxx20-compile-and-run | FileCheck %s --match-full-lines
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
struct Reporter {
|
||||
const char *name;
|
||||
|
||||
Reporter(const char *name) : name(name) { print("ctor"); }
|
||||
|
||||
Reporter() : name("<anon>") { print("ctor"); }
|
||||
|
||||
Reporter(const Reporter &that) : name(that.name) { print("copy ctor"); }
|
||||
|
||||
Reporter(Reporter &&that) : name(that.name) { print("move ctor"); }
|
||||
|
||||
~Reporter() { print("dtor"); }
|
||||
|
||||
const Reporter &operator=(const Reporter &that) {
|
||||
print("copy assign");
|
||||
this->name = that.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Reporter &operator=(Reporter &&that) {
|
||||
print("move assign");
|
||||
this->name = that.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
const Reporter *owner;
|
||||
int pos;
|
||||
|
||||
Iterator(const Reporter *owner, int pos) : owner(owner), pos(pos) {}
|
||||
|
||||
Iterator(const Iterator &that) : owner(that.owner), pos(that.pos) {
|
||||
owner->print("iterator copy ctor");
|
||||
}
|
||||
|
||||
Iterator(Iterator &&that) : owner(that.owner), pos(that.pos) {
|
||||
owner->print("iterator move ctor");
|
||||
}
|
||||
|
||||
~Iterator() { owner->print("iterator dtor"); }
|
||||
|
||||
const Iterator &operator=(const Iterator &that) {
|
||||
owner->print("iterator copy assign");
|
||||
this->owner = that.owner;
|
||||
this->pos = that.pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Iterator &operator=(Iterator &&that) {
|
||||
owner->print("iterator move assign");
|
||||
this->owner = that.owner;
|
||||
this->pos = that.pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator &that) const {
|
||||
owner->print("iterator %d == %d", 2 - this->pos, 2 - that.pos);
|
||||
return this->pos == that.pos;
|
||||
}
|
||||
|
||||
Iterator &operator++() {
|
||||
owner->print("iterator prefix ++");
|
||||
pos -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int) {
|
||||
owner->print("iterator postfix ++");
|
||||
auto result = *this;
|
||||
pos -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
int operator*() const {
|
||||
int result = 2 - pos;
|
||||
owner->print("iterator deref: %i", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t operator-(const Iterator &that) const {
|
||||
int result = (2 - this->pos) - (2 - that.pos);
|
||||
owner->print("iterator distance: %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Iterator operator+(int steps) const {
|
||||
owner->print("iterator advance: %i += %i", 2 - this->pos, steps);
|
||||
return Iterator(owner, pos - steps);
|
||||
}
|
||||
|
||||
void print(const char *msg) const { owner->print(msg); }
|
||||
};
|
||||
|
||||
Iterator begin() const {
|
||||
print("begin()");
|
||||
return Iterator(this, 2);
|
||||
}
|
||||
|
||||
Iterator end() const {
|
||||
print("end()");
|
||||
return Iterator(this, -1);
|
||||
}
|
||||
|
||||
void print(const char *msg, ...) const {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
printf("[%s] ", name);
|
||||
vprintf(msg, args);
|
||||
printf("\n");
|
||||
va_end(args);
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
printf("do\n");
|
||||
#pragma omp interchange
|
||||
for (Reporter c{"C"}; auto &&v : Reporter("A"))
|
||||
for (Reporter d{"D"}; auto &&w : Reporter("B"))
|
||||
printf("v=%d w=%d\n", v, w);
|
||||
printf("done\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HEADER */
|
||||
|
||||
// CHECK: do
|
||||
// CHECK-NEXT: [C] ctor
|
||||
// CHECK-NEXT: [A] ctor
|
||||
// CHECK-NEXT: [A] end()
|
||||
// CHECK-NEXT: [A] begin()
|
||||
// CHECK-NEXT: [A] begin()
|
||||
// CHECK-NEXT: [A] iterator distance: 3
|
||||
// CHECK-NEXT: [D] ctor
|
||||
// CHECK-NEXT: [B] ctor
|
||||
// CHECK-NEXT: [B] end()
|
||||
// CHECK-NEXT: [B] begin()
|
||||
// CHECK-NEXT: [B] begin()
|
||||
// CHECK-NEXT: [B] iterator distance: 3
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: v=0 w=0
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: v=1 w=0
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: v=2 w=0
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: v=0 w=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: v=1 w=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: v=2 w=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: v=0 w=2
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: v=1 w=2
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: v=2 w=2
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] dtor
|
||||
// CHECK-NEXT: [D] dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] dtor
|
||||
// CHECK-NEXT: [C] dtor
|
||||
// CHECK-NEXT: done
|
38
openmp/runtime/test/transform/interchange/intfor.c
Normal file
38
openmp/runtime/test/transform/interchange/intfor.c
Normal file
@ -0,0 +1,38 @@
|
||||
// RUN: %libomp-compile-and-run | FileCheck %s --match-full-lines
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("do\n");
|
||||
#pragma omp interchange
|
||||
for (int i = 7; i < 17; i += 3)
|
||||
for (int j = 8; j < 18; j += 3)
|
||||
printf("i=%d j=%d\n", i, j);
|
||||
printf("done\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HEADER */
|
||||
|
||||
// CHECK: do
|
||||
// CHECK-NEXT: i=7 j=8
|
||||
// CHECK-NEXT: i=10 j=8
|
||||
// CHECK-NEXT: i=13 j=8
|
||||
// CHECK-NEXT: i=16 j=8
|
||||
// CHECK-NEXT: i=7 j=11
|
||||
// CHECK-NEXT: i=10 j=11
|
||||
// CHECK-NEXT: i=13 j=11
|
||||
// CHECK-NEXT: i=16 j=11
|
||||
// CHECK-NEXT: i=7 j=14
|
||||
// CHECK-NEXT: i=10 j=14
|
||||
// CHECK-NEXT: i=13 j=14
|
||||
// CHECK-NEXT: i=16 j=14
|
||||
// CHECK-NEXT: i=7 j=17
|
||||
// CHECK-NEXT: i=10 j=17
|
||||
// CHECK-NEXT: i=13 j=17
|
||||
// CHECK-NEXT: i=16 j=17
|
||||
// CHECK-NEXT: done
|
222
openmp/runtime/test/transform/interchange/iterfor.cpp
Normal file
222
openmp/runtime/test/transform/interchange/iterfor.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
// RUN: %libomp-cxx20-compile-and-run | FileCheck %s --match-full-lines
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
struct Reporter {
|
||||
const char *name;
|
||||
|
||||
Reporter(const char *name) : name(name) { print("ctor"); }
|
||||
|
||||
Reporter() : name("<anon>") { print("ctor"); }
|
||||
|
||||
Reporter(const Reporter &that) : name(that.name) { print("copy ctor"); }
|
||||
|
||||
Reporter(Reporter &&that) : name(that.name) { print("move ctor"); }
|
||||
|
||||
~Reporter() { print("dtor"); }
|
||||
|
||||
const Reporter &operator=(const Reporter &that) {
|
||||
print("copy assign");
|
||||
this->name = that.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Reporter &operator=(Reporter &&that) {
|
||||
print("move assign");
|
||||
this->name = that.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
const Reporter *owner;
|
||||
int pos;
|
||||
|
||||
Iterator(const Reporter *owner, int pos) : owner(owner), pos(pos) {}
|
||||
|
||||
Iterator(const Iterator &that) : owner(that.owner), pos(that.pos) {
|
||||
owner->print("iterator copy ctor");
|
||||
}
|
||||
|
||||
Iterator(Iterator &&that) : owner(that.owner), pos(that.pos) {
|
||||
owner->print("iterator move ctor");
|
||||
}
|
||||
|
||||
~Iterator() { owner->print("iterator dtor"); }
|
||||
|
||||
const Iterator &operator=(const Iterator &that) {
|
||||
owner->print("iterator copy assign");
|
||||
this->owner = that.owner;
|
||||
this->pos = that.pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Iterator &operator=(Iterator &&that) {
|
||||
owner->print("iterator move assign");
|
||||
this->owner = that.owner;
|
||||
this->pos = that.pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator &that) const {
|
||||
owner->print("iterator %d == %d", 2 - this->pos, 2 - that.pos);
|
||||
return this->pos == that.pos;
|
||||
}
|
||||
|
||||
bool operator!=(const Iterator &that) const {
|
||||
owner->print("iterator %d != %d", 2 - this->pos, 2 - that.pos);
|
||||
return this->pos == that.pos;
|
||||
}
|
||||
|
||||
Iterator &operator++() {
|
||||
owner->print("iterator prefix ++");
|
||||
pos -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int) {
|
||||
owner->print("iterator postfix ++");
|
||||
auto result = *this;
|
||||
pos -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
int operator*() const {
|
||||
int result = 2 - pos;
|
||||
owner->print("iterator deref: %i", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t operator-(const Iterator &that) const {
|
||||
int result = (2 - this->pos) - (2 - that.pos);
|
||||
owner->print("iterator distance: %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Iterator operator+(int steps) const {
|
||||
owner->print("iterator advance: %i += %i", 2 - this->pos, steps);
|
||||
return Iterator(owner, pos - steps);
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() const {
|
||||
print("begin()");
|
||||
return Iterator(this, 2);
|
||||
}
|
||||
|
||||
Iterator end() const {
|
||||
print("end()");
|
||||
return Iterator(this, -1);
|
||||
}
|
||||
|
||||
void print(const char *msg, ...) const {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
printf("[%s] ", name);
|
||||
vprintf(msg, args);
|
||||
printf("\n");
|
||||
va_end(args);
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
printf("do\n");
|
||||
Reporter A("A"), B("B");
|
||||
#pragma omp interchange
|
||||
for (auto it = A.begin(); it != A.end(); ++it)
|
||||
for (auto jt = B.begin(); jt != B.end(); ++jt)
|
||||
printf("i=%d j=%d\n", *it, *jt);
|
||||
printf("done\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HEADER */
|
||||
|
||||
// CHECK: do
|
||||
// CHECK-NEXT: [A] ctor
|
||||
// CHECK-NEXT: [B] ctor
|
||||
// CHECK-NEXT: [A] begin()
|
||||
// CHECK-NEXT: [A] begin()
|
||||
// CHECK-NEXT: [A] end()
|
||||
// CHECK-NEXT: [A] iterator distance: 3
|
||||
// CHECK-NEXT: [B] begin()
|
||||
// CHECK-NEXT: [B] begin()
|
||||
// CHECK-NEXT: [B] end()
|
||||
// CHECK-NEXT: [B] iterator distance: 3
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: i=0 j=0
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: i=1 j=0
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: i=2 j=0
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: i=0 j=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: i=1 j=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: i=2 j=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: i=0 j=2
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: i=1 j=2
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: i=2 j=2
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: done
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] dtor
|
||||
// CHECK-NEXT: [A] dtor
|
@ -0,0 +1,340 @@
|
||||
// RUN: %libomp-cxx20-compile-and-run | FileCheck %s --match-full-lines
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdarg>
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
struct Reporter {
|
||||
const char *name;
|
||||
|
||||
Reporter(const char *name) : name(name) { print("ctor"); }
|
||||
|
||||
Reporter() : name("<anon>") { print("ctor"); }
|
||||
|
||||
Reporter(const Reporter &that) : name(that.name) { print("copy ctor"); }
|
||||
|
||||
Reporter(Reporter &&that) : name(that.name) { print("move ctor"); }
|
||||
|
||||
~Reporter() { print("dtor"); }
|
||||
|
||||
const Reporter &operator=(const Reporter &that) {
|
||||
print("copy assign");
|
||||
this->name = that.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Reporter &operator=(Reporter &&that) {
|
||||
print("move assign");
|
||||
this->name = that.name;
|
||||
return *this;
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
const Reporter *owner;
|
||||
int pos;
|
||||
|
||||
Iterator(const Reporter *owner, int pos) : owner(owner), pos(pos) {}
|
||||
|
||||
Iterator(const Iterator &that) : owner(that.owner), pos(that.pos) {
|
||||
owner->print("iterator copy ctor");
|
||||
}
|
||||
|
||||
Iterator(Iterator &&that) : owner(that.owner), pos(that.pos) {
|
||||
owner->print("iterator move ctor");
|
||||
}
|
||||
|
||||
~Iterator() { owner->print("iterator dtor"); }
|
||||
|
||||
const Iterator &operator=(const Iterator &that) {
|
||||
owner->print("iterator copy assign");
|
||||
this->owner = that.owner;
|
||||
this->pos = that.pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const Iterator &operator=(Iterator &&that) {
|
||||
owner->print("iterator move assign");
|
||||
this->owner = that.owner;
|
||||
this->pos = that.pos;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const Iterator &that) const {
|
||||
owner->print("iterator %d == %d", 2 - this->pos, 2 - that.pos);
|
||||
return this->pos == that.pos;
|
||||
}
|
||||
|
||||
Iterator &operator++() {
|
||||
owner->print("iterator prefix ++");
|
||||
pos -= 1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int) {
|
||||
owner->print("iterator postfix ++");
|
||||
auto result = *this;
|
||||
pos -= 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
int operator*() const {
|
||||
int result = 2 - pos;
|
||||
owner->print("iterator deref: %i", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t operator-(const Iterator &that) const {
|
||||
int result = (2 - this->pos) - (2 - that.pos);
|
||||
owner->print("iterator distance: %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
Iterator operator+(int steps) const {
|
||||
owner->print("iterator advance: %i += %i", 2 - this->pos, steps);
|
||||
return Iterator(owner, pos - steps);
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() const {
|
||||
print("begin()");
|
||||
return Iterator(this, 2);
|
||||
}
|
||||
|
||||
Iterator end() const {
|
||||
print("end()");
|
||||
return Iterator(this, -1);
|
||||
}
|
||||
|
||||
void print(const char *msg, ...) const {
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
printf("[%s] ", name);
|
||||
vprintf(msg, args);
|
||||
printf("\n");
|
||||
va_end(args);
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
printf("do\n");
|
||||
#pragma omp parallel for collapse(3) num_threads(1)
|
||||
for (int i = 0; i < 2; ++i)
|
||||
#pragma omp interchange
|
||||
for (Reporter c{"C"}; auto &&v : Reporter("A"))
|
||||
for (Reporter d{"D"}; auto &&w : Reporter("B"))
|
||||
for (int k = 0; k < 2; ++k)
|
||||
printf("i=%d v=%d w=%d k=%d\n", i, v, w, k);
|
||||
printf("done\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HEADER */
|
||||
|
||||
// CHECK: do
|
||||
// CHECK-NEXT: [C] ctor
|
||||
// CHECK-NEXT: [A] ctor
|
||||
// CHECK-NEXT: [A] end()
|
||||
// CHECK-NEXT: [A] begin()
|
||||
// CHECK-NEXT: [A] begin()
|
||||
// CHECK-NEXT: [A] iterator distance: 3
|
||||
// CHECK-NEXT: [D] ctor
|
||||
// CHECK-NEXT: [B] ctor
|
||||
// CHECK-NEXT: [B] end()
|
||||
// CHECK-NEXT: [B] begin()
|
||||
// CHECK-NEXT: [B] begin()
|
||||
// CHECK-NEXT: [B] iterator distance: 3
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: i=0 v=0 w=0 k=0
|
||||
// CHECK-NEXT: i=0 v=0 w=0 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: i=0 v=1 w=0 k=0
|
||||
// CHECK-NEXT: i=0 v=1 w=0 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: i=0 v=2 w=0 k=0
|
||||
// CHECK-NEXT: i=0 v=2 w=0 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: i=0 v=0 w=1 k=0
|
||||
// CHECK-NEXT: i=0 v=0 w=1 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: i=0 v=1 w=1 k=0
|
||||
// CHECK-NEXT: i=0 v=1 w=1 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: i=0 v=2 w=1 k=0
|
||||
// CHECK-NEXT: i=0 v=2 w=1 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: i=0 v=0 w=2 k=0
|
||||
// CHECK-NEXT: i=0 v=0 w=2 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: i=0 v=1 w=2 k=0
|
||||
// CHECK-NEXT: i=0 v=1 w=2 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: i=0 v=2 w=2 k=0
|
||||
// CHECK-NEXT: i=0 v=2 w=2 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: i=1 v=0 w=0 k=0
|
||||
// CHECK-NEXT: i=1 v=0 w=0 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: i=1 v=1 w=0 k=0
|
||||
// CHECK-NEXT: i=1 v=1 w=0 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 0
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: i=1 v=2 w=0 k=0
|
||||
// CHECK-NEXT: i=1 v=2 w=0 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: i=1 v=0 w=1 k=0
|
||||
// CHECK-NEXT: i=1 v=0 w=1 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: i=1 v=1 w=1 k=0
|
||||
// CHECK-NEXT: i=1 v=1 w=1 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 1
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: i=1 v=2 w=1 k=0
|
||||
// CHECK-NEXT: i=1 v=2 w=1 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 0
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 0
|
||||
// CHECK-NEXT: i=1 v=0 w=2 k=0
|
||||
// CHECK-NEXT: i=1 v=0 w=2 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 1
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 1
|
||||
// CHECK-NEXT: i=1 v=1 w=2 k=0
|
||||
// CHECK-NEXT: i=1 v=1 w=2 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [B] iterator move assign
|
||||
// CHECK-NEXT: [B] iterator deref: 2
|
||||
// CHECK-NEXT: [A] iterator advance: 0 += 2
|
||||
// CHECK-NEXT: [A] iterator move assign
|
||||
// CHECK-NEXT: [A] iterator deref: 2
|
||||
// CHECK-NEXT: i=1 v=2 w=2 k=0
|
||||
// CHECK-NEXT: i=1 v=2 w=2 k=1
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] iterator dtor
|
||||
// CHECK-NEXT: [B] dtor
|
||||
// CHECK-NEXT: [D] dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] iterator dtor
|
||||
// CHECK-NEXT: [A] dtor
|
||||
// CHECK-NEXT: [C] dtor
|
||||
// CHECK-NEXT: done
|
@ -0,0 +1,106 @@
|
||||
// RUN: %libomp-cxx-compile-and-run | FileCheck %s --match-full-lines
|
||||
|
||||
#ifndef HEADER
|
||||
#define HEADER
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
int main() {
|
||||
printf("do\n");
|
||||
#pragma omp parallel for collapse(4) num_threads(1)
|
||||
for (int i = 0; i < 3; ++i)
|
||||
#pragma omp interchange
|
||||
for (int j = 0; j < 3; ++j)
|
||||
for (int k = 0; k < 3; ++k)
|
||||
for (int l = 0; l < 3; ++l)
|
||||
printf("i=%d j=%d k=%d l=%d\n", i, j, k, l);
|
||||
printf("done\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#endif /* HEADER */
|
||||
|
||||
// CHECK: do
|
||||
// CHECK-NEXT: i=0 j=0 k=0 l=0
|
||||
// CHECK-NEXT: i=0 j=0 k=0 l=1
|
||||
// CHECK-NEXT: i=0 j=0 k=0 l=2
|
||||
// CHECK-NEXT: i=0 j=1 k=0 l=0
|
||||
// CHECK-NEXT: i=0 j=1 k=0 l=1
|
||||
// CHECK-NEXT: i=0 j=1 k=0 l=2
|
||||
// CHECK-NEXT: i=0 j=2 k=0 l=0
|
||||
// CHECK-NEXT: i=0 j=2 k=0 l=1
|
||||
// CHECK-NEXT: i=0 j=2 k=0 l=2
|
||||
// CHECK-NEXT: i=0 j=0 k=1 l=0
|
||||
// CHECK-NEXT: i=0 j=0 k=1 l=1
|
||||
// CHECK-NEXT: i=0 j=0 k=1 l=2
|
||||
// CHECK-NEXT: i=0 j=1 k=1 l=0
|
||||
// CHECK-NEXT: i=0 j=1 k=1 l=1
|
||||
// CHECK-NEXT: i=0 j=1 k=1 l=2
|
||||
// CHECK-NEXT: i=0 j=2 k=1 l=0
|
||||
// CHECK-NEXT: i=0 j=2 k=1 l=1
|
||||
// CHECK-NEXT: i=0 j=2 k=1 l=2
|
||||
// CHECK-NEXT: i=0 j=0 k=2 l=0
|
||||
// CHECK-NEXT: i=0 j=0 k=2 l=1
|
||||
// CHECK-NEXT: i=0 j=0 k=2 l=2
|
||||
// CHECK-NEXT: i=0 j=1 k=2 l=0
|
||||
// CHECK-NEXT: i=0 j=1 k=2 l=1
|
||||
// CHECK-NEXT: i=0 j=1 k=2 l=2
|
||||
// CHECK-NEXT: i=0 j=2 k=2 l=0
|
||||
// CHECK-NEXT: i=0 j=2 k=2 l=1
|
||||
// CHECK-NEXT: i=0 j=2 k=2 l=2
|
||||
// CHECK-NEXT: i=1 j=0 k=0 l=0
|
||||
// CHECK-NEXT: i=1 j=0 k=0 l=1
|
||||
// CHECK-NEXT: i=1 j=0 k=0 l=2
|
||||
// CHECK-NEXT: i=1 j=1 k=0 l=0
|
||||
// CHECK-NEXT: i=1 j=1 k=0 l=1
|
||||
// CHECK-NEXT: i=1 j=1 k=0 l=2
|
||||
// CHECK-NEXT: i=1 j=2 k=0 l=0
|
||||
// CHECK-NEXT: i=1 j=2 k=0 l=1
|
||||
// CHECK-NEXT: i=1 j=2 k=0 l=2
|
||||
// CHECK-NEXT: i=1 j=0 k=1 l=0
|
||||
// CHECK-NEXT: i=1 j=0 k=1 l=1
|
||||
// CHECK-NEXT: i=1 j=0 k=1 l=2
|
||||
// CHECK-NEXT: i=1 j=1 k=1 l=0
|
||||
// CHECK-NEXT: i=1 j=1 k=1 l=1
|
||||
// CHECK-NEXT: i=1 j=1 k=1 l=2
|
||||
// CHECK-NEXT: i=1 j=2 k=1 l=0
|
||||
// CHECK-NEXT: i=1 j=2 k=1 l=1
|
||||
// CHECK-NEXT: i=1 j=2 k=1 l=2
|
||||
// CHECK-NEXT: i=1 j=0 k=2 l=0
|
||||
// CHECK-NEXT: i=1 j=0 k=2 l=1
|
||||
// CHECK-NEXT: i=1 j=0 k=2 l=2
|
||||
// CHECK-NEXT: i=1 j=1 k=2 l=0
|
||||
// CHECK-NEXT: i=1 j=1 k=2 l=1
|
||||
// CHECK-NEXT: i=1 j=1 k=2 l=2
|
||||
// CHECK-NEXT: i=1 j=2 k=2 l=0
|
||||
// CHECK-NEXT: i=1 j=2 k=2 l=1
|
||||
// CHECK-NEXT: i=1 j=2 k=2 l=2
|
||||
// CHECK-NEXT: i=2 j=0 k=0 l=0
|
||||
// CHECK-NEXT: i=2 j=0 k=0 l=1
|
||||
// CHECK-NEXT: i=2 j=0 k=0 l=2
|
||||
// CHECK-NEXT: i=2 j=1 k=0 l=0
|
||||
// CHECK-NEXT: i=2 j=1 k=0 l=1
|
||||
// CHECK-NEXT: i=2 j=1 k=0 l=2
|
||||
// CHECK-NEXT: i=2 j=2 k=0 l=0
|
||||
// CHECK-NEXT: i=2 j=2 k=0 l=1
|
||||
// CHECK-NEXT: i=2 j=2 k=0 l=2
|
||||
// CHECK-NEXT: i=2 j=0 k=1 l=0
|
||||
// CHECK-NEXT: i=2 j=0 k=1 l=1
|
||||
// CHECK-NEXT: i=2 j=0 k=1 l=2
|
||||
// CHECK-NEXT: i=2 j=1 k=1 l=0
|
||||
// CHECK-NEXT: i=2 j=1 k=1 l=1
|
||||
// CHECK-NEXT: i=2 j=1 k=1 l=2
|
||||
// CHECK-NEXT: i=2 j=2 k=1 l=0
|
||||
// CHECK-NEXT: i=2 j=2 k=1 l=1
|
||||
// CHECK-NEXT: i=2 j=2 k=1 l=2
|
||||
// CHECK-NEXT: i=2 j=0 k=2 l=0
|
||||
// CHECK-NEXT: i=2 j=0 k=2 l=1
|
||||
// CHECK-NEXT: i=2 j=0 k=2 l=2
|
||||
// CHECK-NEXT: i=2 j=1 k=2 l=0
|
||||
// CHECK-NEXT: i=2 j=1 k=2 l=1
|
||||
// CHECK-NEXT: i=2 j=1 k=2 l=2
|
||||
// CHECK-NEXT: i=2 j=2 k=2 l=0
|
||||
// CHECK-NEXT: i=2 j=2 k=2 l=1
|
||||
// CHECK-NEXT: i=2 j=2 k=2 l=2
|
||||
// CHECK-NEXT: done
|
Loading…
x
Reference in New Issue
Block a user