Skip to content

Commit a128366

Browse files
authored
[OpenMP][CodeGen] Improved codegen for combined loop directives (#87278)
IR for 'target teams loop' is now dependent on suitability of associated loop-nest. If a loop-nest: - does not contain a function call, or - the -fopenmp-assume-no-nested-parallelism has been specified, - or the call is to an OpenMP API AND - does not contain nested loop bind(parallel) directives then it can be emitted as 'target teams distribute parallel for', which is the current default. Otherwise, it is emitted as 'target teams distribute'. Added debug output indicating how 'target teams loop' was emitted. Flag is -mllvm -debug-only=target-teams-loop-codegen Added LIT tests explicitly verifying 'target teams loop' emitted as a parallel loop and a distribute loop. Updated other 'loop' related tests as needed to reflect change in IR. - These updates account for most of the changed files and additions/deletions.
1 parent b3792ae commit a128366

20 files changed

+5886
-6903
lines changed

clang/include/clang/AST/StmtOpenMP.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6109,6 +6109,8 @@ class OMPTeamsGenericLoopDirective final : public OMPLoopDirective {
61096109
class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
61106110
friend class ASTStmtReader;
61116111
friend class OMPExecutableDirective;
6112+
/// true if loop directive's associated loop can be a parallel for.
6113+
bool CanBeParallelFor = false;
61126114
/// Build directive with the given start and end location.
61136115
///
61146116
/// \param StartLoc Starting location of the directive kind.
@@ -6131,6 +6133,9 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
61316133
llvm::omp::OMPD_target_teams_loop, SourceLocation(),
61326134
SourceLocation(), CollapsedNum) {}
61336135

6136+
/// Set whether associated loop can be a parallel for.
6137+
void setCanBeParallelFor(bool ParFor) { CanBeParallelFor = ParFor; }
6138+
61346139
public:
61356140
/// Creates directive with a list of \p Clauses.
61366141
///
@@ -6145,7 +6150,7 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
61456150
static OMPTargetTeamsGenericLoopDirective *
61466151
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
61476152
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
6148-
Stmt *AssociatedStmt, const HelperExprs &Exprs);
6153+
Stmt *AssociatedStmt, const HelperExprs &Exprs, bool CanBeParallelFor);
61496154

61506155
/// Creates an empty directive with the place
61516156
/// for \a NumClauses clauses.
@@ -6159,6 +6164,10 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
61596164
unsigned CollapsedNum,
61606165
EmptyShell);
61616166

6167+
/// Return true if current loop directive's associated loop can be a
6168+
/// parallel for.
6169+
bool canBeParallelFor() const { return CanBeParallelFor; }
6170+
61626171
static bool classof(const Stmt *T) {
61636172
return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass;
61646173
}

clang/lib/AST/StmtOpenMP.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2431,7 +2431,7 @@ OMPTeamsGenericLoopDirective::CreateEmpty(const ASTContext &C,
24312431
OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
24322432
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
24332433
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
2434-
const HelperExprs &Exprs) {
2434+
const HelperExprs &Exprs, bool CanBeParallelFor) {
24352435
auto *Dir = createDirective<OMPTargetTeamsGenericLoopDirective>(
24362436
C, Clauses, AssociatedStmt,
24372437
numLoopChildren(CollapsedNum, OMPD_target_teams_loop), StartLoc, EndLoc,
@@ -2473,6 +2473,7 @@ OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
24732473
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
24742474
Dir->setCombinedDistCond(Exprs.DistCombinedFields.DistCond);
24752475
Dir->setCombinedParForInDistCond(Exprs.DistCombinedFields.ParForInDistCond);
2476+
Dir->setCanBeParallelFor(CanBeParallelFor);
24762477
return Dir;
24772478
}
24782479

clang/lib/CodeGen/CGOpenMPRuntime.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2656,11 +2656,12 @@ void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF,
26562656
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
26572657
llvm::Value *Args[] = {
26582658
emitUpdateLocation(CGF, Loc,
2659-
isOpenMPDistributeDirective(DKind)
2659+
isOpenMPDistributeDirective(DKind) ||
2660+
(DKind == OMPD_target_teams_loop)
26602661
? OMP_IDENT_WORK_DISTRIBUTE
2661-
: isOpenMPLoopDirective(DKind)
2662-
? OMP_IDENT_WORK_LOOP
2663-
: OMP_IDENT_WORK_SECTIONS),
2662+
: isOpenMPLoopDirective(DKind)
2663+
? OMP_IDENT_WORK_LOOP
2664+
: OMP_IDENT_WORK_SECTIONS),
26642665
getThreadID(CGF, Loc)};
26652666
auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc);
26662667
if (isOpenMPDistributeDirective(DKind) &&
@@ -8885,7 +8886,8 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
88858886
OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
88868887
switch (D.getDirectiveKind()) {
88878888
case OMPD_target:
8888-
// For now, just treat 'target teams loop' as if it's distributed.
8889+
// For now, treat 'target' with nested 'teams loop' as if it's
8890+
// distributed (target teams distribute).
88898891
if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop)
88908892
return NestedDir;
88918893
if (DKind == OMPD_teams) {
@@ -9369,7 +9371,8 @@ llvm::Value *CGOpenMPRuntime::emitTargetNumIterationsCall(
93699371
SizeEmitter) {
93709372
OpenMPDirectiveKind Kind = D.getDirectiveKind();
93719373
const OMPExecutableDirective *TD = &D;
9372-
// Get nested teams distribute kind directive, if any.
9374+
// Get nested teams distribute kind directive, if any. For now, treat
9375+
// 'target_teams_loop' as if it's really a target_teams_distribute.
93739376
if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) &&
93749377
Kind != OMPD_target_teams_loop)
93759378
TD = getNestedDistributeDirective(CGM.getContext(), D);

clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,6 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
646646
case OMPD_target:
647647
case OMPD_target_teams:
648648
return hasNestedSPMDDirective(Ctx, D);
649-
case OMPD_target_teams_loop:
650649
case OMPD_target_parallel_loop:
651650
case OMPD_target_parallel:
652651
case OMPD_target_parallel_for:
@@ -658,6 +657,12 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
658657
return true;
659658
case OMPD_target_teams_distribute:
660659
return false;
660+
case OMPD_target_teams_loop:
661+
// Whether this is true or not depends on how the directive will
662+
// eventually be emitted.
663+
if (auto *TTLD = dyn_cast<OMPTargetTeamsGenericLoopDirective>(&D))
664+
return TTLD->canBeParallelFor();
665+
return false;
661666
case OMPD_parallel:
662667
case OMPD_for:
663668
case OMPD_parallel_for:

clang/lib/CodeGen/CGStmtOpenMP.cpp

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "clang/AST/StmtVisitor.h"
2525
#include "clang/Basic/OpenMPKinds.h"
2626
#include "clang/Basic/PrettyStackTrace.h"
27+
#include "clang/Basic/SourceManager.h"
2728
#include "llvm/ADT/SmallSet.h"
2829
#include "llvm/BinaryFormat/Dwarf.h"
2930
#include "llvm/Frontend/OpenMP/OMPConstants.h"
@@ -34,11 +35,14 @@
3435
#include "llvm/IR/IntrinsicInst.h"
3536
#include "llvm/IR/Metadata.h"
3637
#include "llvm/Support/AtomicOrdering.h"
38+
#include "llvm/Support/Debug.h"
3739
#include <optional>
3840
using namespace clang;
3941
using namespace CodeGen;
4042
using namespace llvm::omp;
4143

44+
#define TTL_CODEGEN_TYPE "target-teams-loop-codegen"
45+
4246
static const VarDecl *getBaseDecl(const Expr *Ref);
4347

4448
namespace {
@@ -1432,9 +1436,12 @@ void CodeGenFunction::EmitOMPReductionClauseFinal(
14321436
*this, D.getBeginLoc(),
14331437
isOpenMPWorksharingDirective(D.getDirectiveKind()));
14341438
}
1439+
bool TeamsLoopCanBeParallel = false;
1440+
if (auto *TTLD = dyn_cast<OMPTargetTeamsGenericLoopDirective>(&D))
1441+
TeamsLoopCanBeParallel = TTLD->canBeParallelFor();
14351442
bool WithNowait = D.getSingleClause<OMPNowaitClause>() ||
14361443
isOpenMPParallelDirective(D.getDirectiveKind()) ||
1437-
ReductionKind == OMPD_simd;
1444+
TeamsLoopCanBeParallel || ReductionKind == OMPD_simd;
14381445
bool SimpleReduction = ReductionKind == OMPD_simd;
14391446
// Emit nowait reduction if nowait clause is present or directive is a
14401447
// parallel directive (it always has implicit barrier).
@@ -7928,11 +7935,9 @@ void CodeGenFunction::EmitOMPParallelGenericLoopDirective(
79287935
void CodeGenFunction::EmitOMPTeamsGenericLoopDirective(
79297936
const OMPTeamsGenericLoopDirective &S) {
79307937
// To be consistent with current behavior of 'target teams loop', emit
7931-
// 'teams loop' as if its constituent constructs are 'distribute,
7932-
// 'parallel, and 'for'.
7938+
// 'teams loop' as if its constituent constructs are 'teams' and 'distribute'.
79337939
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
7934-
CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
7935-
S.getDistInc());
7940+
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
79367941
};
79377942

79387943
// Emit teams region as a standalone region.
@@ -7946,15 +7951,33 @@ void CodeGenFunction::EmitOMPTeamsGenericLoopDirective(
79467951
CodeGenDistribute);
79477952
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
79487953
};
7949-
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
7954+
emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
79507955
emitPostUpdateForReductionClause(*this, S,
79517956
[](CodeGenFunction &) { return nullptr; });
79527957
}
79537958

7954-
static void
7955-
emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF,
7956-
const OMPTargetTeamsGenericLoopDirective &S,
7957-
PrePostActionTy &Action) {
7959+
static void emitTargetTeamsLoopCodegenStatus(CodeGenFunction &CGF,
7960+
std::string StatusMsg,
7961+
const OMPExecutableDirective &D) {
7962+
#ifndef NDEBUG
7963+
bool IsDevice = CGF.CGM.getLangOpts().OpenMPIsTargetDevice;
7964+
if (IsDevice)
7965+
StatusMsg += ": DEVICE";
7966+
else
7967+
StatusMsg += ": HOST";
7968+
SourceLocation L = D.getBeginLoc();
7969+
auto &SM = CGF.getContext().getSourceManager();
7970+
PresumedLoc PLoc = SM.getPresumedLoc(L);
7971+
const char *FileName = PLoc.isValid() ? PLoc.getFilename() : nullptr;
7972+
unsigned LineNo =
7973+
PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L);
7974+
llvm::dbgs() << StatusMsg << ": " << FileName << ": " << LineNo << "\n";
7975+
#endif
7976+
}
7977+
7978+
static void emitTargetTeamsGenericLoopRegionAsParallel(
7979+
CodeGenFunction &CGF, PrePostActionTy &Action,
7980+
const OMPTargetTeamsGenericLoopDirective &S) {
79587981
Action.Enter(CGF);
79597982
// Emit 'teams loop' as if its constituent constructs are 'distribute,
79607983
// 'parallel, and 'for'.
@@ -7974,19 +7997,50 @@ emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF,
79747997
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
79757998
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
79767999
};
7977-
8000+
DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
8001+
emitTargetTeamsLoopCodegenStatus(
8002+
CGF, TTL_CODEGEN_TYPE " as parallel for", S));
79788003
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
79798004
CodeGenTeams);
79808005
emitPostUpdateForReductionClause(CGF, S,
79818006
[](CodeGenFunction &) { return nullptr; });
79828007
}
79838008

7984-
/// Emit combined directive 'target teams loop' as if its constituent
7985-
/// constructs are 'target', 'teams', 'distribute', 'parallel', and 'for'.
8009+
static void emitTargetTeamsGenericLoopRegionAsDistribute(
8010+
CodeGenFunction &CGF, PrePostActionTy &Action,
8011+
const OMPTargetTeamsGenericLoopDirective &S) {
8012+
Action.Enter(CGF);
8013+
// Emit 'teams loop' as if its constituent construct is 'distribute'.
8014+
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
8015+
CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
8016+
};
8017+
8018+
// Emit teams region as a standalone region.
8019+
auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
8020+
PrePostActionTy &Action) {
8021+
Action.Enter(CGF);
8022+
CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
8023+
CGF.EmitOMPReductionClauseInit(S, PrivateScope);
8024+
(void)PrivateScope.Privatize();
8025+
CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
8026+
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
8027+
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
8028+
};
8029+
DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
8030+
emitTargetTeamsLoopCodegenStatus(
8031+
CGF, TTL_CODEGEN_TYPE " as distribute", S));
8032+
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
8033+
emitPostUpdateForReductionClause(CGF, S,
8034+
[](CodeGenFunction &) { return nullptr; });
8035+
}
8036+
79868037
void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDirective(
79878038
const OMPTargetTeamsGenericLoopDirective &S) {
79888039
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7989-
emitTargetTeamsGenericLoopRegion(CGF, S, Action);
8040+
if (S.canBeParallelFor())
8041+
emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S);
8042+
else
8043+
emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S);
79908044
};
79918045
emitCommonOMPTargetDirective(*this, S, CodeGen);
79928046
}
@@ -7996,7 +8050,10 @@ void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDeviceFunction(
79968050
const OMPTargetTeamsGenericLoopDirective &S) {
79978051
// Emit SPMD target parallel loop region as a standalone region.
79988052
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
7999-
emitTargetTeamsGenericLoopRegion(CGF, S, Action);
8053+
if (S.canBeParallelFor())
8054+
emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S);
8055+
else
8056+
emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S);
80008057
};
80018058
llvm::Function *Fn;
80028059
llvm::Constant *Addr;

clang/lib/Sema/SemaOpenMP.cpp

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4478,6 +4478,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
44784478
Params);
44794479
break;
44804480
}
4481+
// For 'target teams loop', collect all captured regions so codegen can
4482+
// later decide the best IR to emit given the associated loop-nest.
44814483
case OMPD_target_teams_loop:
44824484
case OMPD_target_teams_distribute_parallel_for:
44834485
case OMPD_target_teams_distribute_parallel_for_simd: {
@@ -6135,6 +6137,79 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack,
61356137
}
61366138
}
61376139

6140+
namespace {
6141+
/// A 'teams loop' with a nested 'loop bind(parallel)' or generic function
6142+
/// call in the associated loop-nest cannot be a 'parallel for'.
6143+
class TeamsLoopChecker final : public ConstStmtVisitor<TeamsLoopChecker> {
6144+
Sema &SemaRef;
6145+
6146+
public:
6147+
bool teamsLoopCanBeParallelFor() const { return TeamsLoopCanBeParallelFor; }
6148+
6149+
// Is there a nested OpenMP loop bind(parallel)
6150+
void VisitOMPExecutableDirective(const OMPExecutableDirective *D) {
6151+
if (D->getDirectiveKind() == llvm::omp::Directive::OMPD_loop) {
6152+
if (const auto *C = D->getSingleClause<OMPBindClause>())
6153+
if (C->getBindKind() == OMPC_BIND_parallel) {
6154+
TeamsLoopCanBeParallelFor = false;
6155+
// No need to continue visiting any more
6156+
return;
6157+
}
6158+
}
6159+
for (const Stmt *Child : D->children())
6160+
if (Child)
6161+
Visit(Child);
6162+
}
6163+
6164+
void VisitCallExpr(const CallExpr *C) {
6165+
// Function calls inhibit parallel loop translation of 'target teams loop'
6166+
// unless the assume-no-nested-parallelism flag has been specified.
6167+
// OpenMP API runtime library calls do not inhibit parallel loop
6168+
// translation, regardless of the assume-no-nested-parallelism.
6169+
if (C) {
6170+
bool IsOpenMPAPI = false;
6171+
auto *FD = dyn_cast_or_null<FunctionDecl>(C->getCalleeDecl());
6172+
if (FD) {
6173+
std::string Name = FD->getNameInfo().getAsString();
6174+
IsOpenMPAPI = Name.find("omp_") == 0;
6175+
}
6176+
TeamsLoopCanBeParallelFor =
6177+
IsOpenMPAPI || SemaRef.getLangOpts().OpenMPNoNestedParallelism;
6178+
if (!TeamsLoopCanBeParallelFor)
6179+
return;
6180+
}
6181+
for (const Stmt *Child : C->children())
6182+
if (Child)
6183+
Visit(Child);
6184+
}
6185+
6186+
void VisitCapturedStmt(const CapturedStmt *S) {
6187+
if (!S)
6188+
return;
6189+
Visit(S->getCapturedDecl()->getBody());
6190+
}
6191+
6192+
void VisitStmt(const Stmt *S) {
6193+
if (!S)
6194+
return;
6195+
for (const Stmt *Child : S->children())
6196+
if (Child)
6197+
Visit(Child);
6198+
}
6199+
explicit TeamsLoopChecker(Sema &SemaRef)
6200+
: SemaRef(SemaRef), TeamsLoopCanBeParallelFor(true) {}
6201+
6202+
private:
6203+
bool TeamsLoopCanBeParallelFor;
6204+
};
6205+
} // namespace
6206+
6207+
static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
6208+
TeamsLoopChecker Checker(SemaRef);
6209+
Checker.Visit(AStmt);
6210+
return Checker.teamsLoopCanBeParallelFor();
6211+
}
6212+
61386213
bool Sema::mapLoopConstruct(llvm::SmallVector<OMPClause *> &ClausesWithoutBind,
61396214
ArrayRef<OMPClause *> Clauses,
61406215
OpenMPBindClauseKind &BindKind,
@@ -10895,7 +10970,8 @@ StmtResult Sema::ActOnOpenMPTargetTeamsGenericLoopDirective(
1089510970
setFunctionHasBranchProtectedScope();
1089610971

1089710972
return OMPTargetTeamsGenericLoopDirective::Create(
10898-
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
10973+
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
10974+
teamsLoopCanBeParallelFor(AStmt, *this));
1089910975
}
1090010976

1090110977
StmtResult Sema::ActOnOpenMPParallelGenericLoopDirective(
@@ -15645,14 +15721,19 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
1564515721
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
1564615722
CaptureRegion = OMPD_target;
1564715723
break;
15724+
case OMPD_teams_loop:
15725+
case OMPD_target_teams_loop:
15726+
// For [target] teams loop, assume capture region is 'teams' so it's
15727+
// available for codegen later to use if/when necessary.
15728+
CaptureRegion = OMPD_teams;
15729+
break;
1564815730
case OMPD_target_teams_distribute_parallel_for_simd:
1564915731
if (OpenMPVersion >= 50 &&
1565015732
(NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
1565115733
CaptureRegion = OMPD_parallel;
1565215734
break;
1565315735
}
1565415736
[[fallthrough]];
15655-
case OMPD_target_teams_loop:
1565615737
case OMPD_target_teams_distribute_parallel_for:
1565715738
// If this clause applies to the nested 'parallel' region, capture within
1565815739
// the 'teams' region, otherwise do not capture.
@@ -15775,7 +15856,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
1577515856
case OMPD_declare_target:
1577615857
case OMPD_end_declare_target:
1577715858
case OMPD_loop:
15778-
case OMPD_teams_loop:
1577915859
case OMPD_teams:
1578015860
case OMPD_tile:
1578115861
case OMPD_unroll:

0 commit comments

Comments
 (0)