[llvm-branch-commits] [clang] [llvm] [clang][OpenMP] Prototype #2 of directive splitting (PR #109288)
Krzysztof Parzyszek via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Sep 19 07:08:57 PDT 2024
https://github.com/kparzysz created https://github.com/llvm/llvm-project/pull/109288
This is proto #1 minus the introduction of opaque AST nodes.
This isn't 100% finished, but it should be enough to illustrate the changes needed to implement the feature.
Proto #1: https://github.com/llvm/llvm-project/pull/108855
>From 915fe94064e727d3e75127ab4cb1786226297250 Mon Sep 17 00:00:00 2001
From: Krzysztof Parzyszek <Krzysztof.Parzyszek at amd.com>
Date: Fri, 30 Aug 2024 13:57:13 -0500
Subject: [PATCH] [clang][OpenMP] Prototype #2 of directive splitting
This is proto #1 minus the introduction of opaque AST nodes.
This isn't 100% finished, but it should be enough to illustrate
the changes needed to implement the feature.
Proto #1: https://github.com/llvm/llvm-project/pull/108855
---
clang/include/clang/AST/OpenMPClause.h | 9 +-
clang/include/clang/AST/Stmt.h | 10 +-
clang/include/clang/Basic/OpenMPKinds.h | 18 +-
clang/include/clang/Sema/SemaOpenMP.h | 49 +-
clang/lib/AST/Stmt.cpp | 15 +-
clang/lib/Basic/OpenMPKinds.cpp | 70 +-
clang/lib/CodeGen/CGStmtOpenMP.cpp | 6 +-
clang/lib/Parse/ParseOpenMP.cpp | 45 +-
clang/lib/Sema/CMakeLists.txt | 1 +
clang/lib/Sema/SemaExpr.cpp | 19 +-
clang/lib/Sema/SemaOpenMP.cpp | 2336 +++++++++++------
clang/lib/Sema/SemaOpenMPExt.cpp | 1547 +++++++++++
clang/lib/Sema/SemaOpenMPExt.h | 428 +++
clang/lib/Sema/TreeTransform.h | 83 +-
.../Frontend/OpenMP/ConstructDecompositionT.h | 106 +-
llvm/include/llvm/Frontend/OpenMP/OMP.h | 2 +
llvm/include/llvm/Frontend/OpenMP/OMP.td | 1 +
llvm/lib/Frontend/OpenMP/OMP.cpp | 54 +
18 files changed, 3853 insertions(+), 946 deletions(-)
create mode 100644 clang/lib/Sema/SemaOpenMPExt.cpp
create mode 100644 clang/lib/Sema/SemaOpenMPExt.h
diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index 3a1d6852d2a708..ddfb86d1d8d943 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -388,6 +388,13 @@ template <class T> class OMPDirectiveListClause : public OMPClause {
NumKinds);
}
+ ArrayRef<OpenMPDirectiveKind> getDirectiveKinds() const {
+ return ArrayRef<OpenMPDirectiveKind>(
+ static_cast<const T *>(this)
+ ->template getTrailingObjects<OpenMPDirectiveKind>(),
+ NumKinds);
+ }
+
void setDirectiveKinds(ArrayRef<OpenMPDirectiveKind> DK) {
assert(
DK.size() == NumKinds &&
@@ -6284,7 +6291,7 @@ class OMPMapClause final : public OMPMappableExprListClause<OMPMapClause>,
const OMPMappableExprListSizeTy &Sizes);
/// Fetches Expr * of iterator modifier.
- Expr *getIteratorModifier() {
+ Expr *getIteratorModifier() const {
return getTrailingObjects<Expr *>()[2 * varlist_size()];
}
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index 7aed83e9c68bb7..61e94c3e0a55ba 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1435,9 +1435,15 @@ class alignas(void *) Stmt {
/// Skip no-op (attributed, compound) container stmts and skip captured
/// stmt at the top, if \a IgnoreCaptured is true.
- Stmt *IgnoreContainers(bool IgnoreCaptured = false);
+ Stmt *IgnoreContainers(bool IgnoreCaptured = false) {
+ return stripContainers(static_cast<int>(IgnoreCaptured));
+ }
const Stmt *IgnoreContainers(bool IgnoreCaptured = false) const {
- return const_cast<Stmt *>(this)->IgnoreContainers(IgnoreCaptured);
+ return stripContainers(static_cast<int>(IgnoreCaptured));
+ }
+ Stmt *stripContainers(int NumCaptured = 0);
+ const Stmt *stripContainers(int NumCaptured = 0) const {
+ return const_cast<Stmt *>(this)->stripContainers(NumCaptured);
}
const Stmt *stripLabelLikeStatements() const;
diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h
index 1acdafa8572211..c1188a745d089c 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -385,9 +385,25 @@ bool isOpenMPInformationalDirective(OpenMPDirectiveKind DKind);
/// Checks if the specified directive can capture variables.
/// \param DKind Specified directive.
+/// \param OrderedIsStandalone Assume that the "ordered" directive is
+/// standalone (i.e. without a statement). The default association of
+/// "ordered" is "None", which corresponds to the default value of the
+/// parameter.
/// \return true - if the above condition is met for this directive
/// otherwise - false.
-bool isOpenMPCapturingDirective(OpenMPDirectiveKind DKind);
+bool isOpenMPCapturingDirective(OpenMPDirectiveKind DKind,
+ bool OrderedIsStandalone = true);
+
+/// Checks if the specified directive has an associated statement.
+/// \param DKind Specified directive.
+/// \param OrderedIsStandalone Assume that the "ordered" directive is
+/// standalone (i.e. without a statement). The default association of
+/// "ordered" is "None", which corresponds to the default value of the
+/// parameter.
+/// \return true - if the above condition is met for this directive
+/// otherwise - false.
+bool isOpenMPDirectiveWithStatement(OpenMPDirectiveKind DKind,
+ bool OrderedIsStandalone = true);
}
template <>
diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h
index 819b9fe347568d..ced79e3df92b8b 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -45,6 +45,8 @@ class DeclGroupRef;
class ParsedAttr;
class Scope;
+struct ConstructDecomposition;
+
class SemaOpenMP : public SemaBase {
public:
SemaOpenMP(Sema &S);
@@ -149,6 +151,9 @@ class SemaOpenMP : public SemaBase {
VarDecl *isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo = false,
unsigned StopAt = 0);
+ bool shouldCaptureInRegion(ValueDecl *D, unsigned Level,
+ unsigned OpenMPCaptureLevel) const;
+
/// The member expression(this->fd) needs to be rebuilt in the template
/// instantiation to generate private copy for OpenMP when default
/// clause is used. The function will return true if default
@@ -378,7 +383,8 @@ class SemaOpenMP : public SemaBase {
static int getOpenMPCaptureLevels(OpenMPDirectiveKind Kind);
/// Initialization of captured region for OpenMP region.
- void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope);
+ void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope,
+ bool HasAssociatedStmt);
/// Called for syntactical loops (ForStmt or CXXForRangeStmt) associated to
/// an OpenMP loop directive.
@@ -1404,6 +1410,37 @@ class SemaOpenMP : public SemaBase {
void handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL);
+ struct VariableImplicitInfo {
+ static const unsigned MapKindNum = OMPC_MAP_unknown;
+ static const unsigned DefaultmapKindNum = OMPC_DEFAULTMAP_unknown + 1;
+
+ llvm::SmallVector<Expr *> Privates;
+ llvm::SmallVector<Expr *> Firstprivates;
+ llvm::SmallVector<Expr *> Mappings[DefaultmapKindNum][MapKindNum];
+ llvm::SmallVector<OpenMPMapModifierKind, NumberOfOMPMapClauseModifiers>
+ MapModifiers[DefaultmapKindNum];
+ llvm::SmallVector<Expr *> ReductionMappings;
+
+ llvm::SmallVector<SourceLocation, NumberOfOMPMapClauseModifiers>
+ ImplicitMapModifiersLoc[DefaultmapKindNum];
+
+ void addPrivate(Expr *E);
+ void addFirstprivate(Expr *E);
+ void addMapping(Expr *E, unsigned DefKind, unsigned MapKind);
+ void addMapModifier(unsigned MapKind, unsigned DefKind);
+ void addReductionMapping(Expr *E);
+
+ VariableImplicitInfo &include(const VariableImplicitInfo &Other);
+
+ #ifndef NDEBUG
+ bool empty() const;
+ #endif
+
+ private:
+ std::pair<Stmt *, Decl *> getDecl(Expr *E);
+ bool isDeclPresent(ArrayRef<Expr *> Range, Expr *E);
+ };
+
private:
void *VarDataSharingAttributesStack;
@@ -1419,7 +1456,15 @@ class SemaOpenMP : public SemaBase {
/// Adjusts the function scopes index for the target-based regions.
void adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
- unsigned Level) const;
+ unsigned Level,
+ unsigned CaptureLevel) const;
+
+ /// Adjusts the function scopes index for regions that privatize
+ /// thread-local globals.
+ void adjustOpenMPGlobalScopeIndex(ValueDecl *VD,
+ unsigned &FunctionScopesIndex,
+ unsigned Level,
+ unsigned CaptureLevel) const;
/// Returns the number of scopes associated with the construct on the given
/// OpenMP level.
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp
index fe59d6070b3e81..56f8aa3ffda0fb 100644
--- a/clang/lib/AST/Stmt.cpp
+++ b/clang/lib/AST/Stmt.cpp
@@ -194,11 +194,20 @@ Stmt::determineLikelihoodConflict(const Stmt *Then, const Stmt *Else) {
/// Skip no-op (attributed, compound) container stmts and skip captured
/// stmt at the top, if \a IgnoreCaptured is true.
-Stmt *Stmt::IgnoreContainers(bool IgnoreCaptured) {
+Stmt *Stmt::stripContainers(int NumCaptured) {
Stmt *S = this;
- if (IgnoreCaptured)
- if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
+ if (NumCaptured >= 0) {
+ // If the number of captured statements to skip is non-negative,
+ // then try to skip that exact number of them.
+ while (NumCaptured--)
+ if (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
+ S = CapS->getCapturedStmt();
+ } else {
+ // If the number of captured statements to skip is negative,
+ // then skip all of them.
+ while (auto CapS = dyn_cast_or_null<CapturedStmt>(S))
S = CapS->getCapturedStmt();
+ }
while (true) {
if (auto AS = dyn_cast_or_null<AttributedStmt>(S))
S = AS->getSubStmt();
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 630a8898aa2293..329c980489db56 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -717,7 +717,8 @@ bool clang::isOpenMPInformationalDirective(OpenMPDirectiveKind DKind) {
return Cat == Category::Informational;
}
-bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind) {
+bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind,
+ bool OrderedIsStandalone) {
if (isOpenMPExecutableDirective(DKind)) {
switch (DKind) {
case OMPD_atomic:
@@ -728,13 +729,17 @@ bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind) {
case OMPD_depobj:
case OMPD_error:
case OMPD_flush:
+ case OMPD_interop:
case OMPD_masked:
case OMPD_master:
+ case OMPD_scan:
case OMPD_section:
case OMPD_taskwait:
case OMPD_taskyield:
case OMPD_assume:
return false;
+ case OMPD_ordered:
+ return !OrderedIsStandalone;
default:
return !isOpenMPLoopTransformationDirective(DKind);
}
@@ -753,8 +758,12 @@ bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind) {
void clang::getOpenMPCaptureRegions(
SmallVectorImpl<OpenMPDirectiveKind> &CaptureRegions,
OpenMPDirectiveKind DKind) {
- assert(unsigned(DKind) < llvm::omp::Directive_enumSize);
- assert(isOpenMPCapturingDirective(DKind) && "Expecting capturing directive");
+ assert(static_cast<size_t>(DKind) < llvm::omp::Directive_enumSize);
+ assert(isOpenMPCapturingDirective(DKind, /*OrderedIsStandalone=*/false) &&
+ "Expecting capturing directive");
+
+ size_t StartSize = CaptureRegions.size();
+ bool IsComposite = llvm::omp::isCompositeConstruct(DKind);
auto GetRegionsForLeaf = [&](OpenMPDirectiveKind LKind) {
assert(isLeafConstruct(LKind) && "Epecting leaf directive");
@@ -790,9 +799,11 @@ void clang::getOpenMPCaptureRegions(
// bind clause or the parent directive when there is no bind clause.
// If any of the directives that push regions here are parents of 'loop',
// assume 'parallel'. Otherwise do nothing.
- if (!CaptureRegions.empty() &&
+ if (CaptureRegions.size() != StartSize &&
!llvm::is_contained(CaptureRegions, OMPD_parallel))
CaptureRegions.push_back(OMPD_parallel);
+ else if (!IsComposite)
+ CaptureRegions.push_back(OMPD_unknown);
else
return true;
break;
@@ -810,7 +821,11 @@ void clang::getOpenMPCaptureRegions(
// but when they're constituents of a compound directive, and other
// leafs from that directive have specific regions, then these directives
// add no additional regions.
- return true;
+ if (!IsComposite)
+ CaptureRegions.push_back(OMPD_unknown);
+ else
+ return true;
+ break;
case OMPD_masked:
case OMPD_master:
return false;
@@ -822,20 +837,35 @@ void clang::getOpenMPCaptureRegions(
};
bool MayNeedUnknownRegion = false;
- for (OpenMPDirectiveKind L : getLeafConstructsOrSelf(DKind))
- MayNeedUnknownRegion |= GetRegionsForLeaf(L);
+ if (IsComposite) {
+ // If it's a composite directive, look at individual leafs.
+ for (OpenMPDirectiveKind L : getLeafConstructsOrSelf(DKind))
+ MayNeedUnknownRegion |= GetRegionsForLeaf(L);
+ } else {
+ // If it's not a composite construct, look at constituent constructs
+ // which may be leaf or composite.
+ SmallVector<OpenMPDirectiveKind> Parts;
+ for (OpenMPDirectiveKind L : getLeafOrCompositeConstructs(DKind, Parts)) {
+ if (isLeafConstruct(L))
+ MayNeedUnknownRegion |= GetRegionsForLeaf(L);
+ else
+ getOpenMPCaptureRegions(CaptureRegions, L);
+ }
+ }
// We need OMPD_unknown when no regions were added, and specific leaf
// constructs were present. Push a single OMPD_unknown as the capture
/// region.
- if (CaptureRegions.empty() && MayNeedUnknownRegion)
+ if (CaptureRegions.size() == StartSize && MayNeedUnknownRegion)
CaptureRegions.push_back(OMPD_unknown);
// OMPD_unknown is only expected as the only region. If other regions
// are present OMPD_unknown should not be present.
- assert((CaptureRegions[0] == OMPD_unknown ||
- !llvm::is_contained(CaptureRegions, OMPD_unknown)) &&
- "Misplaced OMPD_unknown");
+ if (IsComposite) {
+ assert((CaptureRegions[StartSize] == OMPD_unknown ||
+ !llvm::is_contained(CaptureRegions, OMPD_unknown)) &&
+ "Misplaced OMPD_unknown");
+ }
}
bool clang::checkFailClauseParameter(OpenMPClauseKind FailClauseParameter) {
@@ -844,3 +874,21 @@ bool clang::checkFailClauseParameter(OpenMPClauseKind FailClauseParameter) {
FailClauseParameter == llvm::omp::OMPC_seq_cst;
}
+bool clang::isOpenMPDirectiveWithStatement(OpenMPDirectiveKind DKind,
+ bool OrderedIsStandalone) {
+ switch (DKind) {
+ // The association of these in the spec is either "none" or "separating",
+ // but they do have an associated statement in clang.
+ case OMPD_section:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target_update:
+ return true;
+ case OMPD_ordered:
+ return !OrderedIsStandalone;
+ default:
+ break;
+ }
+ Association Assoc = getDirectiveAssociation(DKind);
+ return Assoc != Association::None && Assoc != Association::Separating;
+}
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 8afe2abf2cc494..055131ffd348d7 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -92,6 +92,7 @@ class OMPLexicalScope : public CodeGenFunction::LexicalScope {
assert(S.hasAssociatedStmt() &&
"Expected associated statement for inlined directive.");
const CapturedStmt *CS = S.getCapturedStmt(*CapturedRegion);
+
for (const auto &C : CS->captures()) {
if (C.capturesVariable() || C.capturesVariableByCopy()) {
auto *VD = C.getCapturedVar();
@@ -1605,6 +1606,9 @@ static void emitCommonOMPParallelDirective(
CGF.CGM.getOpenMPRuntime().emitParallelOutlinedFunction(
CGF, S, *CS->getCapturedDecl()->param_begin(), InnermostKind,
CodeGen);
+ // The codegen for the clauses below may require variables created by their
+ // pre-inits.
+ OMPParallelScope Scope(CGF, S);
if (const auto *NumThreadsClause = S.getSingleClause<OMPNumThreadsClause>()) {
CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
NumThreads = CGF.EmitScalarExpr(NumThreadsClause->getNumThreads(),
@@ -1625,8 +1629,6 @@ static void emitCommonOMPParallelDirective(
break;
}
}
-
- OMPParallelScope Scope(CGF, S);
llvm::SmallVector<llvm::Value *, 16> CapturedVars;
// Combining 'distribute' with 'for' requires sharing each 'distribute' chunk
// lower and upper bounds with the pragma 'for' chunking mechanism.
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 64dfcd47296998..55f060e4608018 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2404,15 +2404,10 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
bool ReadDirectiveWithinMetadirective) {
assert(isOpenMPExecutableDirective(DKind) && "Unexpected directive category");
- bool HasAssociatedStatement = true;
- Association Assoc = getDirectiveAssociation(DKind);
-
- // OMPD_ordered has None as association, but it comes in two variants,
- // the second of which is associated with a block.
- // OMPD_scan and OMPD_section are both "separating", but section is treated
- // as if it was associated with a statement, while scan is not.
- if (DKind != OMPD_ordered && DKind != OMPD_section &&
- (Assoc == Association::None || Assoc == Association::Separating)) {
+ bool HasAssociatedStatement =
+ isOpenMPDirectiveWithStatement(DKind, /*OrderedIsStandalone=*/false);
+
+ if (!HasAssociatedStatement) {
if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) ==
ParsedStmtContext()) {
Diag(Tok, diag::err_omp_immediate_directive)
@@ -2422,7 +2417,6 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
return StmtError();
}
}
- HasAssociatedStatement = false;
}
SourceLocation EndLoc;
@@ -2539,9 +2533,17 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
}
StmtResult AssociatedStmt;
- if (HasAssociatedStatement) {
+ Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope(),
+ HasAssociatedStatement);
+ // These directives do have an associated statement in clang, but they
+ // are standalone in the source.
+ if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data ||
+ DKind == OMPD_target_exit_data) {
+ AssociatedStmt = (Sema::CompoundScopeRAII(Actions),
+ Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt,
+ /*isStmtExpr=*/false));
+ } else if (HasAssociatedStatement) {
// The body is a block scope like in Lambdas and Blocks.
- Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());
// FIXME: We create a bogus CompoundStmt scope to hold the contents of
// the captured region. Code elsewhere assumes that any FunctionScopeInfo
// should have at least one compound statement scope within it.
@@ -2555,18 +2557,10 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
AssociatedStmt =
Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get());
}
- AssociatedStmt =
- Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
- } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data ||
- DKind == OMPD_target_exit_data) {
- Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());
- AssociatedStmt = (Sema::CompoundScopeRAII(Actions),
- Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt,
- /*isStmtExpr=*/false));
- AssociatedStmt =
- Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
}
+ AssociatedStmt =
+ Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
StmtResult Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective(
DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, EndLoc);
@@ -2621,17 +2615,18 @@ StmtResult Parser::ParseOpenMPInformationalDirective(
ConsumeAnnotationToken();
StmtResult AssociatedStmt;
+ Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope(),
+ HasAssociatedStatement);
if (HasAssociatedStatement) {
- Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());
ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
{
Sema::CompoundScopeRAII Scope(Actions);
AssociatedStmt = ParseStatement();
}
- AssociatedStmt =
- Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
}
+ AssociatedStmt =
+ Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
StmtResult Directive = Actions.OpenMP().ActOnOpenMPInformationalDirective(
DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc);
diff --git a/clang/lib/Sema/CMakeLists.txt b/clang/lib/Sema/CMakeLists.txt
index 2cee4f5ef6e99c..f8630d730749ec 100644
--- a/clang/lib/Sema/CMakeLists.txt
+++ b/clang/lib/Sema/CMakeLists.txt
@@ -71,6 +71,7 @@ add_clang_library(clangSema
SemaOpenACC.cpp
SemaOpenCL.cpp
SemaOpenMP.cpp
+ SemaOpenMPExt.cpp
SemaOverload.cpp
SemaPPC.cpp
SemaPseudoObject.cpp
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2f7e9c754ce095..e364d8b2b62f80 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -18553,6 +18553,9 @@ static bool captureInCapturedRegion(
ByRef = (Kind == Sema::TryCapture_ExplicitByRef);
} else if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) {
// Using an LValue reference type is consistent with Lambdas (see below).
+ if (!S.OpenMP().shouldCaptureInRegion(Var, RSI->OpenMPLevel,
+ RSI->OpenMPCaptureLevel))
+ return true;
if (S.OpenMP().isOpenMPCapturedDecl(Var)) {
bool HasConst = DeclRefType.isConstQualified();
DeclRefType = DeclRefType.getUnqualifiedType();
@@ -18560,10 +18563,6 @@ static bool captureInCapturedRegion(
if (HasConst)
DeclRefType.addConst();
}
- // Do not capture firstprivates in tasks.
- if (S.OpenMP().isOpenMPPrivateDecl(Var, RSI->OpenMPLevel,
- RSI->OpenMPCaptureLevel) != OMPC_unknown)
- return true;
ByRef = S.OpenMP().isOpenMPCapturedByRef(Var, RSI->OpenMPLevel,
RSI->OpenMPCaptureLevel);
}
@@ -18967,9 +18966,7 @@ bool Sema::tryCaptureVariable(
QualType QTy = Var->getType();
if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var))
QTy = PVD->getOriginalType();
- for (int I = 1,
- E = OpenMP().getNumberOfConstructScopes(RSI->OpenMPLevel);
- I < E; ++I) {
+ for (int I = 1, E = RSI->OpenMPCaptureLevel + 1; I < E; ++I) {
auto *OuterRSI = cast<CapturedRegionScopeInfo>(
FunctionScopes[FunctionScopesIndex - I]);
assert(RSI->OpenMPLevel == OuterRSI->OpenMPLevel &&
@@ -18991,8 +18988,8 @@ bool Sema::tryCaptureVariable(
// target region, therefore we need to propagate the capture from the
// enclosing region. Therefore, the capture is not initially nested.
if (IsTargetCap)
- OpenMP().adjustOpenMPTargetScopeIndex(FunctionScopesIndex,
- RSI->OpenMPLevel);
+ OpenMP().adjustOpenMPTargetScopeIndex(
+ FunctionScopesIndex, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel);
if (IsTargetCap || IsOpenMPPrivateDecl == OMPC_private ||
(IsGlobal && !IsGlobalCap)) {
@@ -19003,6 +19000,10 @@ bool Sema::tryCaptureVariable(
if (HasConst)
DeclRefType.addConst();
CaptureType = Context.getLValueReferenceType(DeclRefType);
+ if (!IsTargetCap)
+ OpenMP().adjustOpenMPGlobalScopeIndex(Var, FunctionScopesIndex,
+ RSI->OpenMPLevel,
+ RSI->OpenMPCaptureLevel);
break;
}
}
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index c8109d41704f7b..1a238c3f781bbf 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -13,6 +13,7 @@
#include "clang/Sema/SemaOpenMP.h"
+#include "SemaOpenMPExt.h"
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
@@ -38,6 +39,7 @@
#include "clang/Sema/ScopeInfo.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaInternal.h"
+#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/ADT/STLExtras.h"
@@ -45,6 +47,7 @@
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/Frontend/OpenMP/ClauseT.h"
#include "llvm/Frontend/OpenMP/OMPAssume.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
#include "llvm/IR/Assumptions.h"
@@ -73,6 +76,12 @@ enum DefaultDataSharingAttributes {
DSA_firstprivate = 1 << 3, /// Default data sharing attribute 'firstprivate'.
};
+struct UnitConstruct {
+ OpenMPDirectiveKind DKind;
+ SmallVector<OMPClause *> Clauses;
+ SmallVector<omp::Clause> Pending; // Clauses that need AST nodes.
+};
+
/// Stack for tracking declarations used in OpenMP directives and
/// clauses and their data-sharing attributes.
class DSAStackTy {
@@ -172,6 +181,7 @@ class DSAStackTy {
OpenMPDirectiveKind Directive = OMPD_unknown;
DeclarationNameInfo DirectiveName;
Scope *CurScope = nullptr;
+ // Used to detemine variables local to OpenMP constructs.
DeclContext *Context = nullptr;
SourceLocation ConstructLoc;
/// Set of 'depend' clauses with 'sink|source' dependence kind. Required to
@@ -224,6 +234,21 @@ class DSAStackTy {
ImplicitDefaultFirstprivateFDs;
Expr *DeclareMapperVar = nullptr;
SmallVector<VarDecl *, 16> IteratorVarDecls;
+ // List of leaf-or-composite constructs with clauses created from the
+ // current directive. This is created in ActOnOpenMPRegionEnd, and then
+ // used to create the AST in createASTForDirective. After that it's no
+ // longer needed.
+ SmallVector<UnitConstruct> UnitConstructs;
+ // List of capture initialization statements. These statements declare
+ // and initialize captures for `num_teams` and `thread_limit` clauses,
+ // whose expressions need to be evaluated before the outermost leaf
+ // construct. [5.2:341:24-30]
+ llvm::DenseMap<OMPClause *, Stmt *> PreInits;
+ // Variable DSA info collected during creating capture regions.
+ // Used for contructing leaf-or-composite directives.
+ SemaOpenMP::VarsWithInheritedDSAType VarsWithInheritedDSA;
+ bool HasDSAError = false;
+
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -288,6 +313,8 @@ class DSAStackTy {
const SharingMapTy *getTopOfStackOrNull() const {
return const_cast<DSAStackTy &>(*this).getTopOfStackOrNull();
}
+
+public:
SharingMapTy &getTopOfStack() {
assert(!isStackEmpty() && "no current directive");
return *getTopOfStackOrNull();
@@ -296,6 +323,7 @@ class DSAStackTy {
return const_cast<DSAStackTy &>(*this).getTopOfStack();
}
+private:
SharingMapTy *getSecondOnStackOrNull() {
size_t Size = getStackSize();
if (Size <= 1)
@@ -1221,6 +1249,14 @@ class DSAStackTy {
}
assert((StackLevel > 0 && I != EndI) || (StackLevel == 0 && I == EndI));
}
+ /// Add a capture initialization statement
+ void addPreInit(OMPClause *Clause, Stmt *Init) {
+ bool Inserted = getTopOfStack().PreInits.insert({Clause, Init}).second;
+ assert(Inserted);
+ }
+ llvm::DenseMap<OMPClause *, Stmt *> &getPreInits() {
+ return getTopOfStack().PreInits;
+ }
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
@@ -2281,6 +2317,16 @@ bool SemaOpenMP::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
return IsByRef;
}
+bool SemaOpenMP::shouldCaptureInRegion(ValueDecl *D, unsigned Level,
+ unsigned OpenMPCaptureLevel) const {
+ assert(getLangOpts().OpenMP && "OpenMP is not allowed");
+ // Do not capture firstprivates in tasks.
+ if (isOpenMPPrivateDecl(D, Level, OpenMPCaptureLevel) != OMPC_unknown)
+ return false;
+
+ return true;
+}
+
unsigned SemaOpenMP::getOpenMPNestingLevel() const {
assert(getLangOpts().OpenMP);
return DSAStack->getNestingLevel();
@@ -2320,10 +2366,10 @@ bool SemaOpenMP::isOpenMPRebuildMemberExpr(ValueDecl *D) {
return false;
}
-static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
- Expr *CaptureExpr, bool WithInit,
- DeclContext *CurContext,
- bool AsExpression);
+static VarDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, Expr *CaptureExpr,
+ bool WithInit, DeclContext *CurContext,
+ bool AsExpression,
+ bool MakeOMPCapturedExprDecl);
VarDecl *SemaOpenMP::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
unsigned StopAt) {
@@ -2468,9 +2514,10 @@ VarDecl *SemaOpenMP::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
DeclAccessPair::make(FD, FD->getAccess()),
/*HadMultipleCandidates=*/false, DeclarationNameInfo(), FD->getType(),
VK_LValue, OK_Ordinary);
- OMPCapturedExprDecl *CD = buildCaptureDecl(
+ VarDecl *CD = buildCaptureDecl(
SemaRef, FD->getIdentifier(), ME, DVarPrivate.CKind != OMPC_private,
- SemaRef.CurContext->getParent(), /*AsExpression=*/false);
+ SemaRef.CurContext->getParent(), /*AsExpression=*/false,
+ /*MakeOMPCapturedExprDecl=*/true);
DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr(
SemaRef, CD, CD->getType().getNonReferenceType(), SourceLocation());
VD = cast<VarDecl>(VDPrivateRefExpr->getDecl());
@@ -2487,8 +2534,30 @@ VarDecl *SemaOpenMP::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
}
void SemaOpenMP::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
- unsigned Level) const {
- FunctionScopesIndex -= getOpenMPCaptureLevels(DSAStack->getDirective(Level));
+ unsigned Level,
+ unsigned CaptureLevel) const {
+ assert(isOpenMPTargetExecutionDirective(DSAStack->getDirective(Level)));
+ FunctionScopesIndex -= (CaptureLevel + 1);
+}
+
+void SemaOpenMP::adjustOpenMPGlobalScopeIndex(ValueDecl *VD,
+ unsigned &FunctionScopesIndex,
+ unsigned Level,
+ unsigned CaptureLevel) const {
+ if (auto *V = dyn_cast<VarDecl>(VD); V && DSAStack->isThreadPrivate(V)) {
+ OpenMPDirectiveKind Kind = DSAStack->getDirective(Level);
+ SmallVector<OpenMPDirectiveKind> Regions;
+ getOpenMPCaptureRegions(Regions, Kind);
+ for (unsigned CL = CaptureLevel + 1; CL > 0; --CL) {
+ OpenMPDirectiveKind RKind = Regions[CL - 1];
+ // FunctionScopesIndex is the index of the parent of the first capturing
+ // scope.
+ --FunctionScopesIndex;
+ // Looking for a team-generating directive.
+ if (RKind == OMPD_parallel || RKind == OMPD_teams)
+ break;
+ }
+ }
}
void SemaOpenMP::startOpenMPLoop() {
@@ -2795,21 +2864,7 @@ static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
if (RC->getModifier() == OMPC_REDUCTION_inscan) {
InscanFound = true;
InscanLoc = RC->getModifierLoc();
- continue;
- }
- if (RC->getModifier() == OMPC_REDUCTION_task) {
- // OpenMP 5.0, 2.19.5.4 reduction Clause.
- // A reduction clause with the task reduction-modifier may only appear on
- // a parallel construct, a worksharing construct or a combined or
- // composite construct for which any of the aforementioned constructs is a
- // constituent construct and simd or loop are not constituent constructs.
- OpenMPDirectiveKind CurDir = Stack->getCurrentDirective();
- if (!(isOpenMPParallelDirective(CurDir) ||
- isOpenMPWorksharingDirective(CurDir)) ||
- isOpenMPSimdDirective(CurDir))
- S.Diag(RC->getModifierLoc(),
- diag::err_omp_reduction_task_not_parallel_or_worksharing);
- continue;
+ break;
}
}
if (InscanFound) {
@@ -2847,8 +2902,6 @@ static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
ArrayRef<OMPClause *> Clauses);
-static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
- bool WithInit);
static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
const ValueDecl *D,
@@ -2967,20 +3020,61 @@ void SemaOpenMP::EndOpenMPDSABlock(Stmt *CurDirective) {
}
};
- if (const auto *D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) {
- for (OMPClause *C : D->clauses()) {
- if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) {
- FinalizeLastprivate(Clause);
- } else if (auto *Clause = dyn_cast<OMPNontemporalClause>(C)) {
- FinalizeNontemporal(Clause);
- } else if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) {
- FinalizeAllocators(Clause);
+ auto FinalizeDirective = [&](Stmt *Dir) {
+ if (const auto *D = dyn_cast_or_null<OMPExecutableDirective>(Dir)) {
+ for (OMPClause *C : D->clauses()) {
+ if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) {
+ FinalizeLastprivate(Clause);
+ } else if (auto *Clause = dyn_cast<OMPNontemporalClause>(C)) {
+ FinalizeNontemporal(Clause);
+ } else if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) {
+ FinalizeAllocators(Clause);
+ }
}
+ // Check allocate clauses.
+ if (!SemaRef.CurContext->isDependentContext())
+ checkAllocateClauses(SemaRef, DSAStack, D->clauses());
+ checkReductionClauses(SemaRef, DSAStack, D->clauses());
+ }
+ };
+
+ SmallVector<Stmt *> Directives;
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+
+ if (isa_and_present<OMPExecutableDirective>(CurDirective)) {
+ if (!SemaRef.CurContext->isDependentContext()) {
+ SmallVector<OpenMPDirectiveKind> Parts;
+ OpenMPDirectiveKind CurKind =
+ cast<OMPExecutableDirective>(CurDirective)->getDirectiveKind();
+ if (isLeafConstruct(CurKind) || isCompositeConstruct(CurKind)) {
+ std::ignore = getLeafOrCompositeConstructs(DKind, Parts);
+ } else {
+ // XXX Is this a good way to detect splitting errors?
+ // If there was an error in splitting the directive, we keep it
+ // in the original (compound) form.
+ Parts.push_back(DKind);
+ }
+
+ Stmt *S = CurDirective;
+ for (OpenMPDirectiveKind D : Parts) {
+ Directives.push_back(S);
+ assert(isa<OMPExecutableDirective>(S) &&
+ "Expecting executable directive");
+ if (cast<OMPExecutableDirective>(S)->hasAssociatedStmt()) {
+ S = cast<OMPExecutableDirective>(S)->getAssociatedStmt();
+ if (!isOpenMPCapturingDirective(D, /*OrderedIsStandalone=*/false))
+ continue;
+ for (int I = 0, E = getOpenMPCaptureLevels(D); I != E; ++I)
+ S = cast<CapturedStmt>(S)->getCapturedStmt();
+ }
+ }
+ } else {
+ // Inside templates we use a single compound directive.
+ Directives.push_back(CurDirective);
}
- // Check allocate clauses.
- if (!SemaRef.CurContext->isDependentContext())
- checkAllocateClauses(SemaRef, DSAStack, D->clauses());
- checkReductionClauses(SemaRef, DSAStack, D->clauses());
+
+ for (Stmt *Dir : llvm::reverse(Directives))
+ FinalizeDirective(Dir);
}
DSAStack->pop();
@@ -3714,6 +3808,87 @@ getMapClauseKindFromModifier(OpenMPDefaultmapClauseModifier M,
return Kind;
}
+void SemaOpenMP::VariableImplicitInfo::addPrivate(Expr *E) {
+ if (!isDeclPresent(Privates, E))
+ Privates.push_back(E);
+}
+
+void SemaOpenMP::VariableImplicitInfo::addFirstprivate(Expr *E) {
+ if (!isDeclPresent(Firstprivates, E))
+ Firstprivates.push_back(E);
+}
+
+void SemaOpenMP::VariableImplicitInfo::addMapping(Expr *E, unsigned DefKind,
+ unsigned MapKind) {
+ auto &Ms = Mappings[DefKind][MapKind];
+ if (!isDeclPresent(Ms, E))
+ Ms.push_back(E);
+}
+
+void SemaOpenMP::VariableImplicitInfo::addMapModifier(unsigned MapKind,
+ unsigned DefKind) {
+ if (!llvm::is_contained(MapModifiers[DefKind], MapKind))
+ MapModifiers[DefKind].push_back(
+ static_cast<OpenMPMapModifierKind>(MapKind));
+}
+
+void SemaOpenMP::VariableImplicitInfo::addReductionMapping(Expr *E) {
+ if (!isDeclPresent(ReductionMappings, E))
+ ReductionMappings.push_back(E);
+}
+
+SemaOpenMP::VariableImplicitInfo &
+SemaOpenMP::VariableImplicitInfo::include(const VariableImplicitInfo &Other) {
+ for (Expr *E : Other.Privates)
+ addPrivate(E);
+ for (Expr *E : Other.Firstprivates)
+ addFirstprivate(E);
+ for (unsigned I = 0; I != DefaultmapKindNum; ++I) {
+ for (unsigned J = 0; J != MapKindNum; ++J) {
+ for (Expr *E : Other.Mappings[I][J])
+ addMapping(E, I, J);
+ }
+ for (unsigned MapKind : Other.MapModifiers[I])
+ addMapModifier(MapKind, I);
+ }
+ for (Expr *E : Other.ReductionMappings)
+ addReductionMapping(E);
+
+ return *this;
+}
+
+#ifndef NDEBUG
+bool SemaOpenMP::VariableImplicitInfo::empty() const {
+ if (!Privates.empty() || !Firstprivates.empty() || !ReductionMappings.empty())
+ return false;
+ for (unsigned I = 0; I != DefaultmapKindNum; ++I) {
+ for (unsigned J = 0; J != MapKindNum; ++J) {
+ if (!Mappings[I][J].empty())
+ return false;
+ }
+ }
+ return true;
+}
+#endif
+
+std::pair<Stmt *, Decl *> SemaOpenMP::VariableImplicitInfo::getDecl(Expr *E) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ return {nullptr, DRE->getDecl()};
+ if (auto *ME = dyn_cast<MemberExpr>(E))
+ return {ME->getBase(), ME->getMemberDecl()};
+ if (isa<ArraySectionExpr, ArraySubscriptExpr>(E))
+ return {nullptr, nullptr};
+ llvm_unreachable("Unexpected expression");
+}
+
+bool SemaOpenMP::VariableImplicitInfo::isDeclPresent(ArrayRef<Expr *> Range,
+ Expr *E) {
+ std::pair<Stmt *, Decl *> D = getDecl(E);
+ if (!D.second)
+ return false;
+ return llvm::any_of(Range, [&](Expr *T) { return D == getDecl(T); });
+}
+
namespace {
struct VariableImplicitInfo {
static const unsigned MapKindNum = OMPC_MAP_unknown;
@@ -3732,12 +3907,22 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
OpenMPDirectiveKind DKind = OMPD_unknown;
bool ErrorFound = false;
bool TryCaptureCXXThisMembers = false;
- CapturedStmt *CS = nullptr;
+ llvm::SmallDenseSet<std::pair<VarDecl *, SourceLocation>, 8> CapturedVars;
+ llvm::SmallDenseSet<VarDecl *, 8> CapturedCanonDecls;
+ bool CapturedThis = false;
+ bool CheckCaptures = false;
- VariableImplicitInfo ImpInfo;
+ SemaOpenMP::VariableImplicitInfo ImpInfo;
SemaOpenMP::VarsWithInheritedDSAType VarsWithInheritedDSA;
llvm::SmallDenseSet<const ValueDecl *, 4> ImplicitDeclarations;
+ void visitCaptureThisMembers(Stmt *S) {
+ bool SavedTryCaptureCXXThisMembers = TryCaptureCXXThisMembers;
+ TryCaptureCXXThisMembers = true;
+ Visit(S);
+ TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers;
+ }
+
void VisitSubCaptures(OMPExecutableDirective *S) {
// Check implicitly captured variables.
if (!S->hasAssociatedStmt() || !S->getAssociatedStmt())
@@ -3757,15 +3942,8 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
// Try to capture inner this->member references to generate correct mappings
// and diagnostics.
if (TryCaptureCXXThisMembers ||
- (isOpenMPTargetExecutionDirective(DKind) &&
- llvm::any_of(S->getInnermostCapturedStmt()->captures(),
- [](const CapturedStmt::Capture &C) {
- return C.capturesThis();
- }))) {
- bool SavedTryCaptureCXXThisMembers = TryCaptureCXXThisMembers;
- TryCaptureCXXThisMembers = true;
- Visit(S->getInnermostCapturedStmt()->getCapturedStmt());
- TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers;
+ (isOpenMPTargetExecutionDirective(DKind) && CapturedThis)) {
+ visitCaptureThisMembers(S->getInnermostCapturedStmt()->getCapturedStmt());
}
// In tasks firstprivates are not captured anymore, need to analyze them
// explicitly.
@@ -3779,6 +3957,15 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
}
}
+ bool isCaptured(VarDecl *VD) const {
+ assert(CheckCaptures);
+ return CapturedCanonDecls.count(VD->getCanonicalDecl());
+ }
+
+ bool isInternal(VarDecl *VD) const {
+ return CheckCaptures && !isCaptured(VD);
+ }
+
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
if (TryCaptureCXXThisMembers || E->isTypeDependent() ||
@@ -3788,22 +3975,24 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
// Check the datasharing rules for the expressions in the clauses.
- if (!CS || (isa<OMPCapturedExprDecl>(VD) && !CS->capturesVariable(VD) &&
- !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr &&
- !Stack->isImplicitDefaultFirstprivateFD(VD))) {
+ if (!CheckCaptures ||
+ (isa<OMPCapturedExprDecl>(VD) && isInternal(VD) &&
+ !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr &&
+ !Stack->isImplicitDefaultFirstprivateFD(VD))) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
if (!CED->hasAttr<OMPCaptureNoInitAttr>()) {
Visit(CED->getInit());
return;
}
- } else if (VD->isImplicit() || isa<OMPCapturedExprDecl>(VD))
+ } else if (VD->isImplicit() || isa<OMPCapturedExprDecl>(VD)) {
// Do not analyze internal variables and do not enclose them into
// implicit clauses.
if (!Stack->isImplicitDefaultFirstprivateFD(VD))
return;
+ }
VD = VD->getCanonicalDecl();
// Skip internally declared variables.
- if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) &&
+ if (VD->hasLocalStorage() && isInternal(VD) &&
!Stack->isImplicitDefaultFirstprivateFD(VD) &&
!Stack->isImplicitTaskFirstprivate(VD))
return;
@@ -3819,7 +4008,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
// Skip internally declared static variables.
std::optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
+ if (VD->hasGlobalStorage() && isInternal(VD) &&
(Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) &&
!Stack->isImplicitDefaultFirstprivateFD(VD) &&
@@ -3885,13 +4074,8 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
if (SemaRef.getLangOpts().OpenMP > 50) {
bool IsModifierPresent = Stack->getDefaultmapModifier(ClauseKind) ==
OMPC_DEFAULTMAP_MODIFIER_present;
- if (IsModifierPresent) {
- if (!llvm::is_contained(ImpInfo.MapModifiers[ClauseKind],
- OMPC_MAP_MODIFIER_present)) {
- ImpInfo.MapModifiers[ClauseKind].push_back(
- OMPC_MAP_MODIFIER_present);
- }
- }
+ if (IsModifierPresent)
+ ImpInfo.addMapModifier(OMPC_MAP_MODIFIER_present, ClauseKind);
}
if (isOpenMPTargetExecutionDirective(DKind) &&
@@ -3928,13 +4112,13 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
IsFirstprivate =
IsFirstprivate || (Stack->mustBeFirstprivate(ClauseKind) && !Res);
if (IsFirstprivate) {
- ImpInfo.Firstprivates.insert(E);
+ ImpInfo.addFirstprivate(E);
} else {
OpenMPDefaultmapClauseModifier M =
Stack->getDefaultmapModifier(ClauseKind);
OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
M, ClauseKind == OMPC_DEFAULTMAP_aggregate || Res);
- ImpInfo.Mappings[ClauseKind][Kind].insert(E);
+ ImpInfo.addMapping(E, ClauseKind, Kind);
}
return;
}
@@ -3971,9 +4155,10 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
!DVar.RefExpr)) &&
!Stack->isLoopControlVariable(VD).first) {
if (Stack->getDefaultDSA() == DSA_private)
- ImpInfo.Privates.insert(E);
- else
- ImpInfo.Firstprivates.insert(E);
+ ImpInfo.addPrivate(E);
+ else {
+ ImpInfo.addFirstprivate(E);
+ }
return;
}
@@ -4030,7 +4215,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
getVariableCategoryFromDecl(SemaRef.getLangOpts(), FD);
OpenMPMapClauseKind Kind = getMapClauseKindFromModifier(
Modifier, /*IsAggregateOrDeclareTarget=*/true);
- ImpInfo.Mappings[ClauseKind][Kind].insert(E);
+ ImpInfo.addMapping(E, ClauseKind, Kind);
return;
}
@@ -4065,7 +4250,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
// expression.
// TODO: try to make it firstprivate.
if (DVar.CKind != OMPC_unknown)
- ImpInfo.Firstprivates.insert(E);
+ ImpInfo.addFirstprivate(E);
}
return;
}
@@ -4167,41 +4352,99 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
}
}
+ void visitCapturedVariable(VarDecl *VD, SourceLocation Loc) {
+ // Do not try to map the variable if it or its sub-component was mapped
+ // already.
+ if (isOpenMPTargetExecutionDirective(DKind) &&
+ Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind) { return true; }))
+ return;
+ DeclRefExpr *DRE = buildDeclRefExpr(
+ SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context), Loc,
+ /*RefersToCapture=*/true);
+ Visit(DRE);
+ }
+
void visitSubCaptures(CapturedStmt *S) {
for (const CapturedStmt::Capture &Cap : S->captures()) {
if (!Cap.capturesVariable() && !Cap.capturesVariableByCopy())
continue;
- VarDecl *VD = Cap.getCapturedVar();
- // Do not try to map the variable if it or its sub-component was mapped
- // already.
- if (isOpenMPTargetExecutionDirective(DKind) &&
- Stack->checkMappableExprComponentListsForDecl(
- VD, /*CurrentRegionOnly=*/true,
- [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
- OpenMPClauseKind) { return true; }))
- continue;
- DeclRefExpr *DRE = buildDeclRefExpr(
- SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context),
- Cap.getLocation(), /*RefersToCapture=*/true);
- Visit(DRE);
+ visitCapturedVariable(Cap.getCapturedVar(), Cap.getLocation());
}
}
+
+ void visitOpenCaptures() {
+ for (auto [CV, Loc] : CapturedVars)
+ visitCapturedVariable(CV, Loc);
+ }
+
bool isErrorFound() const { return ErrorFound; }
- const VariableImplicitInfo &getImplicitInfo() const { return ImpInfo; }
+ const SemaOpenMP::VariableImplicitInfo &getImplicitInfo() const {
+ return ImpInfo;
+ }
const SemaOpenMP::VarsWithInheritedDSAType &getVarsWithInheritedDSA() const {
return VarsWithInheritedDSA;
}
- DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS)
- : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {
- DKind = S->getCurrentDirective();
+ void processLinkGlobals() {
// Process declare target link variables for the target directives.
if (isOpenMPTargetExecutionDirective(DKind)) {
for (DeclRefExpr *E : Stack->getLinkGlobals())
Visit(E);
}
}
+
+ DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS)
+ : Stack(S), SemaRef(SemaRef), CheckCaptures(CS != nullptr) {
+ DKind = S->getCurrentDirective();
+
+ auto addCaptures = [&](CapturedStmt *C) {
+ for (CapturedStmt::Capture &Cap : C->captures()) {
+ if (Cap.capturesVariable() || Cap.capturesVariableByCopy()) {
+ VarDecl *VD = Cap.getCapturedVar();
+ CapturedVars.insert({VD, Cap.getLocation()});
+ CapturedCanonDecls.insert(VD->getCanonicalDecl());
+ } else if (Cap.capturesThis()) {
+ CapturedThis = true;
+ }
+ }
+ };
+
+ while (auto *C = dyn_cast_or_null<CapturedStmt>(CS)) {
+ addCaptures(C);
+ CS = dyn_cast<CapturedStmt>(C->getCapturedStmt());
+ }
+ // alternative:
+ // if (CS) addCaptures(CS);
+ processLinkGlobals();
+ }
+
+ struct UseScopes {};
+ // RegionIndex: innermost == 0
+ DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, size_t RegionIndex, UseScopes)
+ : Stack(S), SemaRef(SemaRef), CheckCaptures(true) {
+ DKind = S->getCurrentDirective();
+ ArrayRef<FunctionScopeInfo *> Scopes = SemaRef.getFunctionScopes();
+ assert(RegionIndex < Scopes.size());
+
+ FunctionScopeInfo *FSI = Scopes[Scopes.size() - RegionIndex - 1];
+ for (sema::Capture &Cap : cast<CapturingScopeInfo>(FSI)->Captures) {
+ if (Cap.isThisCapture())
+ CapturedThis = true;
+ if (!Cap.isVariableCapture())
+ continue;
+ if (auto *VD = dyn_cast<VarDecl>(Cap.getVariable())) {
+ CapturedVars.insert({VD, Cap.getLocation()});
+ CapturedCanonDecls.insert(VD->getCanonicalDecl());
+ }
+ }
+
+ processLinkGlobals();
+ }
};
+
} // namespace
static void handleDeclareVariantConstructTrait(DSAStackTy *Stack,
@@ -4331,7 +4574,6 @@ static void processCapturedRegions(Sema &SemaRef, OpenMPDirectiveKind DKind,
Scope *CurScope, SourceLocation Loc) {
SmallVector<OpenMPDirectiveKind> Regions;
getOpenMPCaptureRegions(Regions, DKind);
-
bool LoopBoundSharing = isOpenMPLoopBoundSharingDirective(DKind);
auto MarkAsInlined = [&](CapturedRegionScopeInfo *CSI) {
@@ -4372,7 +4614,7 @@ static void processCapturedRegions(Sema &SemaRef, OpenMPDirectiveKind DKind,
break;
case OMPD_unknown:
SemaRef.ActOnCapturedRegionStart(Loc, CurScope, CR_OpenMP,
- getUnknownRegionParams(SemaRef));
+ getUnknownRegionParams(SemaRef), Level);
break;
case OMPD_metadirective:
case OMPD_nothing:
@@ -4383,7 +4625,11 @@ static void processCapturedRegions(Sema &SemaRef, OpenMPDirectiveKind DKind,
}
void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
- Scope *CurScope) {
+ Scope *CurScope,
+ bool HasAssociatedStmt) {
+ if (!HasAssociatedStmt)
+ return;
+
switch (DKind) {
case OMPD_atomic:
case OMPD_critical:
@@ -4416,10 +4662,10 @@ int SemaOpenMP::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
return CaptureRegions.size();
}
-static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
- Expr *CaptureExpr, bool WithInit,
- DeclContext *CurContext,
- bool AsExpression) {
+static VarDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, Expr *CaptureExpr,
+ bool WithInit, DeclContext *CurContext,
+ bool AsExpression,
+ bool MakeOMPCapturedExprDecl) {
assert(CaptureExpr);
ASTContext &C = S.getASTContext();
Expr *Init = AsExpression ? CaptureExpr : CaptureExpr->IgnoreImpCasts();
@@ -4437,38 +4683,49 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
}
WithInit = true;
}
- auto *CED = OMPCapturedExprDecl::Create(C, CurContext, Id, Ty,
- CaptureExpr->getBeginLoc());
- if (!WithInit)
- CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C));
- CurContext->addHiddenDecl(CED);
+
+ VarDecl *VD;
+ if (MakeOMPCapturedExprDecl) {
+ VD = OMPCapturedExprDecl::Create(C, CurContext, Id, Ty,
+ CaptureExpr->getBeginLoc());
+ if (!WithInit)
+ VD->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C));
+ } else {
+ SourceLocation Loc = CaptureExpr->getBeginLoc();
+ VD = VarDecl::Create(C, CurContext, Loc, Loc, Id, Ty,
+ C.getTrivialTypeSourceInfo(Ty), SC_None);
+ }
+
+ CurContext->addHiddenDecl(VD);
Sema::TentativeAnalysisScope Trap(S);
- S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false);
- return CED;
+ S.AddInitializerToDecl(VD, Init, /*DirectInit=*/false);
+ return VD;
}
static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
bool WithInit) {
- OMPCapturedExprDecl *CD;
+ VarDecl *CD;
if (VarDecl *VD = S.OpenMP().isOpenMPCapturedDecl(D))
CD = cast<OMPCapturedExprDecl>(VD);
else
CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit,
- S.CurContext,
- /*AsExpression=*/false);
+ S.CurContext, /*AsExpression=*/false,
+ /*MakeOMPCapturedExprDecl=*/true);
return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
CaptureExpr->getExprLoc());
}
static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref,
- StringRef Name) {
+ bool RefersToCapture, StringRef Name,
+ bool MakeOMPCapturedExprDecl = true) {
CaptureExpr = S.DefaultLvalueConversion(CaptureExpr).get();
if (!Ref) {
- OMPCapturedExprDecl *CD = buildCaptureDecl(
- S, &S.getASTContext().Idents.get(Name), CaptureExpr,
- /*WithInit=*/true, S.CurContext, /*AsExpression=*/true);
+ VarDecl *CD =
+ buildCaptureDecl(S, &S.getASTContext().Idents.get(Name), CaptureExpr,
+ /*WithInit=*/true, S.CurContext, /*AsExpression=*/true,
+ MakeOMPCapturedExprDecl);
Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
- CaptureExpr->getExprLoc());
+ CaptureExpr->getExprLoc(), RefersToCapture);
}
ExprResult Res = Ref;
if (!S.getLangOpts().CPlusPlus &&
@@ -4580,62 +4837,30 @@ static bool checkOrderedOrderSpecified(Sema &S,
return false;
}
-StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S,
- ArrayRef<OMPClause *> Clauses) {
- handleDeclareVariantConstructTrait(DSAStack, DSAStack->getCurrentDirective(),
- /*ScopeEntry=*/false);
- if (!isOpenMPCapturingDirective(DSAStack->getCurrentDirective()))
- return S;
+static void
+getImplicitInfoFromClauses(Sema &SemaRef, OpenMPDirectiveKind DKind,
+ ArrayRef<OMPClause *> Clauses,
+ SemaOpenMP::VariableImplicitInfo &ImpInfo);
+
+static OMPClause *
+createImplicitClause(Sema &SemaRef, OpenMPDirectiveKind LeafKind,
+ DSAStackTy *Stack,
+ const SemaOpenMP::VariableImplicitInfo &ImpInfo,
+ const omp::Clause &ExtClause);
+static OMPClause *processImplicitMapWithDefaultMappers(Sema &S,
+ DSAStackTy *Stack,
+ OMPClause *Clause);
+
+static bool checkOrderedClause(Sema &SemaRef, OpenMPDirectiveKind DKind,
+ ArrayRef<OMPClause *> Clauses) {
+ // Diagnose violations of clause restrictions
bool ErrorFound = false;
- CaptureRegionUnwinderRAII CaptureRegionUnwinder(
- SemaRef, ErrorFound, DSAStack->getCurrentDirective());
- if (!S.isUsable()) {
- ErrorFound = true;
- return StmtError();
- }
- SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
- getOpenMPCaptureRegions(CaptureRegions, DSAStack->getCurrentDirective());
OMPOrderedClause *OC = nullptr;
OMPScheduleClause *SC = nullptr;
SmallVector<const OMPLinearClause *, 4> LCs;
- SmallVector<const OMPClauseWithPreInit *, 4> PICs;
- // This is required for proper codegen.
for (OMPClause *Clause : Clauses) {
- if (!getLangOpts().OpenMPSimd &&
- (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) ||
- DSAStack->getCurrentDirective() == OMPD_target) &&
- Clause->getClauseKind() == OMPC_in_reduction) {
- // Capture taskgroup task_reduction descriptors inside the tasking regions
- // with the corresponding in_reduction items.
- auto *IRC = cast<OMPInReductionClause>(Clause);
- for (Expr *E : IRC->taskgroup_descriptors())
- if (E)
- SemaRef.MarkDeclarationsReferencedInExpr(E);
- }
- if (isOpenMPPrivate(Clause->getClauseKind()) ||
- Clause->getClauseKind() == OMPC_copyprivate ||
- (getLangOpts().OpenMPUseTLS &&
- getASTContext().getTargetInfo().isTLSSupported() &&
- Clause->getClauseKind() == OMPC_copyin)) {
- DSAStack->setForceVarCapturing(Clause->getClauseKind() == OMPC_copyin);
- // Mark all variables in private list clauses as used in inner region.
- for (Stmt *VarRef : Clause->children()) {
- if (auto *E = cast_or_null<Expr>(VarRef)) {
- SemaRef.MarkDeclarationsReferencedInExpr(E);
- }
- }
- DSAStack->setForceVarCapturing(/*V=*/false);
- } else if (CaptureRegions.size() > 1 ||
- CaptureRegions.back() != OMPD_unknown) {
- if (auto *C = OMPClauseWithPreInit::get(Clause))
- PICs.push_back(C);
- if (auto *C = OMPClauseWithPostUpdate::get(Clause)) {
- if (Expr *E = C->getPostUpdateExpr())
- SemaRef.MarkDeclarationsReferencedInExpr(E);
- }
- }
if (Clause->getClauseKind() == OMPC_schedule)
SC = cast<OMPScheduleClause>(Clause);
else if (Clause->getClauseKind() == OMPC_ordered)
@@ -4643,9 +4868,6 @@ StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S,
else if (Clause->getClauseKind() == OMPC_linear)
LCs.push_back(cast<OMPLinearClause>(Clause));
}
- // Capture allocator expressions if used.
- for (Expr *E : DSAStack->getInnerAllocators())
- SemaRef.MarkDeclarationsReferencedInExpr(E);
// OpenMP, 2.7.1 Loop Construct, Restrictions
// The nonmonotonic modifier cannot be specified if an ordered clause is
// specified.
@@ -4654,10 +4876,11 @@ StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S,
SC->getSecondScheduleModifier() ==
OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
OC) {
- Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic
- ? SC->getFirstScheduleModifierLoc()
- : SC->getSecondScheduleModifierLoc(),
- diag::err_omp_simple_clause_incompatible_with_ordered)
+ SemaRef.Diag(SC->getFirstScheduleModifier() ==
+ OMPC_SCHEDULE_MODIFIER_nonmonotonic
+ ? SC->getFirstScheduleModifierLoc()
+ : SC->getSecondScheduleModifierLoc(),
+ diag::err_omp_simple_clause_incompatible_with_ordered)
<< getOpenMPClauseName(OMPC_schedule)
<< getOpenMPSimpleClauseTypeName(OMPC_schedule,
OMPC_SCHEDULE_MODIFIER_nonmonotonic)
@@ -4665,44 +4888,222 @@ StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S,
ErrorFound = true;
}
// OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Restrictions.
- // If an order(concurrent) clause is present, an ordered clause may not appear
- // on the same directive.
+ // If an order(concurrent) clause is present, an ordered clause may not
+ // appear on the same directive.
if (checkOrderedOrderSpecified(SemaRef, Clauses))
ErrorFound = true;
if (!LCs.empty() && OC && OC->getNumForLoops()) {
for (const OMPLinearClause *C : LCs) {
- Diag(C->getBeginLoc(), diag::err_omp_linear_ordered)
+ SemaRef.Diag(C->getBeginLoc(), diag::err_omp_linear_ordered)
<< SourceRange(OC->getBeginLoc(), OC->getEndLoc());
}
ErrorFound = true;
}
- if (isOpenMPWorksharingDirective(DSAStack->getCurrentDirective()) &&
- isOpenMPSimdDirective(DSAStack->getCurrentDirective()) && OC &&
- OC->getNumForLoops()) {
- Diag(OC->getBeginLoc(), diag::err_omp_ordered_simd)
- << getOpenMPDirectiveName(DSAStack->getCurrentDirective());
+ if (isOpenMPWorksharingDirective(DKind) && isOpenMPSimdDirective(DKind) &&
+ OC && OC->getNumForLoops()) {
+ SemaRef.Diag(OC->getBeginLoc(), diag::err_omp_ordered_simd)
+ << getOpenMPDirectiveName(DKind);
ErrorFound = true;
}
- if (ErrorFound) {
- return StmtError();
+
+ return ErrorFound;
+}
+
+// The ImpInfo will be used to create omp::Clause's, but it also contains
+// additional info, like source locations.
+struct VariableImplicitInfoQueues : public SemaOpenMP::VariableImplicitInfo {
+ VariableImplicitInfoQueues() {
+ PrivatesQ = Privates;
+ FirstprivatesQ = Firstprivates;
+ for (size_t I = 0; I != DefaultmapKindNum; ++I) {
+ for (size_t J = 0; J != MapKindNum; ++J)
+ MappingsQ[I][J] = Mappings[I][J];
+ MapModifiersQ[I] = MapModifiers[I];
+ }
+ ReductionMappingsQ = ReductionMappings;
}
- StmtResult SR = S;
- unsigned CompletedRegions = 0;
- for (OpenMPDirectiveKind ThisCaptureRegion : llvm::reverse(CaptureRegions)) {
+
+ using MappingTy = std::remove_reference_t<decltype(Mappings[0][0])>;
+ using MapModifierTy = std::remove_reference_t<decltype(MapModifiers[0])>;
+ QueueAdapter<decltype(Privates)> PrivatesQ;
+ QueueAdapter<decltype(Firstprivates)> FirstprivatesQ;
+ QueueAdapter<MappingTy> MappingsQ[DefaultmapKindNum][MapKindNum];
+ QueueAdapter<MapModifierTy> MapModifiersQ[DefaultmapKindNum];
+ QueueAdapter<decltype(ReductionMappings)> ReductionMappingsQ;
+};
+
+static void generateExtClauseForBind(Sema &SemaRef, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses,
+ SmallVectorImpl<omp::Clause> &ExtClauses) {
+ OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
+ unsigned OpenMPVersion = SemaRef.getLangOpts().OpenMP;
+ if (OpenMPVersion < 50 || !isOpenMPGenericLoopDirective(DKind))
+ return;
+
+ auto IsBind = [](OMPClause *C) { return C->getClauseKind() == OMPC_bind; };
+
+ auto F = llvm::find_if(Clauses, IsBind);
+ if (F != Clauses.end()) {
+ // Bind clause is already present.
+ return;
+ }
+
+ // Bind clause not found, infer the binding type from the constituent
+ // directives.
+ // [5.0:129:25-28] If the bind clause is not present on the construct and
+ // the loop construct is closely nested inside a teams or parallel
+ // construct, the binding region is the corresponding teams or parallel
+ // region. If none of those conditions hold, the binding region is not
+ // defined.
+ auto determineBinding = [&](OpenMPDirectiveKind DFrom) {
+ OpenMPBindClauseKind BindKind = OMPC_BIND_unknown;
+ ArrayRef<OpenMPDirectiveKind> Leafs = getLeafConstructsOrSelf(DFrom);
+
+ for (OpenMPDirectiveKind L : llvm::reverse(Leafs)) {
+ if (L == OMPD_parallel)
+ BindKind = OMPC_BIND_parallel;
+ else if (L == OMPD_teams)
+ BindKind = OMPC_BIND_teams;
+ else if (L == OMPD_simd)
+ BindKind = OMPC_BIND_thread;
+ if (BindKind != OMPC_BIND_unknown)
+ break;
+ }
+
+ return BindKind;
+ };
+
+ // "Kind" may be a compound directive that contains "loop" as a leaf.
+ // Try to determine the binding from it first, then from the parent.
+ OpenMPBindClauseKind BindKind = determineBinding(DKind);
+ if (BindKind == OMPC_BIND_unknown)
+ BindKind = determineBinding(Stack->getParentDirective());
+
+ // Default bind(thread) if binding is unknown.
+ if (BindKind == OMPC_BIND_unknown) {
+ SemaRef.Diag(Stack->getDefaultDSALocation(),
+ diag::err_omp_bind_required_on_loop);
+ BindKind = OMPC_BIND_thread;
+ }
+
+ using TagType = omp::Clause::TagType;
+ assert(BindKind != OMPC_BIND_unknown && "Binding must be known");
+
+ auto C = omp::clause::Bind{/*Binding=*/*ext::conv(BindKind)};
+ ExtClauses.push_back(omp::Clause{{OMPC_bind, C}, TagType::get()});
+}
+
+static void
+generateExtClausesFromImplicit(VariableImplicitInfoQueues &ImpInfoQs,
+ SmallVectorImpl<omp::Clause> &ExtClauses) {
+ using TagType = omp::Clause::TagType;
+
+ // The compound directive splitting will assign clauses to leaf constructs
+ // based only on the OpenMP rules. For example, in
+ // #pragma omp target parallel num_threads(n + k)
+ // {...use(k)...}
+ // both n and k may end up being implicitly firstprivate. The OpenMP rules
+ // will dictate that the firstprivate clause applies to both `target`, and
+ // `parallel`. The problem is that the parallel region does not use n,
+ // and the codegen for firstprivate(n) will try to insert copy-in for it
+ // into the region. This will fail, since the original n is not available
+ // there.
+ //
+ // Create individual clauses for each variable. This will allow to filter
+ // out the unnecessary ones, where the variable is not captured in the
+ // corresponding region.
+
+ while (!ImpInfoQs.PrivatesQ.empty()) {
+ Expr *E = ImpInfoQs.PrivatesQ.take();
+ auto C = ext::clause::Private{/*List=*/{ext::makeObject(E)}};
+ ExtClauses.push_back(ext::Clause{{OMPC_private, C}, TagType::get()});
+ }
+
+ while (!ImpInfoQs.FirstprivatesQ.empty()) {
+ Expr *E = ImpInfoQs.FirstprivatesQ.take();
+ auto C = ext::clause::Firstprivate{/*List=*/{ext::makeObject(E)}};
+ ExtClauses.push_back(ext::Clause{{OMPC_firstprivate, C}, TagType::get()});
+ }
+
+ for (size_t I = 0; I != ImpInfoQs.DefaultmapKindNum; ++I) {
+ ext::clause::Map::MapTypeModifiers MapMods;
+
+ while (!ImpInfoQs.MapModifiersQ[I].empty()) {
+ OpenMPMapModifierKind M = ImpInfoQs.MapModifiersQ[I].take();
+ if (auto MaybeMod = ext::conv(M))
+ MapMods.push_back(*MaybeMod);
+ }
+
+ for (size_t J = 0; J != ImpInfoQs.MapKindNum; ++J) {
+ auto &MappingsQ = ImpInfoQs.MappingsQ[I][J];
+ ArrayRef<Expr *> Tail = MappingsQ.takeAll();
+ if (Tail.empty())
+ continue;
+
+ auto MaybeType = ext::conv(static_cast<OpenMPMapClauseKind>(J));
+ auto C =
+ ext::clause::Map{{/*MapType=*/MaybeType, /*MapTypeModifiers=*/MapMods,
+ /*Mappers=*/std::nullopt, /*Iterator=*/std::nullopt,
+ /*LocatorList=*/ext::makeObjects(Tail)}};
+ ExtClauses.push_back(ext::Clause{{OMPC_map, C}, TagType::get(I, J)});
+ }
+ }
+
+ // Do all reduction mappings in a single clause.
+ if (!ImpInfoQs.ReductionMappingsQ.empty()) {
+ ArrayRef<Expr *> Tail = ImpInfoQs.ReductionMappingsQ.takeAll();
+ auto RedMapC =
+ ext::clause::Map{{/*MapType=*/ext::clause::Map::MapType::Tofrom,
+ /*MapTypeModifiers=*/std::nullopt,
+ /*Mappers=*/std::nullopt, /*Iterator=*/std::nullopt,
+ /*LocatorList=*/ext::makeObjects(Tail)}};
+ ExtClauses.push_back(ext::Clause{{OMPC_map, RedMapC}, TagType::get()});
+ }
+}
+
+static void captureObjectsInClause(Sema &SemaRef, DSAStackTy *Stack,
+ OpenMPDirectiveKind DKind,
+ OMPClause *Clause) {
+ OpenMPClauseKind CKind = Clause->getClauseKind();
+ if (!SemaRef.getLangOpts().OpenMPSimd &&
+ (isOpenMPTaskingDirective(DKind) || DKind == OMPD_target) &&
+ CKind == OMPC_in_reduction) {
+ // Capture taskgroup task_reduction descriptors inside the tasking
+ // regions with the corresponding in_reduction items.
+ auto *IRC = cast<OMPInReductionClause>(Clause);
+ for (Expr *E : IRC->taskgroup_descriptors())
+ if (E)
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
+ }
+ if (isOpenMPPrivate(CKind) || CKind == OMPC_copyprivate ||
+ (SemaRef.getLangOpts().OpenMPUseTLS &&
+ SemaRef.getASTContext().getTargetInfo().isTLSSupported() &&
+ CKind == OMPC_copyin)) {
+ Stack->setForceVarCapturing(CKind == OMPC_copyin);
// Mark all variables in private list clauses as used in inner region.
- // Required for proper codegen of combined directives.
- // TODO: add processing for other clauses.
- if (ThisCaptureRegion != OMPD_unknown) {
- for (const clang::OMPClauseWithPreInit *C : PICs) {
- OpenMPDirectiveKind CaptureRegion = C->getCaptureRegion();
- // Find the particular capture region for the clause if the
- // directive is a combined one with multiple capture regions.
- // If the directive is not a combined one, the capture region
- // associated with the clause is OMPD_unknown and is generated
- // only once.
- if (CaptureRegion == ThisCaptureRegion ||
- CaptureRegion == OMPD_unknown) {
- if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) {
+ for (Stmt *VarRef : Clause->children()) {
+ if (auto *E = cast_or_null<Expr>(VarRef))
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
+ }
+ Stack->setForceVarCapturing(/*V=*/false);
+ } else {
+ if (auto *PIC = OMPClauseWithPreInit::get(Clause)) {
+ assert(!PIC->getPreInitStmt() && "PreInit stmt no longer expected");
+ if (CKind != OMPC_num_teams && CKind != OMPC_thread_limit) {
+ // This used to be done indirectly by creating the captured
+ // expression for the pre-init.
+ for (auto *Ch : Clause->children()) {
+ if (auto *E = dyn_cast_or_null<Expr>(Ch))
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
+ }
+ } else {
+ // Either num_teams or thread_limit.
+ assert(CKind == OMPC_num_teams || CKind == OMPC_thread_limit);
+ auto &PreInits = Stack->getPreInits();
+ for (auto [C, P] : PreInits) {
+ if (C != Clause)
+ continue;
+ if (auto *DS = cast_or_null<DeclStmt>(P)) {
for (Decl *D : DS->decls())
SemaRef.MarkVariableReferenced(D->getLocation(),
cast<VarDecl>(D));
@@ -4710,42 +5111,223 @@ StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S,
}
}
}
- if (ThisCaptureRegion == OMPD_target) {
- // Capture allocator traits in the target region. They are used implicitly
- // and, thus, are not captured by default.
- for (OMPClause *C : Clauses) {
- if (const auto *UAC = dyn_cast<OMPUsesAllocatorsClause>(C)) {
- for (unsigned I = 0, End = UAC->getNumberOfAllocators(); I < End;
- ++I) {
- OMPUsesAllocatorsClause::Data D = UAC->getAllocatorData(I);
- if (Expr *E = D.AllocatorTraits)
- SemaRef.MarkDeclarationsReferencedInExpr(E);
- }
- continue;
- }
- }
+ if (auto *PUC = OMPClauseWithPostUpdate::get(Clause)) {
+ if (Expr *E = PUC->getPostUpdateExpr())
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
}
- if (ThisCaptureRegion == OMPD_parallel) {
- // Capture temp arrays for inscan reductions and locals in aligned
- // clauses.
- for (OMPClause *C : Clauses) {
- if (auto *RC = dyn_cast<OMPReductionClause>(C)) {
- if (RC->getModifier() != OMPC_REDUCTION_inscan)
- continue;
- for (Expr *E : RC->copy_array_temps())
- if (E)
- SemaRef.MarkDeclarationsReferencedInExpr(E);
- }
- if (auto *AC = dyn_cast<OMPAlignedClause>(C)) {
- for (Expr *E : AC->varlist())
- SemaRef.MarkDeclarationsReferencedInExpr(E);
+ }
+
+ if (auto *Alloc = dyn_cast<OMPAllocateClause>(Clause)) {
+ if (Expr *E = Alloc->getAllocator())
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
+ } else if (auto *Aligned = dyn_cast<OMPAlignedClause>(Clause)) {
+ // The children of "aligned" don't seem to be visited anywhere.
+ // Is this an isolated case, or do we need to visit more clauses here?
+ if (Expr *E = Aligned->getAlignment())
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
+ for (Stmt *VarRef : Aligned->children()) {
+ if (Expr *E = dyn_cast<Expr>(VarRef))
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
+ }
+ } else if (const auto *UAC = dyn_cast<OMPUsesAllocatorsClause>(Clause)) {
+ // Capture allocator traits in the target region. They are used
+ // implicitly and, thus, are not captured by default.
+ for (unsigned I = 0, N = UAC->getNumberOfAllocators(); I < N; ++I) {
+ OMPUsesAllocatorsClause::Data D = UAC->getAllocatorData(I);
+ if (Expr *E = D.AllocatorTraits)
+ SemaRef.MarkDeclarationsReferencedInExpr(E);
+ }
+ }
+}
+
+StmtResult SemaOpenMP::ActOnOpenMPRegionEnd(StmtResult S,
+ ArrayRef<OMPClause *> Clauses) {
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ if (!S.isUnset())
+ handleDeclareVariantConstructTrait(DSAStack, DKind, /*ScopeEntry=*/false);
+ StmtResult SR = S;
+ bool IsCapturing =
+ isOpenMPCapturingDirective(DKind, /*OrderedIsStandalone=*/S.isUnset());
+ bool IsTemplate = SemaRef.CurContext->isDependentContext();
+ unsigned OpenMPVersion = SemaRef.getLangOpts().OpenMP;
+
+ SemaOpenMP::VarsWithInheritedDSAType VarsWithInheritedDSA;
+ VariableImplicitInfoQueues ImpInfoQs;
+
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ if (IsCapturing)
+ getOpenMPCaptureRegions(CaptureRegions, DKind);
+ size_t NumCaptureRegions = CaptureRegions.size();
+ size_t RemainingCaptureRegions = NumCaptureRegions;
+
+ bool ErrorFound = false;
+
+ auto makeOriginal = [&] {
+ UnitConstruct Original;
+ Original.DKind = DKind;
+ Original.Clauses.assign(Clauses.begin(), Clauses.end());
+ return Original;
+ };
+
+ if (S.isInvalid() && !IsCapturing)
+ return StmtError();
+
+ CaptureRegionUnwinderRAII CaptureRegionUnwinder(SemaRef, ErrorFound, DKind);
+ if (S.isInvalid()) {
+ ErrorFound = true;
+ return StmtError();
+ }
+
+ if (IsCapturing && !IsTemplate && SR.isUsable()) {
+ Stmt *T = SR.get();
+ for (size_t I = 0; I != NumCaptureRegions - RemainingCaptureRegions; ++I)
+ T = cast<CapturedStmt>(T)->getCapturedStmt();
+ DSAAttrChecker DSAChecker(DSAStack, SemaRef, /*RegionIndex=*/0,
+ DSAAttrChecker::UseScopes{});
+ DSAChecker.Visit(T);
+ DSAChecker.visitOpenCaptures();
+
+ DSAStack->getTopOfStack().HasDSAError |= DSAChecker.isErrorFound();
+ ImpInfoQs.include(DSAChecker.getImplicitInfo());
+ getImplicitInfoFromClauses(SemaRef, DKind, Clauses, ImpInfoQs);
+ for (auto [Decl, Expr] : DSAChecker.getVarsWithInheritedDSA())
+ VarsWithInheritedDSA.insert(std::make_pair(Decl, Expr));
+ }
+
+ // Create the initial set of clauses
+ llvm::SmallVector<omp::Clause> ExtClauses;
+ if (!IsTemplate)
+ llvm::append_range(ExtClauses, ext::makeClauses(Clauses));
+
+ ErrorFound = checkOrderedClause(SemaRef, DKind, Clauses) || ErrorFound;
+ if (ErrorFound)
+ return StmtError();
+
+ generateExtClauseForBind(SemaRef, DSAStack, Clauses, ExtClauses);
+
+ // Convert unprocessed implicit info to ext clauses.
+ generateExtClausesFromImplicit(ImpInfoQs, ExtClauses);
+
+ auto &UnitConstructs = DSAStack->getTopOfStack().UnitConstructs;
+ std::unique_ptr<ExtConstructDecomposition> Splitter;
+
+ auto AppendImplicitClause = [&](UnitConstruct &Unit, const ext::Clause &EC) {
+ OMPClause *IC =
+ createImplicitClause(SemaRef, Unit.DKind, DSAStack, ImpInfoQs, EC);
+ Unit.Clauses.push_back(IC);
+ OMPClause *DM = processImplicitMapWithDefaultMappers(SemaRef, DSAStack, IC);
+ if (DM)
+ Unit.Clauses.push_back(DM);
+ };
+
+ if (!IsTemplate) {
+ Splitter = std::make_unique<ExtConstructDecomposition>(DKind, ExtClauses,
+ OpenMPVersion);
+
+ // Transfer the initial breakdown of the original directive into
+ // UnitConstructs.
+ for (ExtConstructDecomposition::ExtConstruct &Con : Splitter->Output) {
+ UnitConstruct Unit{Con.DKind};
+
+ while (!Con.ClausesQ.empty()) {
+ const ext::Clause &EC = Con.ClausesQ.take();
+ if (EC.tag.getFlags() == EC.tag.Explicit) {
+ if (auto *P = static_cast<OMPClause *>(EC.tag.getPointer()))
+ Unit.Clauses.push_back(P);
+ else
+ AppendImplicitClause(Unit, EC);
+ } else {
+ // Delay creating these (because "task")
+ Unit.Pending.push_back(std::move(EC));
}
}
+
+ UnitConstructs.push_back(std::move(Unit));
}
- if (++CompletedRegions == CaptureRegions.size())
- DSAStack->setBodyComplete();
- SR = SemaRef.ActOnCapturedRegionEnd(SR.get());
}
+
+ if (!Splitter || Splitter->Output.empty()) {
+ // This is intended to cover the case of IsTemplate being true,
+ // and the case when splitting failed. In both cases, treat the
+ // original directive with explicit clauses as the only unit.
+ assert(IsTemplate == !Splitter);
+ assert(!IsTemplate || ImpInfoQs.empty());
+ assert(UnitConstructs.empty());
+ UnitConstructs.push_back(makeOriginal());
+ }
+
+ auto CreatePendingClauses = [&](UnitConstruct &Unit) {
+ for (ext::Clause &EC : Unit.Pending)
+ AppendImplicitClause(Unit, EC);
+ Unit.Pending.clear();
+ };
+
+ for (size_t ConIdx = UnitConstructs.size(); ConIdx != 0; --ConIdx) {
+ UnitConstruct &Unit = UnitConstructs[ConIdx - 1];
+ // If the unit directive is not task, create AST nodes for the pending
+ // clauses early on. This will potentially capture variables from these
+ // clauses, somrthing that should be avoided for task.
+ if (Unit.DKind != OMPD_task)
+ CreatePendingClauses(Unit);
+ if (!isOpenMPCapturingDirective(Unit.DKind,
+ /*OrderedIsStandalone=*/S.isUnset())) {
+ continue;
+ }
+ DSAAttrChecker PerUnitChecker(DSAStack, SemaRef, /*RegionIndex=*/0,
+ DSAAttrChecker::UseScopes{});
+
+ SmallVector<OpenMPDirectiveKind, 4> Regions;
+ getOpenMPCaptureRegions(Regions, Unit.DKind);
+
+ for (OMPClause *Clause : Unit.Clauses)
+ captureObjectsInClause(SemaRef, DSAStack, Unit.DKind, Clause);
+
+ OpenMPDirectiveKind PrevRegion = OMPD_unknown;
+ for (OpenMPDirectiveKind ThisRegion : llvm::reverse(Regions)) {
+ if (ThisRegion != OMPD_task || PrevRegion != OMPD_target) {
+ PerUnitChecker.visitOpenCaptures();
+ for (auto [Decl, Expr] : PerUnitChecker.getVarsWithInheritedDSA())
+ VarsWithInheritedDSA.insert(std::make_pair(Decl, Expr));
+ }
+
+ PrevRegion = ThisRegion;
+ assert(RemainingCaptureRegions > 0 && "Processed too many regions");
+ --RemainingCaptureRegions;
+ SR = SemaRef.ActOnCapturedRegionEnd(SR.get());
+ } // for (ThisRegion)
+
+ // Create implicit clauses after closing the regions to avoid creating
+ // unwanted captures for variables referenced in these clauses.
+ if (Unit.DKind == OMPD_task)
+ CreatePendingClauses(Unit);
+
+ if (IsTemplate)
+ continue;
+
+ // Make ext clauses from the implicit info from PerUnitChecker.
+ ImpInfoQs.include(PerUnitChecker.getImplicitInfo());
+ DSAStack->getTopOfStack().HasDSAError |= PerUnitChecker.isErrorFound();
+
+ QueueAdapter ExtClausesQ(ExtClauses);
+ generateExtClausesFromImplicit(ImpInfoQs, ExtClauses);
+
+ // Apply the clauses created above.
+ while (!ExtClausesQ.empty()) {
+ omp::Clause &EC = ExtClausesQ.take();
+ Splitter->postApply(EC, nullptr); // Ignore result.
+ // Extract the newly added clauses from Splitter.Output, and append them
+ // to Unit.Pending for ExtConstructs that haven't been processed yet.
+ for (size_t Idx = 0; Idx < ConIdx - 1; ++Idx) {
+ auto &Queue = Splitter->Output[Idx].ClausesQ;
+ llvm::append_range(UnitConstructs[Idx].Pending, Queue.takeAll());
+ }
+ }
+ } // for (ConIdx)
+
+ if (RemainingCaptureRegions == 0)
+ DSAStack->setBodyComplete();
+
+ DSAStack->getTopOfStack().VarsWithInheritedDSA = VarsWithInheritedDSA;
return SR;
}
@@ -5764,136 +6346,135 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
/// Perform DFS through the structure/class data members trying to find
/// member(s) with user-defined 'default' mapper and generate implicit map
/// clauses for such members with the found 'default' mapper.
-static void
-processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack,
- SmallVectorImpl<OMPClause *> &Clauses) {
+static OMPClause *processImplicitMapWithDefaultMappers(Sema &S,
+ DSAStackTy *Stack,
+ OMPClause *Clause) {
// Check for the default mapper for data members.
if (S.getLangOpts().OpenMP < 50)
- return;
- SmallVector<OMPClause *, 4> ImplicitMaps;
- for (int Cnt = 0, EndCnt = Clauses.size(); Cnt < EndCnt; ++Cnt) {
- auto *C = dyn_cast<OMPMapClause>(Clauses[Cnt]);
- if (!C)
+ return nullptr;
+
+ auto *MapC = dyn_cast<OMPMapClause>(Clause);
+ if (!MapC)
+ return nullptr;
+
+ SmallVector<Expr *, 4> SubExprs;
+ auto *MI = MapC->mapperlist_begin();
+ for (auto I = MapC->varlist_begin(), End = MapC->varlist_end(); I != End;
+ ++I, ++MI) {
+ // Expression is mapped using mapper - skip it.
+ if (*MI)
continue;
- SmallVector<Expr *, 4> SubExprs;
- auto *MI = C->mapperlist_begin();
- for (auto I = C->varlist_begin(), End = C->varlist_end(); I != End;
- ++I, ++MI) {
- // Expression is mapped using mapper - skip it.
- if (*MI)
+ Expr *E = *I;
+ // Expression is dependent - skip it, build the mapper when it gets
+ // instantiated.
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ E->containsUnexpandedParameterPack())
+ continue;
+ // Array section - need to check for the mapping of the array section
+ // element.
+ QualType CanonType = E->getType().getCanonicalType();
+ if (CanonType->isSpecificBuiltinType(BuiltinType::ArraySection)) {
+ const auto *OASE = cast<ArraySectionExpr>(E->IgnoreParenImpCasts());
+ QualType BaseType =
+ ArraySectionExpr::getBaseOriginalType(OASE->getBase());
+ QualType ElemType;
+ if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
+ ElemType = ATy->getElementType();
+ else
+ ElemType = BaseType->getPointeeType();
+ CanonType = ElemType;
+ }
+
+ // DFS over data members in structures/classes.
+ SmallVector<std::pair<QualType, FieldDecl *>, 4> Types(
+ 1, {CanonType, nullptr});
+ llvm::DenseMap<const Type *, Expr *> Visited;
+ SmallVector<std::pair<FieldDecl *, unsigned>, 4> ParentChain(1,
+ {nullptr, 1});
+ while (!Types.empty()) {
+ QualType BaseType;
+ FieldDecl *CurFD;
+ std::tie(BaseType, CurFD) = Types.pop_back_val();
+ while (ParentChain.back().second == 0)
+ ParentChain.pop_back();
+ --ParentChain.back().second;
+ if (BaseType.isNull())
continue;
- Expr *E = *I;
- // Expression is dependent - skip it, build the mapper when it gets
- // instantiated.
- if (E->isTypeDependent() || E->isValueDependent() ||
- E->containsUnexpandedParameterPack())
+ // Only structs/classes are allowed to have mappers.
+ const RecordDecl *RD = BaseType.getCanonicalType()->getAsRecordDecl();
+ if (!RD)
continue;
- // Array section - need to check for the mapping of the array section
- // element.
- QualType CanonType = E->getType().getCanonicalType();
- if (CanonType->isSpecificBuiltinType(BuiltinType::ArraySection)) {
- const auto *OASE = cast<ArraySectionExpr>(E->IgnoreParenImpCasts());
- QualType BaseType =
- ArraySectionExpr::getBaseOriginalType(OASE->getBase());
- QualType ElemType;
- if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
- ElemType = ATy->getElementType();
- else
- ElemType = BaseType->getPointeeType();
- CanonType = ElemType;
- }
-
- // DFS over data members in structures/classes.
- SmallVector<std::pair<QualType, FieldDecl *>, 4> Types(
- 1, {CanonType, nullptr});
- llvm::DenseMap<const Type *, Expr *> Visited;
- SmallVector<std::pair<FieldDecl *, unsigned>, 4> ParentChain(
- 1, {nullptr, 1});
- while (!Types.empty()) {
- QualType BaseType;
- FieldDecl *CurFD;
- std::tie(BaseType, CurFD) = Types.pop_back_val();
- while (ParentChain.back().second == 0)
- ParentChain.pop_back();
- --ParentChain.back().second;
- if (BaseType.isNull())
- continue;
- // Only structs/classes are allowed to have mappers.
- const RecordDecl *RD = BaseType.getCanonicalType()->getAsRecordDecl();
- if (!RD)
+ auto It = Visited.find(BaseType.getTypePtr());
+ if (It == Visited.end()) {
+ // Try to find the associated user-defined mapper.
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo DefaultMapperId;
+ DefaultMapperId.setName(S.Context.DeclarationNames.getIdentifier(
+ &S.Context.Idents.get("default")));
+ DefaultMapperId.setLoc(E->getExprLoc());
+ ExprResult ER = buildUserDefinedMapperRef(
+ S, Stack->getCurScope(), MapperIdScopeSpec, DefaultMapperId,
+ BaseType, /*UnresolvedMapper=*/nullptr);
+ if (ER.isInvalid())
continue;
- auto It = Visited.find(BaseType.getTypePtr());
- if (It == Visited.end()) {
- // Try to find the associated user-defined mapper.
- CXXScopeSpec MapperIdScopeSpec;
- DeclarationNameInfo DefaultMapperId;
- DefaultMapperId.setName(S.Context.DeclarationNames.getIdentifier(
- &S.Context.Idents.get("default")));
- DefaultMapperId.setLoc(E->getExprLoc());
- ExprResult ER = buildUserDefinedMapperRef(
- S, Stack->getCurScope(), MapperIdScopeSpec, DefaultMapperId,
- BaseType, /*UnresolvedMapper=*/nullptr);
- if (ER.isInvalid())
- continue;
- It = Visited.try_emplace(BaseType.getTypePtr(), ER.get()).first;
- }
- // Found default mapper.
- if (It->second) {
- auto *OE = new (S.Context) OpaqueValueExpr(E->getExprLoc(), CanonType,
- VK_LValue, OK_Ordinary, E);
- OE->setIsUnique(/*V=*/true);
- Expr *BaseExpr = OE;
- for (const auto &P : ParentChain) {
- if (P.first) {
- BaseExpr = S.BuildMemberExpr(
- BaseExpr, /*IsArrow=*/false, E->getExprLoc(),
- NestedNameSpecifierLoc(), SourceLocation(), P.first,
- DeclAccessPair::make(P.first, P.first->getAccess()),
- /*HadMultipleCandidates=*/false, DeclarationNameInfo(),
- P.first->getType(), VK_LValue, OK_Ordinary);
- BaseExpr = S.DefaultLvalueConversion(BaseExpr).get();
- }
- }
- if (CurFD)
+ It = Visited.try_emplace(BaseType.getTypePtr(), ER.get()).first;
+ }
+ // Found default mapper.
+ if (It->second) {
+ auto *OE = new (S.Context) OpaqueValueExpr(E->getExprLoc(), CanonType,
+ VK_LValue, OK_Ordinary, E);
+ OE->setIsUnique(/*V=*/true);
+ Expr *BaseExpr = OE;
+ for (const auto &P : ParentChain) {
+ if (P.first) {
BaseExpr = S.BuildMemberExpr(
BaseExpr, /*IsArrow=*/false, E->getExprLoc(),
- NestedNameSpecifierLoc(), SourceLocation(), CurFD,
- DeclAccessPair::make(CurFD, CurFD->getAccess()),
+ NestedNameSpecifierLoc(), SourceLocation(), P.first,
+ DeclAccessPair::make(P.first, P.first->getAccess()),
/*HadMultipleCandidates=*/false, DeclarationNameInfo(),
- CurFD->getType(), VK_LValue, OK_Ordinary);
- SubExprs.push_back(BaseExpr);
- continue;
- }
- // Check for the "default" mapper for data members.
- bool FirstIter = true;
- for (FieldDecl *FD : RD->fields()) {
- if (!FD)
- continue;
- QualType FieldTy = FD->getType();
- if (FieldTy.isNull() ||
- !(FieldTy->isStructureOrClassType() || FieldTy->isUnionType()))
- continue;
- if (FirstIter) {
- FirstIter = false;
- ParentChain.emplace_back(CurFD, 1);
- } else {
- ++ParentChain.back().second;
+ P.first->getType(), VK_LValue, OK_Ordinary);
+ BaseExpr = S.DefaultLvalueConversion(BaseExpr).get();
}
- Types.emplace_back(FieldTy, FD);
}
+ if (CurFD)
+ BaseExpr = S.BuildMemberExpr(
+ BaseExpr, /*IsArrow=*/false, E->getExprLoc(),
+ NestedNameSpecifierLoc(), SourceLocation(), CurFD,
+ DeclAccessPair::make(CurFD, CurFD->getAccess()),
+ /*HadMultipleCandidates=*/false, DeclarationNameInfo(),
+ CurFD->getType(), VK_LValue, OK_Ordinary);
+ SubExprs.push_back(BaseExpr);
+ continue;
+ }
+ // Check for the "default" mapper for data members.
+ bool FirstIter = true;
+ for (FieldDecl *FD : RD->fields()) {
+ if (!FD)
+ continue;
+ QualType FieldTy = FD->getType();
+ if (FieldTy.isNull() ||
+ !(FieldTy->isStructureOrClassType() || FieldTy->isUnionType()))
+ continue;
+ if (FirstIter) {
+ FirstIter = false;
+ ParentChain.emplace_back(CurFD, 1);
+ } else {
+ ++ParentChain.back().second;
+ }
+ Types.emplace_back(FieldTy, FD);
}
}
- if (SubExprs.empty())
- continue;
- CXXScopeSpec MapperIdScopeSpec;
- DeclarationNameInfo MapperId;
- if (OMPClause *NewClause = S.OpenMP().ActOnOpenMPMapClause(
- nullptr, C->getMapTypeModifiers(), C->getMapTypeModifiersLoc(),
- MapperIdScopeSpec, MapperId, C->getMapType(),
- /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
- SubExprs, OMPVarListLocTy()))
- Clauses.push_back(NewClause);
}
+ if (SubExprs.empty())
+ return nullptr;
+
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo MapperId;
+ return S.OpenMP().ActOnOpenMPMapClause(
+ nullptr, MapC->getMapTypeModifiers(), MapC->getMapTypeModifiersLoc(),
+ MapperIdScopeSpec, MapperId, MapC->getMapType(),
+ /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(), SubExprs,
+ OMPVarListLocTy());
}
namespace {
@@ -5954,30 +6535,129 @@ class TeamsLoopChecker final : public ConstStmtVisitor<TeamsLoopChecker> {
if (Child)
Visit(Child);
}
- explicit TeamsLoopChecker(Sema &SemaRef)
- : SemaRef(SemaRef), TeamsLoopCanBeParallelFor(true) {}
+ explicit TeamsLoopChecker(Sema &SemaRef)
+ : SemaRef(SemaRef), TeamsLoopCanBeParallelFor(true) {}
+
+private:
+ bool TeamsLoopCanBeParallelFor;
+};
+} // namespace
+
+static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
+ TeamsLoopChecker Checker(SemaRef);
+ Checker.Visit(AStmt);
+ return Checker.teamsLoopCanBeParallelFor();
+}
+
+static Stmt *getRawStmt(Stmt *S) {
+ while (isa<CapturedStmt>(S))
+ S = cast<CapturedStmt>(S)->getCapturedStmt();
+ return S;
+}
+
+static void
+getImplicitInfoFromClauses(Sema &SemaRef, OpenMPDirectiveKind DKind,
+ ArrayRef<OMPClause *> Clauses,
+ SemaOpenMP::VariableImplicitInfo &ImpInfo) {
+ constexpr unsigned DefaultmapKindNum =
+ SemaOpenMP::VariableImplicitInfo::DefaultmapKindNum;
+
+ // Get the original location of present modifier from Defaultmap clause.
+ SourceLocation PresentModifierLocs[DefaultmapKindNum];
+ for (OMPClause *C : Clauses) {
+ if (auto *DMC = dyn_cast<OMPDefaultmapClause>(C))
+ if (DMC->getDefaultmapModifier() == OMPC_DEFAULTMAP_MODIFIER_present)
+ PresentModifierLocs[DMC->getDefaultmapKind()] =
+ DMC->getDefaultmapModifierLoc();
+ }
+
+ for (unsigned VC = 0; VC < DefaultmapKindNum; ++VC) {
+ auto K = static_cast<OpenMPDefaultmapClauseKind>(VC);
+ std::fill_n(std::back_inserter(ImpInfo.ImplicitMapModifiersLoc[VC]),
+ ImpInfo.MapModifiers[K].size(), PresentModifierLocs[VC]);
+ }
+
+ // Mark taskgroup task_reduction descriptors as implicitly firstprivate.
+ for (OMPClause *C : Clauses) {
+ if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) {
+ for (Expr *E : IRC->taskgroup_descriptors())
+ if (E)
+ ImpInfo.addFirstprivate(E);
+ }
+ // OpenMP 5.0, 2.10.1 task Construct
+ // [detach clause]... The event-handle will be considered as if it was
+ // specified on a firstprivate clause.
+ if (auto *DC = dyn_cast<OMPDetachClause>(C))
+ ImpInfo.addFirstprivate(DC->getEventHandler());
+ }
+
+ // OpenMP 5.0 [2.19.7]
+ // If a list item appears in a reduction, lastprivate or linear
+ // clause on a combined target construct then it is treated as
+ // if it also appears in a map clause with a map-type of tofrom
+ if (SemaRef.getLangOpts().OpenMP >= 50 && DKind != OMPD_target &&
+ isOpenMPTargetExecutionDirective(DKind)) {
+ for (OMPClause *C : Clauses) {
+ if (auto *RC = dyn_cast<OMPReductionClause>(C)) {
+ for (Expr *E : RC->varlist()) {
+ if (!isa<DeclRefExpr>(E->IgnoreParenImpCasts()))
+ ImpInfo.addReductionMapping(E);
+ }
+ }
+ }
+ }
+}
-private:
- bool TeamsLoopCanBeParallelFor;
-};
-} // namespace
+static StmtResult
+createASTForUnit(Sema &SemaRef, DSAStackTy *Stack, Stmt *AStmt,
+ SourceLocation StartLoc, SourceLocation EndLoc,
+ const DeclarationNameInfo &DirName,
+ OpenMPDirectiveKind CancelRegion,
+ SemaOpenMP::VarsWithInheritedDSAType &VarsWithInheritedDSA,
+ const UnitConstruct &Unit) {
+ SemaOpenMP &S = SemaRef.OpenMP();
+ StmtResult Res;
+
+ // Some implicit clauses (firstprivate in particular) may end up assigned
+ // to a construct that does not use the variable[1]. This may cause issues
+ // later on in codegen, so filter these clauses out. Implicit private and
+ // firstprivate clauses are generated for a single variable to facilitate
+ // this filtering.
+ // [1] Clauses are assigned based on OpenMP rules that ignore variables
+ // unless they force creation of additional clauses.
+ auto isClauseForUsedVariable = [=](OMPClause *C) {
+ // Tasks have special handling of first/private variables, and they
+ // don't capture them in the AST.
+ if (isOpenMPTaskingDirective(Unit.DKind))
+ return true;
+ auto *CS = dyn_cast_or_null<CapturedStmt>(AStmt);
+ if (!CS)
+ return true;
-static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
- TeamsLoopChecker Checker(SemaRef);
- Checker.Visit(AStmt);
- return Checker.teamsLoopCanBeParallelFor();
-}
+ auto IsVarCaptured = [=](Expr *Var) {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(Var)) {
+ if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (CS->capturesVariable(VD))
+ return true;
+ }
+ }
+ return false;
+ };
-static StmtResult createASTForDirective(
- Sema &SemaRef, OpenMPDirectiveKind Kind, ArrayRef<OMPClause *> Clauses,
- Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc,
- const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion,
- SemaOpenMP::VarsWithInheritedDSAType &VarsWithInheritedDSA) {
+ if (auto *FC = dyn_cast<OMPFirstprivateClause>(C))
+ return llvm::any_of(FC->varlist(), IsVarCaptured);
- SemaOpenMP &S = SemaRef.OpenMP();
- StmtResult Res = StmtError();
+ return true;
+ };
- switch (Kind) {
+ SmallVector<OMPClause *> Clauses;
+ llvm::copy_if(Unit.Clauses, std::back_inserter(Clauses),
+ isClauseForUsedVariable);
+
+ OpenMPDirectiveKind Saved = Stack->getTopOfStack().Directive;
+ Stack->getTopOfStack().Directive = Unit.DKind;
+
+ switch (Unit.DKind) {
case OMPD_parallel:
Res = S.ActOnOpenMPParallelDirective(Clauses, AStmt, StartLoc, EndLoc);
break;
@@ -6058,43 +6738,29 @@ static StmtResult createASTForDirective(
case OMPD_taskyield:
assert(Clauses.empty() &&
"No clauses are allowed for 'omp taskyield' directive");
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp taskyield' directive");
Res = S.ActOnOpenMPTaskyieldDirective(StartLoc, EndLoc);
break;
case OMPD_error:
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp error' directive");
Res = S.ActOnOpenMPErrorDirective(Clauses, StartLoc, EndLoc);
break;
case OMPD_barrier:
assert(Clauses.empty() &&
"No clauses are allowed for 'omp barrier' directive");
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp barrier' directive");
Res = S.ActOnOpenMPBarrierDirective(StartLoc, EndLoc);
break;
case OMPD_taskwait:
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp taskwait' directive");
Res = S.ActOnOpenMPTaskwaitDirective(Clauses, StartLoc, EndLoc);
break;
case OMPD_taskgroup:
Res = S.ActOnOpenMPTaskgroupDirective(Clauses, AStmt, StartLoc, EndLoc);
break;
case OMPD_flush:
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp flush' directive");
Res = S.ActOnOpenMPFlushDirective(Clauses, StartLoc, EndLoc);
break;
case OMPD_depobj:
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp depobj' directive");
Res = S.ActOnOpenMPDepobjDirective(Clauses, StartLoc, EndLoc);
break;
case OMPD_scan:
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp scan' directive");
Res = S.ActOnOpenMPScanDirective(Clauses, StartLoc, EndLoc);
break;
case OMPD_ordered:
@@ -6120,14 +6786,10 @@ static StmtResult createASTForDirective(
case OMPD_cancellation_point:
assert(Clauses.empty() &&
"No clauses are allowed for 'omp cancellation point' directive");
- assert(AStmt == nullptr && "No associated statement allowed for 'omp "
- "cancellation point' directive");
Res =
S.ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, CancelRegion);
break;
case OMPD_cancel:
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp cancel' directive");
Res = S.ActOnOpenMPCancelDirective(Clauses, StartLoc, EndLoc, CancelRegion);
break;
case OMPD_target_data:
@@ -6244,8 +6906,6 @@ static StmtResult createASTForDirective(
Clauses, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
break;
case OMPD_interop:
- assert(AStmt == nullptr &&
- "No associated statement allowed for 'omp interop' directive");
Res = S.ActOnOpenMPInteropDirective(Clauses, StartLoc, EndLoc);
break;
case OMPD_dispatch:
@@ -6287,6 +6947,125 @@ static StmtResult createASTForDirective(
default:
llvm_unreachable("Unknown OpenMP directive");
}
+
+ Stack->getTopOfStack().Directive = Saved;
+ return Res;
+}
+
+static StmtResult createASTForDirective(
+ Sema &SemaRef, OpenMPDirectiveKind Kind, ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc,
+ const DeclarationNameInfo &DirName, OpenMPDirectiveKind CancelRegion,
+ SemaOpenMP::VarsWithInheritedDSAType &VarsWithInheritedDSA,
+ DSAStackTy *Stack) {
+ SemaOpenMP &S = SemaRef.OpenMP();
+
+ if (Kind != OMPD_ordered && AStmt != nullptr &&
+ !isOpenMPDirectiveWithStatement(Kind)) {
+ std::string Name = getOpenMPDirectiveName(Kind).str();
+ std::string Msg =
+ "No associated statement allowed for '" + Name + "' directive";
+ llvm_unreachable(Msg.data());
+ }
+ if (AStmt == nullptr && isOpenMPDirectiveWithStatement(Kind))
+ return StmtError();
+
+ for (OMPClause *C : Clauses) {
+ if (!isAllowedClauseForDirective(Kind, C->getClauseKind(),
+ S.getLangOpts().OpenMP))
+ return StmtError();
+ }
+
+ StmtResult Res =
+ isa_and_present<CapturedStmt>(AStmt) ? getRawStmt(AStmt) : AStmt;
+
+ SmallVector<CapturedStmt *> CapStmts;
+ for (auto *CS = dyn_cast_or_null<CapturedStmt>(AStmt); CS != nullptr;
+ CS = dyn_cast<CapturedStmt>(CS->getCapturedStmt()))
+ CapStmts.push_back(CS);
+
+ auto ReconstructCS = [&](CapturedStmt *CS, Stmt *T) {
+ // Regenerate given CapturedStmt with a different "body" statement.
+ //
+ // The T in
+ // CapturedStmt
+ // `-CapturedDecl
+ // `-T
+ // is stored in both CapturedStmt, and CapturedDecl. To replace T, the
+ // decl can be updated via `setBody`, but the stmt must be rebuilt.
+ CapturedDecl *CD = CS->getCapturedDecl();
+ CD->setBody(T);
+ SmallVector<CapturedStmt::Capture> Captures(CS->capture_begin(),
+ CS->capture_end());
+ SmallVector<Expr *> CaptureInits(CS->capture_init_begin(),
+ CS->capture_init_end());
+ return CapturedStmt::Create(
+ S.getASTContext(), T, CS->getCapturedRegionKind(), Captures,
+ CaptureInits, CD,
+ const_cast<RecordDecl *>(CS->getCapturedRecordDecl()));
+ };
+
+ auto ProcessPreInits = [&](StmtResult Inp, bool IsOuter) {
+ StmtResult Res = Inp;
+ SmallVector<Stmt *> Inits;
+ for (auto [C, P] : Stack->getPreInits()) {
+ OpenMPClauseKind CK = C->getClauseKind();
+ bool NeedsOuter = CK == OMPC_num_teams || CK == OMPC_thread_limit;
+ if (IsOuter == NeedsOuter)
+ Inits.push_back(P);
+ }
+ if (!Inits.empty()) {
+ Inits.push_back(Inp.get());
+ Res = CompoundStmt::Create(S.getASTContext(), Inits, FPOptionsOverride(),
+ SourceLocation(), SourceLocation());
+ }
+ return Res;
+ };
+
+ auto &UnitConstructs = Stack->getTopOfStack().UnitConstructs;
+
+ for (UnitConstruct &Unit : llvm::reverse(UnitConstructs)) {
+ SmallVector<OpenMPDirectiveKind, 4> CapRegions;
+ // "ordered" may be either block-associated or standalone. It will have
+ // an associated statement or not, respectively. Both cases are treated
+ // as legal.
+ if (Unit.DKind != OMPD_ordered || AStmt != nullptr) {
+ if (isOpenMPCapturingDirective(Unit.DKind,
+ /*OrderedIsStandalone=*/AStmt == nullptr))
+ getOpenMPCaptureRegions(CapRegions, Unit.DKind);
+ }
+
+ Stmt *AS = nullptr;
+ if (!CapRegions.empty()) {
+ size_t NumRegions = CapRegions.size();
+ assert(CapStmts.size() >= NumRegions && "Not enough captured statenents");
+
+ auto Tail =
+ MutableArrayRef<CapturedStmt *>(CapStmts).take_back(NumRegions);
+ Stmt *T = Res.get();
+ for (CapturedStmt *&CS : llvm::reverse(Tail))
+ T = CS = ReconstructCS(CS, T);
+
+ AS = CapStmts[CapStmts.size() - CapRegions.size()];
+ CapStmts.resize(CapStmts.size() - CapRegions.size());
+ } else {
+ AS = Res.get();
+ }
+
+ Res = createASTForUnit(SemaRef, Stack, AS, StartLoc, EndLoc, DirName,
+ CancelRegion, VarsWithInheritedDSA, Unit);
+
+ if (Res.isInvalid())
+ break;
+
+ // Emit pre-inits for the clauses, except num_teams and thread_limit
+ // (those must be evaluated outside of the construct, by OpenMP rules).
+ Res = ProcessPreInits(Res, /*IsOuter=*/false);
+ }
+
+ if (Res.isUsable())
+ Res = ProcessPreInits(Res, /*IsOuter=*/true);
+
return Res;
}
@@ -6295,47 +7074,13 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
assert(isOpenMPExecutableDirective(Kind) && "Unexpected directive category");
-
StmtResult Res = StmtError();
- OpenMPBindClauseKind BindKind = OMPC_BIND_unknown;
- llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
+ // Diagnose "loop bind(teams)" with "reduction".
+ OpenMPBindClauseKind BindKind = OMPC_BIND_unknown;
if (const OMPBindClause *BC =
OMPExecutableDirective::getSingleClause<OMPBindClause>(Clauses))
BindKind = BC->getBindKind();
-
- if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) {
- const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
-
- // Setting the enclosing teams or parallel construct for the loop
- // directive without bind clause.
- // [5.0:129:25-28] If the bind clause is not present on the construct and
- // the loop construct is closely nested inside a teams or parallel
- // construct, the binding region is the corresponding teams or parallel
- // region. If none of those conditions hold, the binding region is not
- // defined.
- BindKind = OMPC_BIND_thread; // Default bind(thread) if binding is unknown
- ArrayRef<OpenMPDirectiveKind> ParentLeafs =
- getLeafConstructsOrSelf(ParentDirective);
-
- if (ParentDirective == OMPD_unknown) {
- Diag(DSAStack->getDefaultDSALocation(),
- diag::err_omp_bind_required_on_loop);
- } else if (ParentLeafs.back() == OMPD_parallel) {
- BindKind = OMPC_BIND_parallel;
- } else if (ParentLeafs.back() == OMPD_teams) {
- BindKind = OMPC_BIND_teams;
- }
-
- assert(BindKind != OMPC_BIND_unknown && "Expecting BindKind");
-
- OMPClause *C =
- ActOnOpenMPBindClause(BindKind, SourceLocation(), SourceLocation(),
- SourceLocation(), SourceLocation());
- ClausesWithImplicit.push_back(C);
- }
-
- // Diagnose "loop bind(teams)" with "reduction".
if (Kind == OMPD_loop && BindKind == OMPC_BIND_teams) {
for (OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_reduction)
@@ -6358,156 +7103,48 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
VarsWithInheritedDSAType VarsWithInheritedDSA;
bool ErrorFound = false;
- ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
if (AStmt && !SemaRef.CurContext->isDependentContext() &&
- isOpenMPCapturingDirective(Kind)) {
+ isOpenMPCapturingDirective(Kind, /*OrderedIsStandalone=*/false)) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
// Check default data sharing attributes for referenced variables.
- DSAAttrChecker DSAChecker(DSAStack, SemaRef, cast<CapturedStmt>(AStmt));
- int ThisCaptureLevel = getOpenMPCaptureLevels(Kind);
- Stmt *S = AStmt;
- while (--ThisCaptureLevel >= 0)
- S = cast<CapturedStmt>(S)->getCapturedStmt();
- DSAChecker.Visit(S);
- if (!isOpenMPTargetDataManagementDirective(Kind) &&
- !isOpenMPTaskingDirective(Kind)) {
- // Visit subcaptures to generate implicit clauses for captured vars.
- auto *CS = cast<CapturedStmt>(AStmt);
- SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
- getOpenMPCaptureRegions(CaptureRegions, Kind);
- // Ignore outer tasking regions for target directives.
- if (CaptureRegions.size() > 1 && CaptureRegions.front() == OMPD_task)
- CS = cast<CapturedStmt>(CS->getCapturedStmt());
- DSAChecker.visitSubCaptures(CS);
- }
- if (DSAChecker.isErrorFound())
+ VarsWithInheritedDSA = DSAStack->getTopOfStack().VarsWithInheritedDSA;
+
+ if (DSAStack->getTopOfStack().HasDSAError)
return StmtError();
- // Generate list of implicitly defined firstprivate variables.
- VarsWithInheritedDSA = DSAChecker.getVarsWithInheritedDSA();
- VariableImplicitInfo ImpInfo = DSAChecker.getImplicitInfo();
-
- SmallVector<SourceLocation, NumberOfOMPMapClauseModifiers>
- ImplicitMapModifiersLoc[VariableImplicitInfo::DefaultmapKindNum];
- // Get the original location of present modifier from Defaultmap clause.
- SourceLocation PresentModifierLocs[VariableImplicitInfo::DefaultmapKindNum];
- for (OMPClause *C : Clauses) {
- if (auto *DMC = dyn_cast<OMPDefaultmapClause>(C))
- if (DMC->getDefaultmapModifier() == OMPC_DEFAULTMAP_MODIFIER_present)
- PresentModifierLocs[DMC->getDefaultmapKind()] =
- DMC->getDefaultmapModifierLoc();
- }
+ }
- for (OpenMPDefaultmapClauseKind K :
- llvm::enum_seq_inclusive<OpenMPDefaultmapClauseKind>(
- OpenMPDefaultmapClauseKind(), OMPC_DEFAULTMAP_unknown)) {
- std::fill_n(std::back_inserter(ImplicitMapModifiersLoc[K]),
- ImpInfo.MapModifiers[K].size(), PresentModifierLocs[K]);
- }
- // Mark taskgroup task_reduction descriptors as implicitly firstprivate.
- for (OMPClause *C : Clauses) {
- if (auto *IRC = dyn_cast<OMPInReductionClause>(C)) {
- for (Expr *E : IRC->taskgroup_descriptors())
- if (E)
- ImpInfo.Firstprivates.insert(E);
- }
- // OpenMP 5.0, 2.10.1 task Construct
- // [detach clause]... The event-handle will be considered as if it was
- // specified on a firstprivate clause.
- if (auto *DC = dyn_cast<OMPDetachClause>(C))
- ImpInfo.Firstprivates.insert(DC->getEventHandler());
- }
- if (!ImpInfo.Firstprivates.empty()) {
- if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
- ImpInfo.Firstprivates.getArrayRef(), SourceLocation(),
- SourceLocation(), SourceLocation())) {
- ClausesWithImplicit.push_back(Implicit);
- ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
- ImpInfo.Firstprivates.size();
- } else {
- ErrorFound = true;
- }
- }
- if (!ImpInfo.Privates.empty()) {
- if (OMPClause *Implicit = ActOnOpenMPPrivateClause(
- ImpInfo.Privates.getArrayRef(), SourceLocation(),
- SourceLocation(), SourceLocation())) {
- ClausesWithImplicit.push_back(Implicit);
- ErrorFound = cast<OMPPrivateClause>(Implicit)->varlist_size() !=
- ImpInfo.Privates.size();
- } else {
- ErrorFound = true;
- }
- }
- // OpenMP 5.0 [2.19.7]
- // If a list item appears in a reduction, lastprivate or linear
- // clause on a combined target construct then it is treated as
- // if it also appears in a map clause with a map-type of tofrom
- if (getLangOpts().OpenMP >= 50 && Kind != OMPD_target &&
- isOpenMPTargetExecutionDirective(Kind)) {
- SmallVector<Expr *, 4> ImplicitExprs;
- for (OMPClause *C : Clauses) {
- if (auto *RC = dyn_cast<OMPReductionClause>(C))
- for (Expr *E : RC->varlist())
- if (!isa<DeclRefExpr>(E->IgnoreParenImpCasts()))
- ImplicitExprs.emplace_back(E);
- }
- if (!ImplicitExprs.empty()) {
- ArrayRef<Expr *> Exprs = ImplicitExprs;
- CXXScopeSpec MapperIdScopeSpec;
- DeclarationNameInfo MapperId;
- if (OMPClause *Implicit = ActOnOpenMPMapClause(
- nullptr, OMPC_MAP_MODIFIER_unknown, SourceLocation(),
- MapperIdScopeSpec, MapperId, OMPC_MAP_tofrom,
- /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
- Exprs, OMPVarListLocTy(), /*NoDiagnose=*/true))
- ClausesWithImplicit.emplace_back(Implicit);
- }
- }
- for (unsigned I = 0; I < VariableImplicitInfo::DefaultmapKindNum; ++I) {
- int ClauseKindCnt = -1;
- for (unsigned J = 0; J < VariableImplicitInfo::MapKindNum; ++J) {
- ArrayRef<Expr *> ImplicitMap = ImpInfo.Mappings[I][J].getArrayRef();
- ++ClauseKindCnt;
- if (ImplicitMap.empty())
- continue;
- CXXScopeSpec MapperIdScopeSpec;
- DeclarationNameInfo MapperId;
- auto K = static_cast<OpenMPMapClauseKind>(ClauseKindCnt);
- if (OMPClause *Implicit = ActOnOpenMPMapClause(
- nullptr, ImpInfo.MapModifiers[I], ImplicitMapModifiersLoc[I],
- MapperIdScopeSpec, MapperId, K, /*IsMapTypeImplicit=*/true,
- SourceLocation(), SourceLocation(), ImplicitMap,
- OMPVarListLocTy())) {
- ClausesWithImplicit.emplace_back(Implicit);
- ErrorFound |= cast<OMPMapClause>(Implicit)->varlist_size() !=
- ImplicitMap.size();
- } else {
- ErrorFound = true;
- }
- }
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() != OMPC_reduction)
+ continue;
+ auto *RC = cast<OMPReductionClause>(C);
+ if (RC->getModifier() == OMPC_REDUCTION_task) {
+ // OpenMP 5.0, 2.19.5.4 reduction Clause.
+ // A reduction clause with the task reduction-modifier may only appear on
+ // a parallel construct, a worksharing construct or a combined or
+ // composite construct for which any of the aforementioned constructs is a
+ // constituent construct and simd or loop are not constituent constructs.
+ if (!(isOpenMPParallelDirective(Kind) ||
+ isOpenMPWorksharingDirective(Kind)) ||
+ isOpenMPSimdDirective(Kind))
+ Diag(RC->getModifierLoc(),
+ diag::err_omp_reduction_task_not_parallel_or_worksharing);
}
- // Build expressions for implicit maps of data members with 'default'
- // mappers.
- if (getLangOpts().OpenMP >= 50)
- processImplicitMapsWithDefaultMappers(SemaRef, DSAStack,
- ClausesWithImplicit);
}
if (!SemaRef.CurContext->isDependentContext()) {
- Res = createASTForDirective(SemaRef, Kind, ClausesWithImplicit, AStmt,
- StartLoc, EndLoc, DirName, CancelRegion,
- VarsWithInheritedDSA);
+ Res = createASTForDirective(SemaRef, Kind, Clauses, AStmt, StartLoc, EndLoc,
+ DirName, CancelRegion, VarsWithInheritedDSA,
+ DSAStack);
} else {
- if (getDirectiveAssociation(Kind) == Association::Loop)
- Res = ActOnOpenMPOpaqueLoopDirective(Kind, ClausesWithImplicit, AStmt,
- StartLoc, EndLoc,
- VarsWithInheritedDSA);
- else
- Res = ActOnOpenMPOpaqueBlockDirective(Kind, ClausesWithImplicit, AStmt,
- CancelRegion, DirName, StartLoc,
- EndLoc);
+ if (getDirectiveAssociation(Kind) == Association::Loop) {
+ Res = ActOnOpenMPOpaqueLoopDirective(Kind, Clauses, AStmt, StartLoc,
+ EndLoc, VarsWithInheritedDSA);
+ } else {
+ Res = ActOnOpenMPOpaqueBlockDirective(Kind, Clauses, AStmt, CancelRegion,
+ DirName, StartLoc, EndLoc);
+ }
}
ErrorFound = Res.isInvalid() || ErrorFound;
@@ -8411,7 +9048,9 @@ bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) {
static ExprResult
tryBuildCapture(Sema &SemaRef, Expr *Capture,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
- StringRef Name = ".capture_expr.") {
+ bool RefersToCapture, // = false,
+ StringRef Name = ".capture_expr.",
+ bool MakeOMPCapturedExprDecl = true) {
if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors())
return Capture;
if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects))
@@ -8421,9 +9060,11 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture,
/*AllowExplicit=*/true);
auto I = Captures.find(Capture);
if (I != Captures.end())
- return buildCapture(SemaRef, Capture, I->second, Name);
+ return buildCapture(SemaRef, Capture, I->second, RefersToCapture, Name,
+ MakeOMPCapturedExprDecl);
DeclRefExpr *Ref = nullptr;
- ExprResult Res = buildCapture(SemaRef, Capture, Ref, Name);
+ ExprResult Res = buildCapture(SemaRef, Capture, Ref, RefersToCapture, Name,
+ MakeOMPCapturedExprDecl);
Captures[Capture] = Ref;
return Res;
}
@@ -8435,7 +9076,8 @@ calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy,
bool TestIsStrictOp, bool RoundToStep,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
- ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures, ".new_step");
+ ExprResult NewStep =
+ tryBuildCapture(SemaRef, Step, Captures, /*RefersToCapture=*/false);
if (!NewStep.isUsable())
return nullptr;
llvm::APSInt LRes, SRes;
@@ -8657,10 +9299,12 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
if (!LBMaxVal.isUsable())
return nullptr;
- Expr *LBMin =
- tryBuildCapture(SemaRef, LBMinVal.get(), Captures, ".lb_min").get();
- Expr *LBMax =
- tryBuildCapture(SemaRef, LBMaxVal.get(), Captures, ".lb_max").get();
+ Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures,
+ /*RefersToCapture=*/false)
+ .get();
+ Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures,
+ /*RefersToCapture=*/false)
+ .get();
if (!LBMin || !LBMax)
return nullptr;
// LB(MinVal) < LB(MaxVal)
@@ -8668,9 +9312,9 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
if (!MinLessMaxRes.isUsable())
return nullptr;
- Expr *MinLessMax =
- tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures, ".min_less_max")
- .get();
+ Expr *MinLessMax = tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures,
+ /*RefersToCapture=*/false)
+ .get();
if (!MinLessMax)
return nullptr;
if (*TestIsLessOp) {
@@ -8743,10 +9387,12 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
if (!UBMaxVal.isUsable())
return nullptr;
- Expr *UBMin =
- tryBuildCapture(SemaRef, UBMinVal.get(), Captures, ".ub_min").get();
- Expr *UBMax =
- tryBuildCapture(SemaRef, UBMaxVal.get(), Captures, ".ub_max").get();
+ Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures,
+ /*RefersToCapture=*/false)
+ .get();
+ Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures,
+ /*RefersToCapture=*/false)
+ .get();
if (!UBMin || !UBMax)
return nullptr;
// UB(MinVal) > UB(MaxVal)
@@ -8755,7 +9401,7 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
if (!MinGreaterMaxRes.isUsable())
return nullptr;
Expr *MinGreaterMax = tryBuildCapture(SemaRef, MinGreaterMaxRes.get(),
- Captures, ".min_greater_max")
+ Captures, /*RefersToCapture=*/false)
.get();
if (!MinGreaterMax)
return nullptr;
@@ -8779,8 +9425,12 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
}
Expr *UBExpr = *TestIsLessOp ? UBVal : LBVal;
Expr *LBExpr = *TestIsLessOp ? LBVal : UBVal;
- Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures, ".upper").get();
- Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures, ".lower").get();
+ Expr *Upper =
+ tryBuildCapture(SemaRef, UBExpr, Captures, /*RefersToCapture=*/false)
+ .get();
+ Expr *Lower =
+ tryBuildCapture(SemaRef, LBExpr, Captures, /*RefersToCapture=*/false)
+ .get();
if (!Upper || !Lower)
return nullptr;
@@ -8849,10 +9499,14 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
*TestIsLessOp ? InitDependOnLC.has_value() : CondDependOnLC.has_value();
bool UBNonRect =
*TestIsLessOp ? CondDependOnLC.has_value() : InitDependOnLC.has_value();
- Expr *Lower =
- LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
- Expr *Upper =
- UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get();
+ Expr *Lower = LBNonRect ? LBExpr
+ : tryBuildCapture(SemaRef, LBExpr, Captures,
+ /*RefersToCapture=*/false)
+ .get();
+ Expr *Upper = UBNonRect ? UBExpr
+ : tryBuildCapture(SemaRef, UBExpr, Captures,
+ /*RefersToCapture=*/false)
+ .get();
if (!Upper || !Lower)
return std::make_pair(nullptr, nullptr);
@@ -8876,7 +9530,8 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures, ".new_step");
+ ExprResult NewStep =
+ tryBuildCapture(SemaRef, Step, Captures, /*RefersToCapture=*/false);
if (!NewStep.isUsable())
return std::make_pair(nullptr, nullptr);
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
@@ -8965,8 +9620,10 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
// Try to build LB <op> UB, where <op> is <, >, <=, or >=.
Sema::TentativeAnalysisScope Trap(SemaRef);
- ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures);
- ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures);
+ ExprResult NewLB =
+ tryBuildCapture(SemaRef, LB, Captures, /*RefersToCapture=*/false);
+ ExprResult NewUB =
+ tryBuildCapture(SemaRef, UB, Captures, /*RefersToCapture=*/false);
if (!NewLB.isUsable() || !NewUB.isUsable())
return nullptr;
@@ -9050,10 +9707,14 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
!SemaRef.getLangOpts().CPlusPlus)
return nullptr;
// Upper - Lower
- Expr *Upper =
- *TestIsLessOp ? Cnt : tryBuildCapture(SemaRef, LB, Captures).get();
- Expr *Lower =
- *TestIsLessOp ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
+ Expr *Upper = *TestIsLessOp ? Cnt
+ : tryBuildCapture(SemaRef, LB, Captures,
+ /*RefersToCapture=*/false)
+ .get();
+ Expr *Lower = *TestIsLessOp ? tryBuildCapture(SemaRef, LB, Captures,
+ /*RefersToCapture=*/false)
+ .get()
+ : Cnt;
if (!Upper || !Lower)
return nullptr;
@@ -9391,7 +10052,8 @@ buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
// Build 'VarRef = Start.
ExprResult NewStart = IsNonRectangularLB
? Start.get()
- : tryBuildCapture(SemaRef, Start.get(), Captures);
+ : tryBuildCapture(SemaRef, Start.get(), Captures,
+ /*RefersToCapture=*/false);
if (!NewStart.isUsable())
return ExprError();
if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
@@ -9422,7 +10084,8 @@ static ExprResult buildCounterUpdate(
ExprResult NewStep = Step;
if (Captures)
- NewStep = tryBuildCapture(SemaRef, Step.get(), *Captures);
+ NewStep = tryBuildCapture(SemaRef, Step.get(), *Captures,
+ /*RefersToCapture=*/false);
if (NewStep.isInvalid())
return ExprError();
ExprResult Update =
@@ -9438,7 +10101,8 @@ static ExprResult buildCounterUpdate(
if (!NewStart.isUsable())
return ExprError();
if (Captures && !IsNonRectangularLB)
- NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures);
+ NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures,
+ /*RefersToCapture=*/false);
if (NewStart.isInvalid())
return ExprError();
@@ -9627,6 +10291,19 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
DSAStackTy &DSA,
SemaOpenMP::VarsWithInheritedDSAType &VarsWithImplicitDSA,
OMPLoopBasedDirective::HelperExprs &Built) {
+ if (!isOpenMPLoopTransformationDirective(DKind)) {
+ // Find the innermost CapturedStmt that is not "unknown".
+ // The "unknown" capture statements don't have all the required
+ // parameters for generating loop code.
+ SmallVector<OpenMPDirectiveKind> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, DKind);
+ size_t LastIdx = CaptureRegions.size();
+ while (LastIdx && CaptureRegions[LastIdx - 1] == OMPD_unknown)
+ --LastIdx;
+ while (LastIdx-- > 1)
+ AStmt = cast<CapturedStmt>(AStmt)->getCapturedStmt();
+ }
+
unsigned NestedLoopCount = 1;
bool SupportsNonPerfectlyNested = (SemaRef.LangOpts.OpenMP >= 50) &&
!isOpenMPLoopTransformationDirective(DKind);
@@ -9673,9 +10350,10 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
unsigned NumLoops = std::max(OrderedLoopCount, NestedLoopCount);
SmallVector<LoopIterationSpace, 4> IterSpaces(NumLoops);
+ int StripCaptured = isOpenMPLoopTransformationDirective(DKind) ? 1 : -1;
if (!OMPLoopBasedDirective::doForAllLoops(
- AStmt->IgnoreContainers(!isOpenMPLoopTransformationDirective(DKind)),
- SupportsNonPerfectlyNested, NumLoops,
+ AStmt->stripContainers(StripCaptured), SupportsNonPerfectlyNested,
+ NumLoops,
[DKind, &SemaRef, &DSA, NumLoops, NestedLoopCount,
CollapseLoopCountExpr, OrderedLoopCountExpr, &VarsWithImplicitDSA,
&IterSpaces, &Captures,
@@ -9848,8 +10526,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
bool IsConstant = LastIteration.get()->isIntegerConstantExpr(SemaRef.Context);
ExprResult CalcLastIteration;
if (!IsConstant) {
- ExprResult SaveRef =
- tryBuildCapture(SemaRef, LastIteration.get(), Captures);
+ ExprResult SaveRef = tryBuildCapture(SemaRef, LastIteration.get(), Captures,
+ /*RefersToCapture=*/false);
LastIteration = SaveRef;
// Prepare SaveRef + 1.
@@ -10392,7 +11070,7 @@ StmtResult SemaOpenMP::ActOnOpenMPSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(SemaRef, OMPD_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_simd, AStmt);
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
@@ -10400,7 +11078,7 @@ StmtResult SemaOpenMP::ActOnOpenMPSimdDirective(
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_simd, getCollapseNumberExpr(Clauses), getOrderedNumberExpr(Clauses),
- CS, SemaRef, *DSAStack, VarsWithImplicitDSA, B);
+ AStmt, SemaRef, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -10446,7 +11124,7 @@ StmtResult SemaOpenMP::ActOnOpenMPForSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(SemaRef, OMPD_for_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_for_simd, AStmt);
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
@@ -10454,7 +11132,7 @@ StmtResult SemaOpenMP::ActOnOpenMPForSimdDirective(
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_for_simd, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), CS, SemaRef, *DSAStack,
+ getOrderedNumberExpr(Clauses), AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -10654,14 +11332,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsGenericLoopDirective(
if (checkGenericLoopLastprivate(SemaRef, Clauses, OMPD_teams_loop, DSAStack))
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(SemaRef, OMPD_teams_loop, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_teams_loop, AStmt);
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_teams_loop, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
- VarsWithImplicitDSA, B);
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -10687,15 +11365,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsGenericLoopDirective(
DSAStack))
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_target_teams_loop, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_teams_loop, AStmt);
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_teams_loop, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
- VarsWithImplicitDSA, B);
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -10720,15 +11397,14 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelGenericLoopDirective(
DSAStack))
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_parallel_loop, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_parallel_loop, AStmt);
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_parallel_loop, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
- VarsWithImplicitDSA, B);
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -10752,15 +11428,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelGenericLoopDirective(
DSAStack))
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_target_parallel_loop, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_parallel_loop, AStmt);
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse', it will define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_parallel_loop, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
- VarsWithImplicitDSA, B);
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -10916,15 +11591,14 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelForSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_parallel_for_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_parallel_for_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_parallel_for_simd, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), CS, SemaRef, *DSAStack,
+ getOrderedNumberExpr(Clauses), AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13017,15 +13691,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_target_parallel_for, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_parallel_for, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), CS, SemaRef, *DSAStack,
+ getOrderedNumberExpr(Clauses), AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13310,8 +13983,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTaskLoopSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_taskloop_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_taskloop_simd, AStmt);
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
@@ -13319,8 +13991,8 @@ StmtResult SemaOpenMP::ActOnOpenMPTaskLoopSimdDirective(
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_taskloop_simd, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
- VarsWithImplicitDSA, B);
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13427,8 +14099,7 @@ StmtResult SemaOpenMP::ActOnOpenMPMasterTaskLoopSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_master_taskloop_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_master_taskloop_simd, AStmt);
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
@@ -13436,8 +14107,8 @@ StmtResult SemaOpenMP::ActOnOpenMPMasterTaskLoopSimdDirective(
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_master_taskloop_simd, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
- VarsWithImplicitDSA, B);
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13468,8 +14139,7 @@ StmtResult SemaOpenMP::ActOnOpenMPMaskedTaskLoopSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_masked_taskloop_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_masked_taskloop_simd, AStmt);
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
OMPLoopBasedDirective::HelperExprs B;
@@ -13477,8 +14147,8 @@ StmtResult SemaOpenMP::ActOnOpenMPMaskedTaskLoopSimdDirective(
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_masked_taskloop_simd, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
- VarsWithImplicitDSA, B);
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef,
+ *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13509,15 +14179,14 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_parallel_master_taskloop, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_parallel_master_taskloop, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_parallel_master_taskloop, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13548,15 +14217,14 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_parallel_masked_taskloop, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_parallel_masked_taskloop, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_parallel_masked_taskloop, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13587,15 +14255,14 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
- SemaRef, OMPD_parallel_master_taskloop_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_parallel_master_taskloop_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_parallel_master_taskloop_simd, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13627,15 +14294,14 @@ StmtResult SemaOpenMP::ActOnOpenMPParallelMaskedTaskLoopSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
- SemaRef, OMPD_parallel_masked_taskloop_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_parallel_masked_taskloop_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_parallel_masked_taskloop_simd, getCollapseNumberExpr(Clauses),
- /*OrderedLoopCountExpr=*/nullptr, CS, SemaRef, *DSAStack,
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13693,15 +14359,14 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_distribute_parallel_for, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_distribute_parallel_for, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_distribute_parallel_for, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13720,15 +14385,14 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeParallelForSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
- SemaRef, OMPD_distribute_parallel_for_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_distribute_parallel_for_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13749,15 +14413,14 @@ StmtResult SemaOpenMP::ActOnOpenMPDistributeSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_distribute_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_distribute_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_distribute_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS,
+ nullptr /*ordered not a clause on distribute*/, AStmt,
SemaRef, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13778,15 +14441,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetParallelForSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_target_parallel_for_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_parallel_for_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' or 'ordered' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_parallel_for_simd, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), CS, SemaRef, *DSAStack,
+ getOrderedNumberExpr(Clauses), AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13807,14 +14469,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(SemaRef, OMPD_target_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will define the
// nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_simd, getCollapseNumberExpr(Clauses),
- getOrderedNumberExpr(Clauses), CS, SemaRef, *DSAStack,
+ getOrderedNumberExpr(Clauses), AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13835,15 +14497,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_teams_distribute, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_teams_distribute, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_teams_distribute, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS,
+ nullptr /*ordered not a clause on distribute*/, AStmt,
SemaRef, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13863,15 +14524,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_teams_distribute_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_teams_distribute_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_teams_distribute_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13894,15 +14554,15 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForSimdDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
- SemaRef, OMPD_teams_distribute_parallel_for_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_teams_distribute_parallel_for_simd,
+ AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_teams_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -13925,15 +14585,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTeamsDistributeParallelForDirective(
if (!AStmt)
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
- SemaRef, OMPD_teams_distribute_parallel_for, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_teams_distribute_parallel_for, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
@@ -13996,15 +14655,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeDirective(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
- CapturedStmt *CS =
- setBranchProtectedScope(SemaRef, OMPD_target_teams_distribute, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_teams_distribute, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_teams_distribute, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -14028,15 +14686,15 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
- SemaRef, OMPD_target_teams_distribute_parallel_for, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_teams_distribute_parallel_for,
+ AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -14061,7 +14719,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
+ setBranchProtectedScope(
SemaRef, OMPD_target_teams_distribute_parallel_for_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
@@ -14070,7 +14728,7 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
unsigned NestedLoopCount =
checkOpenMPLoop(OMPD_target_teams_distribute_parallel_for_simd,
getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS,
+ nullptr /*ordered not a clause on distribute*/, AStmt,
SemaRef, *DSAStack, VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -14097,15 +14755,14 @@ StmtResult SemaOpenMP::ActOnOpenMPTargetTeamsDistributeSimdDirective(
*this, Clauses, /*MaxNum=*/1, diag::err_omp_multi_expr_not_allowed))
return StmtError();
- CapturedStmt *CS = setBranchProtectedScope(
- SemaRef, OMPD_target_teams_distribute_simd, AStmt);
+ setBranchProtectedScope(SemaRef, OMPD_target_teams_distribute_simd, AStmt);
OMPLoopBasedDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
unsigned NestedLoopCount = checkOpenMPLoop(
OMPD_target_teams_distribute_simd, getCollapseNumberExpr(Clauses),
- nullptr /*ordered not a clause on distribute*/, CS, SemaRef, *DSAStack,
+ nullptr /*ordered not a clause on distribute*/, AStmt, SemaRef, *DSAStack,
VarsWithImplicitDSA, B);
if (NestedLoopCount == 0)
return StmtError();
@@ -15263,16 +15920,22 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, unsigned OpenMPVersion,
OpenMPDirectiveKind NameModifier = OMPD_unknown) {
+ // DKind may be a compound directive. This function is called
+ // from ActOnXyxClause, which are called before directive splitting.
assert(isAllowedClauseForDirective(DKind, CKind, OpenMPVersion) &&
"Invalid directive with CKind-clause");
- // Invalid modifier will be diagnosed separately, just return OMPD_unknown.
- if (NameModifier != OMPD_unknown &&
- !isAllowedClauseForDirective(NameModifier, CKind, OpenMPVersion))
- return OMPD_unknown;
-
ArrayRef<OpenMPDirectiveKind> Leafs = getLeafConstructsOrSelf(DKind);
+ // Invalid modifier will be diagnosed separately, just return OMPD_unknown.
+ if (NameModifier != OMPD_unknown) {
+ if (!isAllowedClauseForDirective(NameModifier, CKind, OpenMPVersion))
+ return OMPD_unknown;
+ if (!llvm::is_contained(Leafs, NameModifier))
+ return OMPD_unknown;
+ DKind = NameModifier;
+ }
+
// [5.2:341:24-30]
// If the clauses have expressions on them, such as for various clauses where
// the argument of the clause is an expression, or lower-bound, length, or
@@ -15329,47 +15992,42 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
break;
}
- // If none of the special cases above applied, and DKind is a capturing
- // directive, find the innermost enclosing leaf construct that allows the
- // clause, and returns the corresponding capture region.
+ if (!isOpenMPCapturingDirective(DKind, /*OrderedIsStandalone=*/false))
+ return OMPD_unknown;
- auto GetEnclosingRegion = [&](int EndIdx, OpenMPClauseKind Clause) {
- // Find the index in "Leafs" of the last leaf that allows the given
- // clause. The search will only include indexes [0, EndIdx).
- // EndIdx may be set to the index of the NameModifier, if present.
- int InnermostIdx = [&]() {
- for (int I = EndIdx - 1; I >= 0; --I) {
- if (isAllowedClauseForDirective(Leafs[I], Clause, OpenMPVersion))
- return I;
- }
- return -1;
- }();
+ // Find the outermost leaf that allows the clause.
+ size_t Outermost = Leafs.size();
- // Find the nearest enclosing capture region.
- SmallVector<OpenMPDirectiveKind, 2> Regions;
- for (int I = InnermostIdx - 1; I >= 0; --I) {
- if (!isOpenMPCapturingDirective(Leafs[I]))
- continue;
- Regions.clear();
- getOpenMPCaptureRegions(Regions, Leafs[I]);
- if (Regions[0] != OMPD_unknown)
- return Regions.back();
- }
+ if (NameModifier == OMPD_unknown) {
+ auto F = llvm::find_if(Leafs, [=](OpenMPDirectiveKind Leaf) {
+ return isAllowedClauseForDirective(Leaf, CKind, OpenMPVersion);
+ });
+ assert(F != Leafs.end() && "No leafs allow the clause");
+ Outermost = &*F - &Leafs.front();
+ } else {
+ auto F = llvm::find_if(
+ Leafs, [=](OpenMPDirectiveKind Leaf) { return Leaf == NameModifier; });
+ assert(F != Leafs.end() && "Could not find name modifier");
+ Outermost = &*F - &Leafs.front();
+ }
+ if (Outermost == 0) {
+ // The capturing region is not a part of this directive.
return OMPD_unknown;
- };
-
- if (isOpenMPCapturingDirective(DKind)) {
- auto GetLeafIndex = [&](OpenMPDirectiveKind Dir) {
- for (int I = 0, E = Leafs.size(); I != E; ++I) {
- if (Leafs[I] == Dir)
- return I + 1;
- }
- return 0;
- };
+ }
- int End = NameModifier == OMPD_unknown ? Leafs.size()
- : GetLeafIndex(NameModifier);
- return GetEnclosingRegion(End, CKind);
+ // Search outwards for the first capturing region that is not
+ // OMPD_unknown. It may correspond to a different leaf.
+ for (size_t LeafIdx = Outermost; LeafIdx > 0; --LeafIdx) {
+ OpenMPDirectiveKind Leaf = Leafs[LeafIdx - 1];
+ if (!isOpenMPCapturingDirective(Leaf, /*OrderedIsStandalone=*/false))
+ continue;
+ SmallVector<OpenMPDirectiveKind, 2> Regions;
+ getOpenMPCaptureRegions(Regions, Leaf);
+ auto F =
+ std::find_if(Regions.rbegin(), Regions.rend(),
+ [](OpenMPDirectiveKind R) { return R != OMPD_unknown; });
+ if (F != Regions.rend())
+ return *F;
}
return OMPD_unknown;
@@ -15394,13 +16052,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPIfClause(
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
CaptureRegion = getOpenMPCaptureRegionForClause(
DKind, OMPC_if, getLangOpts().OpenMP, NameModifier);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
}
return new (getASTContext())
@@ -15427,13 +16078,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPFinalClause(Expr *Condition,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final,
getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
}
return new (getASTContext()) OMPFinalClause(
@@ -15516,12 +16160,16 @@ isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
return true;
*CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, CKind, SemaRef.LangOpts.OpenMP);
- if (*CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- *HelperValStmt = buildPreInits(SemaRef.Context, Captures);
+ if (CKind == OMPC_num_teams || CKind == OMPC_thread_limit) {
+ if (*CaptureRegion != OMPD_unknown &&
+ !SemaRef.CurContext->isDependentContext()) {
+ ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures,
+ /*RefersToCapture=*/true)
+ .get();
+ *HelperValStmt = buildPreInits(SemaRef.Context, Captures);
+ }
}
}
return true;
@@ -15543,13 +16191,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumThreadsClause(Expr *NumThreads,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
DKind, OMPC_num_threads, getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
return new (getASTContext()) OMPNumThreadsClause(
ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
@@ -16409,10 +17050,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPScheduleClause(
DSAStack->getCurrentDirective(), OMPC_schedule,
getLangOpts().OpenMP) != OMPD_unknown &&
!SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
}
}
}
@@ -16915,13 +17552,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPNovariantsClause(Expr *Condition,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_novariants,
getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
}
return new (getASTContext()) OMPNovariantsClause(
@@ -16947,13 +17577,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPNocontextClause(Expr *Condition,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_nocontext,
getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
}
return new (getASTContext()) OMPNocontextClause(
@@ -16970,13 +17593,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPFilterClause(Expr *ThreadID,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_filter, getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
return new (getASTContext()) OMPFilterClause(
ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
@@ -19063,14 +19679,22 @@ OMPClause *SemaOpenMP::ActOnOpenMPReductionClause(
// worksharing-loop construct, a worksharing-loop SIMD construct, a simd
// construct, a parallel worksharing-loop construct or a parallel
// worksharing-loop SIMD construct.
- if (Modifier == OMPC_REDUCTION_inscan &&
- (DSAStack->getCurrentDirective() != OMPD_for &&
- DSAStack->getCurrentDirective() != OMPD_for_simd &&
- DSAStack->getCurrentDirective() != OMPD_simd &&
- DSAStack->getCurrentDirective() != OMPD_parallel_for &&
- DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) {
- Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction);
- return nullptr;
+ // [5.2:136:1-4] A reduction clause with the inscan reduction-modifier may
+ // only appear on a worksharing-loop construct, a simd construct or a
+ // combined or composite construct for which any of the aforementioned
+ // constructs is a constituent construct and distribute is not a constituent
+ // construct.
+ if (Modifier == OMPC_REDUCTION_inscan) {
+ SmallVector<OpenMPDirectiveKind, 4> LeafOrComposite;
+ ArrayRef<OpenMPDirectiveKind> CurrentLOC = getLeafOrCompositeConstructs(
+ DSAStack->getCurrentDirective(), LeafOrComposite);
+ bool Valid = llvm::any_of(CurrentLOC, [](OpenMPDirectiveKind DK) {
+ return llvm::is_contained({OMPD_for, OMPD_simd, OMPD_for_simd}, DK);
+ });
+ if (!Valid) {
+ Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction);
+ return nullptr;
+ }
}
ReductionData RD(VarList.size(), Modifier);
@@ -20138,13 +20762,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPDeviceClause(
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion =
getOpenMPCaptureRegionForClause(DKind, OMPC_device, getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
return new (getASTContext())
OMPDeviceClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc,
@@ -21962,9 +22579,11 @@ SemaOpenMP::DeclGroupPtrTy SemaOpenMP::ActOnOpenMPDeclareMapperDirective(
// Build expressions for implicit maps of data members with 'default'
// mappers.
SmallVector<OMPClause *, 4> ClausesWithImplicit(Clauses);
- if (getLangOpts().OpenMP >= 50)
- processImplicitMapsWithDefaultMappers(SemaRef, DSAStack,
- ClausesWithImplicit);
+ for (OMPClause *C : Clauses) {
+ OMPClause *DM = processImplicitMapWithDefaultMappers(SemaRef, DSAStack, C);
+ if (DM)
+ ClausesWithImplicit.push_back(DM);
+ }
auto *DMD = OMPDeclareMapperDecl::Create(getASTContext(), DC, StartLoc, Name,
MapperType, VN, ClausesWithImplicit,
PrevDMD);
@@ -22052,13 +22671,19 @@ OMPClause *SemaOpenMP::ActOnOpenMPNumTeamsClause(ArrayRef<Expr *> VarList,
SmallVector<Expr *, 3> Vars;
for (Expr *ValExpr : VarList) {
ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
+ ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures,
+ /*RefersToCapture=*/true, ".nt",
+ /*MakeOMPCapturedExprDecl=*/false)
+ .get();
Vars.push_back(ValExpr);
}
- Stmt *PreInit = buildPreInits(getASTContext(), Captures);
- return OMPNumTeamsClause::Create(getASTContext(), CaptureRegion, StartLoc,
- LParenLoc, EndLoc, Vars, PreInit);
+ OMPClause *Clause =
+ OMPNumTeamsClause::Create(getASTContext(), CaptureRegion, StartLoc,
+ LParenLoc, EndLoc, Vars, /*PreInit=*/nullptr);
+ if (Stmt *PreInit = buildPreInits(getASTContext(), Captures))
+ DSAStack->addPreInit(Clause, PreInit);
+ return Clause;
}
OMPClause *SemaOpenMP::ActOnOpenMPThreadLimitClause(ArrayRef<Expr *> VarList,
@@ -22088,13 +22713,19 @@ OMPClause *SemaOpenMP::ActOnOpenMPThreadLimitClause(ArrayRef<Expr *> VarList,
SmallVector<Expr *, 3> Vars;
for (Expr *ValExpr : VarList) {
ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
+ ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures,
+ /*RefersToCapture=*/true, ".tl",
+ /*MakeOMPCapturedExprDecl=*/false)
+ .get();
Vars.push_back(ValExpr);
}
- Stmt *PreInit = buildPreInits(getASTContext(), Captures);
- return OMPThreadLimitClause::Create(getASTContext(), CaptureRegion, StartLoc,
- LParenLoc, EndLoc, Vars, PreInit);
+ OMPClause *Clause = OMPThreadLimitClause::Create(
+ getASTContext(), CaptureRegion, StartLoc, LParenLoc, EndLoc, Vars,
+ /*PreInit=*/nullptr);
+ if (Stmt *PreInit = buildPreInits(getASTContext(), Captures))
+ DSAStack->addPreInit(Clause, PreInit);
+ return Clause;
}
OMPClause *SemaOpenMP::ActOnOpenMPPriorityClause(Expr *Priority,
@@ -22301,14 +22932,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPDistScheduleClause(
<< "dist_schedule" << ChunkSize->getSourceRange();
return nullptr;
}
- } else if (getOpenMPCaptureRegionForClause(
- DSAStack->getCurrentDirective(), OMPC_dist_schedule,
- getLangOpts().OpenMP) != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
}
}
}
@@ -23219,22 +23842,10 @@ StmtResult SemaOpenMP::ActOnOpenMPOpaqueBlockDirective(
OpenMPDirectiveKind DKind, ArrayRef<OMPClause *> Clauses, Stmt *AStmt,
OpenMPDirectiveKind CancelRegion, const DeclarationNameInfo &DirName,
SourceLocation StartLoc, SourceLocation EndLoc) {
- bool NeedsStmt = false;
- if (DKind == OMPD_section || DKind == OMPD_target_enter_data ||
- DKind == OMPD_target_exit_data || DKind == OMPD_target_update) {
- // The association of these in the spec is either "none" or "separating",
- // but they do have an associated statement in clang.
- NeedsStmt = true;
- } else if (DKind != OMPD_ordered) {
- // "ordered" has two versions, one with and one without a statement.
- Association Assoc = getDirectiveAssociation(DKind);
- NeedsStmt = Assoc != Association::None && Assoc != Association::Separating;
- }
-
- if (!AStmt && NeedsStmt)
+ if (!AStmt && isOpenMPDirectiveWithStatement(DKind))
return StmtError();
- if (AStmt && isOpenMPCapturingDirective(DKind))
+ if (AStmt && isOpenMPCapturingDirective(DKind, /*OrderedIsStandalone=*/false))
setBranchProtectedScope(SemaRef, DKind, AStmt);
// "scan" is the only executable, non-loop-associated directive so far
@@ -23247,7 +23858,7 @@ StmtResult SemaOpenMP::ActOnOpenMPOpaqueBlockDirective(
}
Expr *ReductionRef = nullptr;
- assert(!isOpenMPSimdDirective(DKind) && "Unexpected loop directive");
+ assert(!isOpenMPLoopDirective(DKind) && "Unexpected loop directive");
if (DKind == OMPD_taskgroup || isOpenMPParallelDirective(DKind) ||
isOpenMPWorksharingDirective(DKind))
ReductionRef = DSAStack->getTaskgroupReductionRef();
@@ -23291,12 +23902,13 @@ StmtResult SemaOpenMP::ActOnOpenMPOpaqueLoopDirective(
CapturedStmt *CS = [&]() {
switch (DKind) {
+ default:
+ setBranchProtectedScope(SemaRef, DKind, AStmt);
+ LLVM_FALLTHROUGH;
case OMPD_distribute:
case OMPD_for:
case OMPD_taskloop:
return cast<CapturedStmt>(AStmt);
- default:
- return setBranchProtectedScope(SemaRef, DKind, AStmt);
}
}();
@@ -23658,13 +24270,6 @@ OMPClause *SemaOpenMP::ActOnOpenMPXDynCGroupMemClause(Expr *Size,
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
OpenMPDirectiveKind CaptureRegion = getOpenMPCaptureRegionForClause(
DKind, OMPC_ompx_dyn_cgroup_mem, getLangOpts().OpenMP);
- if (CaptureRegion != OMPD_unknown &&
- !SemaRef.CurContext->isDependentContext()) {
- ValExpr = SemaRef.MakeFullExpr(ValExpr).get();
- llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- ValExpr = tryBuildCapture(SemaRef, ValExpr, Captures).get();
- HelperValStmt = buildPreInits(getASTContext(), Captures);
- }
return new (getASTContext()) OMPXDynCGroupMemClause(
ValExpr, HelperValStmt, CaptureRegion, StartLoc, LParenLoc, EndLoc);
@@ -24349,5 +24954,90 @@ void SemaOpenMP::handleOMPAssumeAttr(Decl *D, const ParsedAttr &AL) {
D->addAttr(::new (getASTContext()) OMPAssumeAttr(getASTContext(), AL, Str));
}
+static SmallVector<Expr *> getVarList(const ext::ObjectList &Refs) {
+ SmallVector<Expr *> Vars;
+ llvm::transform(Refs, std::back_inserter(Vars), [](const ext::Object &Obj) {
+ return const_cast<Expr *>(Obj.ref());
+ });
+ return Vars;
+}
+
+static OMPClause *
+createImplicitClause(Sema &SemaRef, OpenMPDirectiveKind LeafKind,
+ DSAStackTy *Stack,
+ const SemaOpenMP::VariableImplicitInfo &ImpInfo,
+ const omp::Clause &ExtClause) {
+
+ SemaOpenMP &S = SemaRef.OpenMP();
+ SourceLocation LocNone;
+ OMPClause *C = nullptr;
+
+ OpenMPDirectiveKind Save = Stack->getTopOfStack().Directive;
+ Stack->getTopOfStack().Directive = LeafKind;
+
+ switch (ExtClause.id) {
+ case OMPC_bind: {
+ auto V = std::get<ext::clause::Bind>(ExtClause.u);
+ C = S.ActOnOpenMPBindClause(ext::vnoc(V.v), LocNone, LocNone, LocNone,
+ LocNone);
+ break;
+ }
+ case OMPC_firstprivate: {
+ auto V = std::get<ext::clause::Firstprivate>(ExtClause.u);
+ C = S.ActOnOpenMPFirstprivateClause(getVarList(V.v), LocNone, LocNone,
+ LocNone);
+ break;
+ }
+ case OMPC_if: {
+ auto V = std::get<ext::clause::If>(ExtClause.u);
+ using DirectiveNameModifier = omp::clause::If::DirectiveNameModifier;
+ auto MaybeMod = std::get<std::optional<DirectiveNameModifier>>(V.t);
+ OpenMPDirectiveKind Mod = MaybeMod ? *MaybeMod : OMPD_unknown;
+ const Expr *IfExpr = std::get<omp::clause::If::IfExpression>(V.t);
+ C = S.ActOnOpenMPIfClause(Mod, const_cast<Expr *>(IfExpr), LocNone, LocNone,
+ LocNone, LocNone, LocNone);
+ break;
+ }
+ case OMPC_map: {
+ assert(ExtClause.tag.getFlags() == ExtClause.tag.Simple ||
+ ExtClause.tag.getFlags() == ExtClause.tag.Mapping);
+ auto V = std::get<omp::clause::Map>(ExtClause.u);
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo MapperId;
+
+ auto &Locators = std::get<omp::clause::Map::LocatorList>(V.t);
+ if (ExtClause.tag.getFlags() == ExtClause.tag.Simple) {
+ C = S.ActOnOpenMPMapClause(nullptr, OMPC_MAP_MODIFIER_unknown, LocNone,
+ MapperIdScopeSpec, MapperId, OMPC_MAP_tofrom,
+ /*IsMapTypeImplicit=*/true, LocNone, LocNone,
+ getVarList(Locators), OMPVarListLocTy(),
+ /*NoDiagnose=*/true);
+ } else if (ExtClause.tag.getFlags() == ExtClause.tag.Mapping) {
+ auto [I, J] = ExtClause.tag.getMapKinds();
+ auto MapType = static_cast<OpenMPMapClauseKind>(J);
+
+ C = S.ActOnOpenMPMapClause(
+ nullptr, ImpInfo.MapModifiers[I], ImpInfo.ImplicitMapModifiersLoc[I],
+ MapperIdScopeSpec, MapperId, MapType, /*IsMapTypeImplicit=*/true,
+ LocNone, LocNone, getVarList(Locators), OMPVarListLocTy());
+ }
+ break;
+ }
+ case OMPC_private: {
+ auto V = std::get<ext::clause::Private>(ExtClause.u);
+ C = S.ActOnOpenMPPrivateClause(getVarList(V.v), LocNone, LocNone, LocNone);
+ break;
+ }
+ default:
+ std::string msg =
+ "Unhandled clause: " + getOpenMPClauseName(ExtClause.id).str();
+ llvm_unreachable(msg.c_str());
+ break;
+ }
+
+ Stack->getTopOfStack().Directive = Save;
+ return C;
+}
+
SemaOpenMP::SemaOpenMP(Sema &S)
: SemaBase(S), VarDataSharingAttributesStack(nullptr) {}
diff --git a/clang/lib/Sema/SemaOpenMPExt.cpp b/clang/lib/Sema/SemaOpenMPExt.cpp
new file mode 100644
index 00000000000000..524ca50ffe184a
--- /dev/null
+++ b/clang/lib/Sema/SemaOpenMPExt.cpp
@@ -0,0 +1,1547 @@
+#include "SemaOpenMPExt.h"
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprOpenMP.h"
+#include "clang/AST/OpenMPClause.h"
+#include "clang/AST/Type.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Frontend/OpenMP/ClauseT.h"
+#include "llvm/Frontend/OpenMP/ConstructDecompositionT.h"
+
+#include <iterator>
+#include <list>
+#include <memory>
+#include <optional>
+#include <type_traits>
+#include <utility>
+
+using namespace clang;
+
+#define MAKE_EMPTY_CLASS(cls, from_cls) \
+ cls make(const from_cls &) { \
+ static_assert(cls::EmptyTrait::value); \
+ return cls{}; \
+ } \
+ [[maybe_unused]] extern int xyzzy_semicolon_absorber
+
+#define MS(x, y) CLAUSET_SCOPED_ENUM_MEMBER_CONVERT(x, y)
+#define MU(x, y) CLAUSET_UNSCOPED_ENUM_MEMBER_CONVERT(x, y)
+
+namespace ext {
+std::optional<clause::Default::DataSharingAttribute>
+conv(llvm::omp::DefaultKind T) {
+ // OMP_DEFAULT_unknown -> std::nullopt
+ using FromTy = llvm::omp::DefaultKind;
+ using ToTy = clause::Default::DataSharingAttribute;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::OMP_DEFAULT_firstprivate, ToTy::Firstprivate},
+ {FromTy::OMP_DEFAULT_none, ToTy::None},
+ {FromTy::OMP_DEFAULT_private, ToTy::Private},
+ {FromTy::OMP_DEFAULT_shared, ToTy::Shared},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::ProcBind::AffinityPolicy>
+conv(llvm::omp::ProcBindKind T) {
+ // OMP_PROC_BIND_default -> assert
+ // OMP_PROC_BIND_unknown -> std::nullopt
+ using FromTy = llvm::omp::ProcBindKind;
+ using ToTy = clause::ProcBind::AffinityPolicy;
+
+ assert(T != FromTy::OMP_PROC_BIND_default && "Unexpected kind");
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::OMP_PROC_BIND_close, ToTy::Close},
+ {FromTy::OMP_PROC_BIND_master, ToTy::Master},
+ {FromTy::OMP_PROC_BIND_primary, ToTy::Primary},
+ {FromTy::OMP_PROC_BIND_spread, ToTy::Spread},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::At::ActionTime> conv(OpenMPAtClauseKind T) {
+ // OMPC_AT_unknown -> std::nullopt
+ using FromTy = OpenMPAtClauseKind;
+ using ToTy = clause::At::ActionTime;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_AT_compilation, ToTy::Compilation},
+ {OMPC_AT_execution, ToTy::Execution},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<MemoryOrder> conv(OpenMPAtomicDefaultMemOrderClauseKind T) {
+ // OMPC_ATOMIC_DEFAULT_MEM_ORDER_unknown -> std::nullopt
+ using FromTy = OpenMPAtomicDefaultMemOrderClauseKind;
+ using ToTy = MemoryOrder;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_ATOMIC_DEFAULT_MEM_ORDER_acq_rel, ToTy::AcqRel},
+ {OMPC_ATOMIC_DEFAULT_MEM_ORDER_relaxed, ToTy::Relaxed},
+ {OMPC_ATOMIC_DEFAULT_MEM_ORDER_seq_cst, ToTy::SeqCst},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Bind::Binding> conv(OpenMPBindClauseKind T) {
+ // OMPC_BIND_unknown -> std::nullopt
+ using FromTy = OpenMPBindClauseKind;
+ using ToTy = clause::Bind::Binding;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_BIND_parallel, ToTy::Parallel},
+ {OMPC_BIND_teams, ToTy::Teams},
+ {OMPC_BIND_thread, ToTy::Thread},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Defaultmap::VariableCategory>
+conv(OpenMPDefaultmapClauseKind T) {
+ // OMPC_DEFAULTMAP_all -> assert
+ // OMPC_DEFAULTMAP_unknown -> std::nullopt
+ using FromTy = OpenMPDefaultmapClauseKind;
+ using ToTy = clause::Defaultmap::VariableCategory;
+ assert(T != OMPC_DEFAULTMAP_all && "Unexpected kind");
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_DEFAULTMAP_aggregate, ToTy::Aggregate},
+ {OMPC_DEFAULTMAP_pointer, ToTy::Pointer},
+ {OMPC_DEFAULTMAP_scalar, ToTy::Scalar},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Defaultmap::ImplicitBehavior>
+conv(OpenMPDefaultmapClauseModifier T) {
+ // OMPC_DEFAULTMAP_MODIFIER_unknown -> std::nullopt
+ // OMPC_DEFAULTMAP_MODIFIER_last -> std::nullopt
+ using FromTy = OpenMPDefaultmapClauseModifier;
+ using ToTy = clause::Defaultmap::ImplicitBehavior;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_DEFAULTMAP_MODIFIER_alloc, ToTy::Alloc},
+ {OMPC_DEFAULTMAP_MODIFIER_default, ToTy::Default},
+ {OMPC_DEFAULTMAP_MODIFIER_firstprivate, ToTy::Firstprivate},
+ {OMPC_DEFAULTMAP_MODIFIER_from, ToTy::From},
+ {OMPC_DEFAULTMAP_MODIFIER_none, ToTy::None},
+ {OMPC_DEFAULTMAP_MODIFIER_present, ToTy::Present},
+ {OMPC_DEFAULTMAP_MODIFIER_to, ToTy::To},
+ {OMPC_DEFAULTMAP_MODIFIER_tofrom, ToTy::Tofrom},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Device::DeviceModifier>
+conv(OpenMPDeviceClauseModifier T) {
+ // OMPC_DEVICE_unknown -> std::nullopt
+ using FromTy = OpenMPDeviceClauseModifier;
+ using ToTy = clause::Device::DeviceModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_DEVICE_ancestor, ToTy::Ancestor},
+ {OMPC_DEVICE_device_num, ToTy::DeviceNum},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::DistSchedule::Kind> conv(OpenMPDistScheduleClauseKind T) {
+ // OMPC_DIST_SCHEDULE_unknown -> std::nullopt
+ using FromTy = OpenMPDistScheduleClauseKind;
+ using ToTy = clause::DistSchedule::Kind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_DIST_SCHEDULE_static, ToTy::Static},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Grainsize::Prescriptiveness>
+conv(OpenMPGrainsizeClauseModifier T) {
+ // OMPC_GRAINSIZE_unknown -> std::nullopt
+ using FromTy = OpenMPGrainsizeClauseModifier;
+ using ToTy = clause::Grainsize::Prescriptiveness;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_GRAINSIZE_strict, ToTy::Strict},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Lastprivate::LastprivateModifier>
+conv(OpenMPLastprivateModifier T) {
+ // OMPC_LASTPRIVATE_unknown -> std::nullopt
+ using FromTy = OpenMPLastprivateModifier;
+ using ToTy = clause::Lastprivate::LastprivateModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_LASTPRIVATE_conditional, ToTy::Conditional},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Linear::LinearModifier> conv(OpenMPLinearClauseKind T) {
+ // OMPC_LINEAR_step -> assert
+ // OMPC_LINEAR_unknown -> std::nullopt
+ using FromTy = OpenMPLinearClauseKind;
+ using ToTy = clause::Linear::LinearModifier;
+ assert(T != OMPC_LINEAR_step && "Unexpected kind");
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_LINEAR_ref, ToTy::Ref},
+ {OMPC_LINEAR_uval, ToTy::Uval},
+ {OMPC_LINEAR_val, ToTy::Val},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Map::MapType> conv(OpenMPMapClauseKind T) {
+ // OMPC_MAP_unknown -> std::nullopt
+ using FromTy = OpenMPMapClauseKind;
+ using ToTy = clause::Map::MapType;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_MAP_alloc, ToTy::Alloc}, {OMPC_MAP_to, ToTy::To},
+ {OMPC_MAP_from, ToTy::From}, {OMPC_MAP_tofrom, ToTy::Tofrom},
+ {OMPC_MAP_delete, ToTy::Delete}, {OMPC_MAP_release, ToTy::Release},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Map::MapTypeModifier> conv(OpenMPMapModifierKind T) {
+ // OMPC_MAP_MODIFIER_last -> std::nullopt
+ // OMPC_MAP_MODIFIER_unknown -> std::nullopt
+ using FromTy = OpenMPMapModifierKind;
+ using ToTy = clause::Map::MapTypeModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_MAP_MODIFIER_always, ToTy::Always},
+ {OMPC_MAP_MODIFIER_close, ToTy::Close},
+ {OMPC_MAP_MODIFIER_present, ToTy::Present},
+ {OMPC_MAP_MODIFIER_ompx_hold, ToTy::OmpxHold},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::NumTasks::Prescriptiveness>
+conv(OpenMPNumTasksClauseModifier T) {
+ // OMPC_NUMTASKS_unknown -> std::nullopt
+ using FromTy = OpenMPNumTasksClauseModifier;
+ using ToTy = clause::NumTasks::Prescriptiveness;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_NUMTASKS_strict, ToTy::Strict},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Order::Ordering> conv(OpenMPOrderClauseKind T) {
+ // OMPC_ORDER_unknown -> std::nullopt
+ using FromTy = OpenMPOrderClauseKind;
+ using ToTy = clause::Order::Ordering;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_ORDER_concurrent, ToTy::Concurrent},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Order::OrderModifier> conv(OpenMPOrderClauseModifier T) {
+ // OMPC_ORDER_MODIFIER_last -> std::nullopt
+ // OMPC_ORDER_MODIFIER_unknown -> std::nullopt
+ using FromTy = OpenMPOrderClauseModifier;
+ using ToTy = clause::Order::OrderModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_ORDER_MODIFIER_reproducible, ToTy::Reproducible},
+ {OMPC_ORDER_MODIFIER_unconstrained, ToTy::Unconstrained},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Reduction::ReductionModifier>
+conv(OpenMPReductionClauseModifier T) {
+ // OMPC_REDUCTION_unknown -> std::nullopt
+ using FromTy = OpenMPReductionClauseModifier;
+ using ToTy = clause::Reduction::ReductionModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_REDUCTION_default, ToTy::Default},
+ {OMPC_REDUCTION_inscan, ToTy::Inscan},
+ {OMPC_REDUCTION_task, ToTy::Task},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+std::optional<clause::Severity::SevLevel> conv(OpenMPSeverityClauseKind T) {
+ // OMPC_SEVERITY_unknown -> std::nullopt
+ using FromTy = OpenMPSeverityClauseKind;
+ using ToTy = clause::Severity::SevLevel;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OMPC_SEVERITY_fatal, ToTy::Fatal},
+ {OMPC_SEVERITY_warning, ToTy::Warning},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ return std::nullopt;
+}
+
+clause::DefinedOperator::IntrinsicOperator conv(OverloadedOperatorKind T) {
+ using FromTy = OverloadedOperatorKind;
+ using ToTy = clause::DefinedOperator::IntrinsicOperator;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {OO_Plus, ToTy::Add}, {OO_Minus, ToTy::Subtract},
+ {OO_Star, ToTy::Multiply}, {OO_Amp, ToTy::AND},
+ {OO_Pipe, ToTy::OR}, {OO_Caret, ToTy::NEQV},
+ {OO_AmpAmp, ToTy::AND}, {OO_PipePipe, ToTy::OR},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+// Reverse conversions
+
+llvm::omp::DefaultKind vnoc(clause::Default::DataSharingAttribute T) {
+ using FromTy = clause::Default::DataSharingAttribute;
+ using ToTy = llvm::omp::DefaultKind;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Firstprivate, ToTy::OMP_DEFAULT_firstprivate},
+ {FromTy::None, ToTy::OMP_DEFAULT_none},
+ {FromTy::Private, ToTy::OMP_DEFAULT_private},
+ {FromTy::Shared, ToTy::OMP_DEFAULT_shared},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+llvm::omp::ProcBindKind vnoc(clause::ProcBind::AffinityPolicy T) {
+ using FromTy = clause::ProcBind::AffinityPolicy;
+ using ToTy = llvm::omp::ProcBindKind;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Close, ToTy::OMP_PROC_BIND_close},
+ {FromTy::Master, ToTy::OMP_PROC_BIND_master},
+ {FromTy::Primary, ToTy::OMP_PROC_BIND_primary},
+ {FromTy::Spread, ToTy::OMP_PROC_BIND_spread},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPAtClauseKind vnoc(clause::At::ActionTime T) {
+ using FromTy = clause::At::ActionTime;
+ using ToTy = OpenMPAtClauseKind;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Compilation, OMPC_AT_compilation},
+ {FromTy::Execution, OMPC_AT_execution},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPAtomicDefaultMemOrderClauseKind vnoc(MemoryOrder T) {
+ using FromTy = MemoryOrder;
+ using ToTy = OpenMPAtomicDefaultMemOrderClauseKind;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::AcqRel, OMPC_ATOMIC_DEFAULT_MEM_ORDER_acq_rel},
+ {FromTy::Relaxed, OMPC_ATOMIC_DEFAULT_MEM_ORDER_relaxed},
+ {FromTy::SeqCst, OMPC_ATOMIC_DEFAULT_MEM_ORDER_seq_cst},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPBindClauseKind vnoc(clause::Bind::Binding T) {
+ using FromTy = clause::Bind::Binding;
+ using ToTy = OpenMPBindClauseKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Parallel, OMPC_BIND_parallel},
+ {FromTy::Teams, OMPC_BIND_teams},
+ {FromTy::Thread, OMPC_BIND_thread},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPDefaultmapClauseKind vnoc(clause::Defaultmap::VariableCategory T) {
+ using FromTy = clause::Defaultmap::VariableCategory;
+ using ToTy = OpenMPDefaultmapClauseKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Aggregate, OMPC_DEFAULTMAP_aggregate},
+ {FromTy::Pointer, OMPC_DEFAULTMAP_pointer},
+ {FromTy::Scalar, OMPC_DEFAULTMAP_scalar},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPDefaultmapClauseModifier vnoc(clause::Defaultmap::ImplicitBehavior T) {
+ using FromTy = clause::Defaultmap::ImplicitBehavior;
+ using ToTy = OpenMPDefaultmapClauseModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Alloc, OMPC_DEFAULTMAP_MODIFIER_alloc},
+ {FromTy::Default, OMPC_DEFAULTMAP_MODIFIER_default},
+ {FromTy::Firstprivate, OMPC_DEFAULTMAP_MODIFIER_firstprivate},
+ {FromTy::From, OMPC_DEFAULTMAP_MODIFIER_from},
+ {FromTy::None, OMPC_DEFAULTMAP_MODIFIER_none},
+ {FromTy::Present, OMPC_DEFAULTMAP_MODIFIER_present},
+ {FromTy::To, OMPC_DEFAULTMAP_MODIFIER_to},
+ {FromTy::Tofrom, OMPC_DEFAULTMAP_MODIFIER_tofrom},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPDeviceClauseModifier vnoc(clause::Device::DeviceModifier T) {
+ using FromTy = clause::Device::DeviceModifier;
+ using ToTy = OpenMPDeviceClauseModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Ancestor, OMPC_DEVICE_ancestor},
+ {FromTy::DeviceNum, OMPC_DEVICE_device_num},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPDistScheduleClauseKind vnoc(clause::DistSchedule::Kind T) {
+ using FromTy = clause::DistSchedule::Kind;
+ using ToTy = OpenMPDistScheduleClauseKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Static, OMPC_DIST_SCHEDULE_static},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPGrainsizeClauseModifier vnoc(clause::Grainsize::Prescriptiveness T) {
+ using FromTy = clause::Grainsize::Prescriptiveness;
+ using ToTy = OpenMPGrainsizeClauseModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Strict, OMPC_GRAINSIZE_strict},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPLastprivateModifier vnoc(clause::Lastprivate::LastprivateModifier T) {
+ using FromTy = clause::Lastprivate::LastprivateModifier;
+ using ToTy = OpenMPLastprivateModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Conditional, OMPC_LASTPRIVATE_conditional},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPLinearClauseKind vnoc(clause::Linear::LinearModifier T) {
+ using FromTy = clause::Linear::LinearModifier;
+ using ToTy = OpenMPLinearClauseKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Ref, OMPC_LINEAR_ref},
+ {FromTy::Uval, OMPC_LINEAR_uval},
+ {FromTy::Val, OMPC_LINEAR_val},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPMapClauseKind vnoc(clause::Map::MapType T) {
+ using FromTy = clause::Map::MapType;
+ using ToTy = OpenMPMapClauseKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Alloc, OMPC_MAP_alloc}, {FromTy::To, OMPC_MAP_to},
+ {FromTy::From, OMPC_MAP_from}, {FromTy::Tofrom, OMPC_MAP_tofrom},
+ {FromTy::Delete, OMPC_MAP_delete}, {FromTy::Release, OMPC_MAP_release},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPMapModifierKind vnoc(clause::Map::MapTypeModifier T) {
+ using FromTy = clause::Map::MapTypeModifier;
+ using ToTy = OpenMPMapModifierKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Always, OMPC_MAP_MODIFIER_always},
+ {FromTy::Close, OMPC_MAP_MODIFIER_close},
+ {FromTy::Present, OMPC_MAP_MODIFIER_present},
+ {FromTy::OmpxHold, OMPC_MAP_MODIFIER_ompx_hold},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPNumTasksClauseModifier vnoc(clause::NumTasks::Prescriptiveness T) {
+ // OMPC_NUMTASKS_unknown -> std::nullopt
+ using FromTy = clause::NumTasks::Prescriptiveness;
+ using ToTy = OpenMPNumTasksClauseModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Strict, OMPC_NUMTASKS_strict},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPOrderClauseKind vnoc(clause::Order::Ordering T) {
+ using FromTy = clause::Order::Ordering;
+ using ToTy = OpenMPOrderClauseKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Concurrent, OMPC_ORDER_concurrent},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPOrderClauseModifier vnoc(clause::Order::OrderModifier T) {
+ using FromTy = clause::Order::OrderModifier;
+ using ToTy = OpenMPOrderClauseModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Reproducible, OMPC_ORDER_MODIFIER_reproducible},
+ {FromTy::Unconstrained, OMPC_ORDER_MODIFIER_unconstrained},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPReductionClauseModifier vnoc(clause::Reduction::ReductionModifier T) {
+ using FromTy = clause::Reduction::ReductionModifier;
+ using ToTy = OpenMPReductionClauseModifier;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Default, OMPC_REDUCTION_default},
+ {FromTy::Inscan, OMPC_REDUCTION_inscan},
+ {FromTy::Task, OMPC_REDUCTION_task},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OpenMPSeverityClauseKind vnoc(clause::Severity::SevLevel T) {
+ using FromTy = clause::Severity::SevLevel;
+ using ToTy = OpenMPSeverityClauseKind;
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Fatal, OMPC_SEVERITY_fatal},
+ {FromTy::Warning, OMPC_SEVERITY_warning},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+
+OverloadedOperatorKind vnoc(clause::DefinedOperator::IntrinsicOperator T) {
+ using FromTy = clause::DefinedOperator::IntrinsicOperator;
+ using ToTy = OverloadedOperatorKind;
+
+ static const llvm::DenseMap<FromTy, ToTy> Conv = {
+ {FromTy::Add, OO_Plus}, {FromTy::Subtract, OO_Minus},
+ {FromTy::Multiply, OO_Star}, {FromTy::AND, OO_Amp},
+ {FromTy::OR, OO_Pipe}, {FromTy::NEQV, OO_Caret},
+ {FromTy::AND, OO_AmpAmp}, {FromTy::OR, OO_PipePipe},
+ };
+ if (auto F = Conv.find(T); F != Conv.end())
+ return F->second;
+ llvm_unreachable("Unexpected value");
+}
+} // namespace ext
+
+namespace omp {
+using tomp::makeList;
+
+// "Convert" possibly null pointer to std::optional:
+// if the pointer is null, return std::nullopt, otherwise return
+// std::optional(ptr).
+template <typename T> //
+std::optional<std::remove_volatile_t<T> *> maybe(T *ptr) {
+ if (ptr == nullptr)
+ return std::nullopt;
+ return ptr;
+}
+
+// Conditionally "convert" given value into std::optional<T>:
+// if func(val) returns false, return std::nullopt, otherwise
+// return std::optional(val).
+// This is a macro to avoid evaluating "val" if the condition
+// is false.
+#define maybeIf(val, cond) \
+ ((cond) ? std::optional<std::remove_reference_t<decltype(val)>>(val) \
+ : std::optional<std::remove_reference_t<decltype(val)>>{})
+
+static const Expr *getPointerFromOffsetOp(const BinaryOperator *B) {
+ BinaryOperatorKind Opc = B->getOpcode();
+ assert(Opc == BO_Add || Opc == BO_Sub);
+ if (B->getLHS()->getType()->isPointerType())
+ return B->getLHS();
+ assert(B->getRHS()->getType()->isPointerType());
+ return B->getRHS();
+}
+
+// Taken from SemaOpenMP.cpp
+static const Expr *getExprAsWritten(const Expr *E) {
+ if (const auto *FE = dyn_cast<FullExpr>(E))
+ E = FE->getSubExpr();
+
+ if (const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E))
+ E = MTE->getSubExpr();
+
+ while (const auto *Binder = dyn_cast<CXXBindTemporaryExpr>(E))
+ E = Binder->getSubExpr();
+
+ if (const auto *ICE = dyn_cast<ImplicitCastExpr>(E))
+ E = ICE->getSubExprAsWritten();
+ return E->IgnoreParens();
+}
+
+// Taken from SemaOpenMP.cpp
+static const ValueDecl *getCanonicalDecl(const ValueDecl *D) {
+ if (const auto *CED = dyn_cast<OMPCapturedExprDecl>(D))
+ if (const auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
+ D = ME->getMemberDecl();
+
+ D = cast<ValueDecl>(D->getCanonicalDecl());
+ return D;
+}
+
+Object makeObject(const Decl *D, const Expr *E = nullptr) {
+ assert(D != nullptr);
+ return Object{D, E};
+}
+
+Object makeObject(const Expr *E) {
+ if (E->containsErrors())
+ return Object{};
+ if (auto *D = llvm::dyn_cast<DeclRefExpr>(E))
+ return Object{getCanonicalDecl(D->getDecl()), E}; // ValueDecl
+ if (auto *D = llvm::dyn_cast<MemberExpr>(E))
+ return Object{getCanonicalDecl(D->getMemberDecl()), E}; // ValueDecl
+
+ if (auto *A = llvm::dyn_cast<ArraySubscriptExpr>(E))
+ return Object{makeObject(A->getBase()).id(), E};
+ if (auto *A = llvm::dyn_cast<ArraySectionExpr>(E))
+ return Object{makeObject(A->getBase()).id(), E};
+ if (auto *A = llvm::dyn_cast<OMPArrayShapingExpr>(E))
+ return Object{makeObject(A->getBase()).id(), E};
+
+ if (auto *P = llvm::dyn_cast<ParenExpr>(E))
+ return makeObject(P->getSubExpr());
+ if (auto *P = llvm::dyn_cast<ImplicitCastExpr>(E))
+ return makeObject(P->getSubExpr());
+ if (auto *P = llvm::dyn_cast<OpaqueValueExpr>(E))
+ return makeObject(P->getSourceExpr());
+
+ if (auto *P = llvm::dyn_cast<BinaryOperator>(E)) {
+ if (P->isAssignmentOp())
+ return makeObject(P->getLHS());
+ BinaryOperatorKind Opc = P->getOpcode();
+ if (Opc == BO_Add || Opc == BO_Sub)
+ return Object{makeObject(getPointerFromOffsetOp(P)).id(), E};
+ }
+ if (auto *P = llvm::dyn_cast<UnaryOperator>(E)) {
+ UnaryOperatorKind Opc = P->getOpcode();
+ if (Opc == UO_Deref || Opc == UO_AddrOf)
+ return Object{makeObject(P->getSubExpr()).id(), E};
+ }
+
+ if (auto *P = llvm::dyn_cast<UnresolvedLookupExpr>(E))
+ return Object{};
+ if (auto *P = llvm::dyn_cast<CXXThisExpr>(E))
+ return Object{P, E};
+
+ E->dump();
+ llvm_unreachable("Expecting DeclRefExpr");
+}
+
+ObjectList makeObjects(llvm::ArrayRef<const Expr *> Vars) {
+ return makeList(Vars, [](const Expr *E) { return makeObject(E); });
+}
+
+clause::DefinedOperator makeDefinedOperator(OverloadedOperatorKind OOK) {
+ // From the OpenMP 5.2 spec:
+ // A reduction identifier is either an id-expression or one of the following
+ // operators: +, - (deprecated), *, &, |, ^, && and ||.
+ // Min and max are included in the implicitly-declared reduction operators.
+ return clause::DefinedOperator{ext::conv(OOK)};
+}
+
+List<clause::ReductionOperator>
+makeReductionOperators(const DeclarationName &RedId,
+ llvm::ArrayRef<const Expr *> Ops) {
+ using ReductionOperator = clause::ReductionOperator;
+ assert(!RedId.isDependentName());
+ List<clause::ReductionOperator> RedOps;
+
+ DeclarationName::NameKind Kind = RedId.getNameKind();
+ if (Kind == DeclarationName::CXXOperatorName) {
+ OverloadedOperatorKind OOK = RedId.getCXXOverloadedOperator();
+ RedOps.push_back(ReductionOperator{makeDefinedOperator(OOK)});
+ return RedOps;
+ }
+
+ assert(Kind == DeclarationName::Identifier);
+ const auto *II = RedId.getAsIdentifierInfo();
+ if (II->getName() == "min") {
+ auto MinOp = clause::DefinedOperator::IntrinsicOperator::Min;
+ RedOps.push_back(ReductionOperator{clause::DefinedOperator{MinOp}});
+ return RedOps;
+ }
+ if (II->getName() == "max") {
+ auto MaxOp = clause::DefinedOperator::IntrinsicOperator::Max;
+ RedOps.push_back(ReductionOperator{clause::DefinedOperator{MaxOp}});
+ return RedOps;
+ }
+
+ for (const Expr *Op : Ops) {
+ if (Op == nullptr) {
+ // This can happen in an invalid code.
+ Object invalid{};
+ RedOps.clear();
+ RedOps.push_back(ReductionOperator{clause::ProcedureDesignator{invalid}});
+ return RedOps;
+ }
+
+ // If it's not an intrinsic operator, then it should be a function call.
+ auto *CallOp = cast<CallExpr>(Op);
+ Object func = makeObject(CallOp->getCallee());
+ RedOps.push_back(ReductionOperator{clause::ProcedureDesignator{func}});
+ }
+
+ return RedOps;
+}
+
+std::optional<Iterator> tryMakeIterator(const Expr *E) {
+ if (E == nullptr)
+ return std::nullopt;
+
+ Iterator Iter;
+ const auto &IterExpr = *llvm::cast<OMPIteratorExpr>(E);
+
+ using IteratorSpecifier =
+ tomp::type::IteratorSpecifierT<TypeTy, IdentTy, ExprTy>;
+ using Range = tomp::type::RangeT<ExprTy>;
+
+ for (int i = 0, e = IterExpr.numOfIterators(); i != e; ++i) {
+ auto *ID = const_cast<Decl *>(IterExpr.getIteratorDecl(i));
+ const OMPIteratorExpr::IteratorRange &IR = IterExpr.getIteratorRange(i);
+ QualType Type = llvm::cast<VarDecl>(ID)->getType();
+ Range R{{IR.Begin, IR.End, maybe(IR.Step)}};
+ Iter.emplace_back(IteratorSpecifier{{Type, Object{ID, nullptr}, R}});
+ }
+
+ return Iter;
+}
+
+template <typename IteratorTy>
+List<Mapper> makeMappers(llvm::iterator_range<IteratorTy> &&Range) {
+ List<Mapper> Mappers;
+ if (Range.empty())
+ return Mappers;
+
+ for (const Expr *M : Range) {
+ if (M == nullptr || isa<UnresolvedLookupExpr>(M))
+ continue;
+ Object obj = makeObject(M);
+ if (obj.id().index() != 0)
+ Mappers.push_back(Mapper{/*MapperIdentifier=*/obj});
+ }
+ return Mappers;
+}
+
+namespace clause {
+MAKE_EMPTY_CLASS(AcqRel, OMPAcqRelClause);
+MAKE_EMPTY_CLASS(Acquire, OMPAcquireClause);
+MAKE_EMPTY_CLASS(Capture, OMPCaptureClause);
+MAKE_EMPTY_CLASS(Compare, OMPCompareClause);
+MAKE_EMPTY_CLASS(DynamicAllocators, OMPDynamicAllocatorsClause);
+MAKE_EMPTY_CLASS(Full, OMPFullClause);
+// MAKE_EMPTY_CLASS(Inbranch, OMPInbranchClause);
+MAKE_EMPTY_CLASS(Mergeable, OMPMergeableClause);
+MAKE_EMPTY_CLASS(Nogroup, OMPNogroupClause);
+MAKE_EMPTY_CLASS(NoOpenmp, OMPNoOpenMPClause);
+MAKE_EMPTY_CLASS(NoOpenmpRoutines, OMPNoOpenMPRoutinesClause);
+MAKE_EMPTY_CLASS(NoParallelism, OMPNoParallelismClause);
+// MAKE_EMPTY_CLASS(Notinbranch, OMPNotinbranchClause);
+MAKE_EMPTY_CLASS(Nowait, OMPNowaitClause);
+MAKE_EMPTY_CLASS(OmpxAttribute, OMPXAttributeClause);
+MAKE_EMPTY_CLASS(OmpxBare, OMPXBareClause);
+MAKE_EMPTY_CLASS(Read, OMPReadClause);
+MAKE_EMPTY_CLASS(Relaxed, OMPRelaxedClause);
+MAKE_EMPTY_CLASS(Release, OMPReleaseClause);
+MAKE_EMPTY_CLASS(ReverseOffload, OMPReverseOffloadClause);
+MAKE_EMPTY_CLASS(SeqCst, OMPSeqCstClause);
+MAKE_EMPTY_CLASS(Simd, OMPSIMDClause);
+MAKE_EMPTY_CLASS(Threads, OMPThreadsClause);
+MAKE_EMPTY_CLASS(UnifiedAddress, OMPUnifiedAddressClause);
+MAKE_EMPTY_CLASS(UnifiedSharedMemory, OMPUnifiedSharedMemoryClause);
+// MAKE_EMPTY_CLASS(Unknown, OMPUnknownClause);
+MAKE_EMPTY_CLASS(Untied, OMPUntiedClause);
+MAKE_EMPTY_CLASS(Weak, OMPWeakClause);
+MAKE_EMPTY_CLASS(Write, OMPWriteClause);
+
+// Make artificial clauses
+MAKE_EMPTY_CLASS(Depobj, OMPDepobjClause);
+MAKE_EMPTY_CLASS(Flush, OMPFlushClause);
+
+// Other clauses
+
+Absent make(const OMPAbsentClause &C) {
+ ArrayRef<OpenMPDirectiveKind> Kinds = C.getDirectiveKinds();
+ return Absent{/*List=*/{Kinds.begin(), Kinds.end()}};
+}
+
+// AdjustArgs
+
+Affinity make(const OMPAffinityClause &C) {
+ return Affinity{
+ {/*Iterator=*/std::nullopt,
+ /*LocatorList=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+Align make(const OMPAlignClause &C) {
+ return Align{/*Alignment=*/C.getAlignment()};
+}
+
+Aligned make(const OMPAlignedClause &C) {
+ return Aligned{
+ {/*Alignment=*/C.getAlignment(),
+ /*List=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+Allocate make(const OMPAllocateClause &C) {
+ return Allocate{
+ {/*AllocatorSimpleModifier=*/C.getAllocator(),
+ /*AllocatorComplexModifier=*/std::nullopt,
+ /*AlignModifier=*/std::nullopt,
+ /*List=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+Allocator make(const OMPAllocatorClause &C) {
+ return Allocator{/*Allocator=*/C.getAllocator()};
+}
+
+// AppendArgs
+
+At make(const OMPAtClause &C) {
+ return At{/*ActionTime=*/*ext::conv(C.getAtKind())};
+}
+
+AtomicDefaultMemOrder make(const OMPAtomicDefaultMemOrderClause &C) {
+ return AtomicDefaultMemOrder{
+ /*MemoryOrder=*/*ext::conv(C.getAtomicDefaultMemOrderKind())};
+}
+
+Bind make(const OMPBindClause &C) {
+ return Bind{/*Binding=*/*ext::conv(C.getBindKind())};
+}
+
+Collapse make(const OMPCollapseClause &C) {
+ return Collapse{/*N=*/C.getNumForLoops()};
+}
+
+Contains make(const OMPContainsClause &C) {
+ ArrayRef<OpenMPDirectiveKind> Kinds = C.getDirectiveKinds();
+ return Contains{/*List=*/{Kinds.begin(), Kinds.end()}};
+}
+
+Copyin make(const OMPCopyinClause &C) {
+ return Copyin{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+Copyprivate make(const OMPCopyprivateClause &C) {
+ return Copyprivate{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+Default make(const OMPDefaultClause &C) {
+ return Default{/*DataSharingAttribute=*/*ext::conv(C.getDefaultKind())};
+}
+
+Defaultmap make(const OMPDefaultmapClause &C) {
+ return Defaultmap{
+ {
+ /*ImplicitBehavior=*/*ext::conv(C.getDefaultmapModifier()),
+ /*VariableCategory=*/ext::conv(C.getDefaultmapKind()),
+ },
+ };
+}
+
+Doacross make(Doacross::DependenceType DepType,
+ llvm::ArrayRef<const Expr *> Vars);
+
+Depend make(const OMPDependClause &C) {
+ using TaskDependenceType = tomp::type::TaskDependenceType;
+
+ CLAUSET_ENUM_CONVERT( //
+ convertDep, OpenMPDependClauseKind, TaskDependenceType,
+ // clang-format off
+ MU(OMPC_DEPEND_in, In)
+ MU(OMPC_DEPEND_out, Out)
+ MU(OMPC_DEPEND_inout, Inout)
+ MU(OMPC_DEPEND_mutexinoutset, Mutexinoutset)
+ MU(OMPC_DEPEND_inoutset, Inoutset)
+ MU(OMPC_DEPEND_depobj, Depobj)
+ // clang-format on
+ );
+
+ std::optional<Iterator> maybeIterator = tryMakeIterator(C.getModifier());
+ using WithLocators = Depend::WithLocators;
+
+ OpenMPDependClauseKind DepType = C.getDependencyKind();
+ if (DepType == OMPC_DEPEND_outallmemory)
+ return Depend{
+ WithLocators{{/*TaskDependenceType=*/TaskDependenceType::Out,
+ /*Iterator=*/std::move(maybeIterator),
+ /*LocatorList=*/{}}},
+ };
+ if (DepType == OMPC_DEPEND_inoutallmemory)
+ return Depend{
+ WithLocators{{/*TaskDependenceType=*/TaskDependenceType::Inout,
+ /*Iterator=*/std::move(maybeIterator),
+ /*LocatorList=*/{}}},
+ };
+ if (DepType != OMPC_DEPEND_source && DepType != OMPC_DEPEND_sink)
+ return Depend{
+ WithLocators{{/*TaskDependenceType=*/convertDep(DepType),
+ /*Iterator=*/std::move(maybeIterator),
+ /*LocatorList=*/makeObjects(C.getVarRefs())}},
+ };
+
+ // XXX The distance vectors are unavailable: they are in DSAStack, which is
+ // a private member of Sema without an accessor.
+ CLAUSET_ENUM_CONVERT( //
+ convertDoa, OpenMPDependClauseKind, Doacross::DependenceType,
+ // clang-format off
+ MU(OMPC_DEPEND_source, Source)
+ MU(OMPC_DEPEND_sink, Sink)
+ // clang-format on
+ );
+
+ return Depend{make(convertDoa(DepType), C.getVarRefs())};
+}
+
+Destroy make(const OMPDestroyClause &C) {
+ if (Expr *Var = C.getInteropVar())
+ return Destroy{/*DestroyVar=*/makeObject(Var)};
+ return Destroy{/*DestroyVar=*/std::nullopt};
+}
+
+Detach make(const OMPDetachClause &C) {
+ return Detach{/*EventHandle=*/makeObject(C.getEventHandler())};
+}
+
+Device make(const OMPDeviceClause &C) {
+ OpenMPDeviceClauseModifier Modifier = C.getModifier();
+ return Device{
+ {/*DeviceModifier=*/ext::conv(Modifier),
+ /*DeviceDescription=*/C.getDevice()},
+ };
+}
+
+// DeviceType
+
+DistSchedule make(const OMPDistScheduleClause &C) {
+ return DistSchedule{
+ {/*Kind=*/*ext::conv(C.getDistScheduleKind()),
+ /*ChunkSize=*/maybe(C.getChunkSize())},
+ };
+}
+
+Doacross make(Doacross::DependenceType DepType,
+ llvm::ArrayRef<const Expr *> Vars) {
+ // XXX The loop iteration distance vector is unavailable (it's not exported
+ // from Sema/SemaOpenMP.
+ return Doacross{{/*DependenceType=*/DepType, /*Vector=*/{}}};
+}
+
+Doacross make(const OMPDoacrossClause &C) {
+ CLAUSET_ENUM_CONVERT( //
+ convert, OpenMPDoacrossClauseModifier, Doacross::DependenceType,
+ // clang-format off
+ MU(OMPC_DOACROSS_source, Source)
+ MU(OMPC_DOACROSS_source_omp_cur_iteration, Source)
+ MU(OMPC_DOACROSS_sink, Sink)
+ MU(OMPC_DOACROSS_sink_omp_cur_iteration, Sink)
+ // clang-format on
+ );
+
+ OpenMPDoacrossClauseModifier DepType = C.getDependenceType();
+ if (DepType == OMPC_DOACROSS_source_omp_cur_iteration ||
+ DepType == OMPC_DOACROSS_sink_omp_cur_iteration)
+ return make(convert(DepType), {});
+
+ return make(convert(DepType), C.getVarRefs());
+}
+
+// Enter
+
+Exclusive make(const OMPExclusiveClause &C) {
+ return Exclusive{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+Fail make(const OMPFailClause &C) {
+ CLAUSET_ENUM_CONVERT( //
+ convert, llvm::omp::Clause, tomp::type::MemoryOrder,
+ // clang-format off
+ MS(OMPC_acq_rel, AcqRel)
+ MS(OMPC_acquire, Acquire)
+ MS(OMPC_relaxed, Relaxed)
+ MS(OMPC_release, Release)
+ MS(OMPC_seq_cst, SeqCst)
+ // clang-format on
+ );
+
+ return Fail{/*MemoryOrder=*/convert(C.getFailParameter())};
+}
+
+Filter make(const OMPFilterClause &C) {
+ return Filter{/*ThreadNum=*/C.getThreadID()};
+}
+
+Final make(const OMPFinalClause &C) {
+ return Final{/*Finalize=*/C.getCondition()};
+}
+
+Firstprivate make(const OMPFirstprivateClause &C) {
+ return Firstprivate{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+From make(const OMPFromClause &C) {
+ std::optional<tomp::type::MotionExpectation> maybeExp;
+ if (llvm::is_contained(C.getMotionModifiers(), OMPC_MOTION_MODIFIER_present))
+ maybeExp = tomp::type::MotionExpectation::Present;
+
+ List<Mapper> Mappers = makeMappers(C.mapperlists());
+ if (!Mappers.empty())
+ assert(Mappers.size() == 1 || Mappers.size() == C.getVarRefs().size());
+
+ return From{
+ {/*Expectation=*/std::move(maybeExp),
+ /*Mappers=*/maybeIf(Mappers, !Mappers.empty()),
+ /*Iterator=*/std::nullopt,
+ /*LocatorList=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+Grainsize make(const OMPGrainsizeClause &C) {
+ return Grainsize{
+ {/*Prescriptiveness=*/ext::conv(C.getModifier()),
+ /*GrainSize=*/C.getGrainsize()},
+ };
+}
+
+HasDeviceAddr make(const OMPHasDeviceAddrClause &C) {
+ return HasDeviceAddr{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+Hint make(const OMPHintClause &C) {
+ return Hint{/*HintExpr=*/C.getHint()}; //
+}
+
+Holds make(const OMPHoldsClause &C) { return Holds{/*E=*/C.getExpr()}; }
+
+If make(const OMPIfClause &C) {
+ return If{
+ {/*DirectiveNameModifier=*/ext::conv(C.getNameModifier()),
+ /*IfExpression=*/C.getCondition()},
+ };
+}
+
+Inclusive make(const OMPInclusiveClause &C) {
+ return Inclusive{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+// Indirect
+
+Init make(const OMPInitClause &C) {
+ const Expr *Var = C.getInteropVar();
+ Init::InteropTypes Types(2);
+ if (C.getIsTarget())
+ Types.push_back(Init::InteropType::Target);
+ if (C.getIsTargetSync())
+ Types.push_back(Init::InteropType::Targetsync);
+ auto Range = C.prefs();
+ llvm::ArrayRef<const Expr *> Prefs(Range.begin(), Range.end());
+
+ using T = decltype(Init::t);
+ return Init{
+ T{/*InteropPreference=*/maybeIf(Prefs, !Prefs.empty()),
+ /*InteropTypes=*/Types,
+ /*InteropVar=*/makeObject(Var)},
+ };
+}
+
+// Initializer
+
+InReduction make(const OMPInReductionClause &C) {
+ auto OpsRange = C.reduction_ops();
+ List<ReductionOperator> RedOps = makeReductionOperators(
+ C.getNameInfo().getName(), {OpsRange.begin(), OpsRange.end()});
+ assert(RedOps.size() == 1 || RedOps.size() == C.getVarRefs().size());
+
+ return InReduction{
+ {/*ReductionIdentifiers=*/RedOps,
+ /*List=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+IsDevicePtr make(const OMPIsDevicePtrClause &C) {
+ return IsDevicePtr{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+Lastprivate make(const OMPLastprivateClause &C) {
+ return Lastprivate{
+ {/*LastprivateModifier=*/ext::conv(C.getKind()),
+ /*List=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+Linear make(const OMPLinearClause &C) {
+ return Linear{
+ {/*StepSimpleModifier=*/std::nullopt,
+ /*StepComplexModifier=*/C.getStep(),
+ /*LinearModifier=*/*ext::conv(C.getModifier()),
+ /*List=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+// Link
+
+Map make(const OMPMapClause &C) {
+ OpenMPMapClauseKind MapType = C.getMapType();
+ List<Mapper> Mappers = makeMappers(C.mapperlists());
+ if (!Mappers.empty())
+ assert(Mappers.size() == 1 || Mappers.size() == C.getVarRefs().size());
+ std::optional<Iterator> maybeIterator =
+ tryMakeIterator(C.getIteratorModifier());
+
+ Map::MapTypeModifiers Modifiers;
+ auto &&KnownModifiers = llvm::make_filter_range(
+ C.getMapTypeModifiers(), [](OpenMPMapModifierKind M) {
+ // Skip "mapper" and "iterator" modifiers, because they're already
+ // handled.
+ return M != OMPC_MAP_MODIFIER_unknown &&
+ M != OMPC_MAP_MODIFIER_mapper && M != OMPC_MAP_MODIFIER_iterator;
+ });
+ llvm::transform(KnownModifiers, std::back_inserter(Modifiers),
+ [](OpenMPMapModifierKind M) { return *ext::conv(M); });
+
+ return Map{
+ {/*MapType=*/ext::conv(MapType),
+ /*MapTypeModifiers=*/
+ maybeIf(Modifiers, !Modifiers.empty()),
+ /*Mappers=*/maybeIf(Mappers, !Mappers.empty()),
+ /*Iterator=*/std::move(maybeIterator),
+ /*LocatorList=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+// Match
+
+Message make(const OMPMessageClause &C) {
+ return Message{/*MsgString=*/C.getMessageString()};
+}
+
+Nocontext make(const OMPNocontextClause &C) {
+ return Nocontext{/*DoNotUpdateContext=*/C.getCondition()};
+}
+
+Nontemporal make(const OMPNontemporalClause &C) {
+ return Nontemporal{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+Novariants make(const OMPNovariantsClause &C) {
+ return Novariants{/*DoNotUseVariant=*/C.getCondition()};
+}
+
+NumTasks make(const OMPNumTasksClause &C) {
+ using T = decltype(NumTasks::t);
+ return NumTasks{
+ T{/*Prescriptiveness=*/ext::conv(C.getModifier()),
+ /*NumTasks=*/C.getNumTasks()},
+ };
+}
+
+NumTeams make(const OMPNumTeamsClause &C) {
+ ArrayRef<const Expr *> UpperBounds = C.getVarRefs();
+ List<NumTeams::Range> Ranges;
+ for (const Expr *E : UpperBounds) {
+ Ranges.push_back(
+ {{/*LowerBound=*/std::nullopt, /*UpperBound=*/const_cast<Expr *>(E)}});
+ }
+ return NumTeams{std::move(Ranges)};
+}
+
+NumThreads make(const OMPNumThreadsClause &C) {
+ return NumThreads{/*Nthreads=*/C.getNumThreads()};
+}
+
+OmpxDynCgroupMem make(const OMPXDynCGroupMemClause &C) {
+ return OmpxDynCgroupMem{C.getSize()};
+}
+
+Order make(const OMPOrderClause &C) {
+ return Order{
+ {/*OrderModifier=*/ext::conv(C.getModifier()),
+ /*Ordering=*/*ext::conv(C.getKind())},
+ };
+}
+
+Ordered make(const OMPOrderedClause &C) {
+ return Ordered{/*N=*/C.getNumForLoops()};
+}
+
+// Otherwise
+
+Partial make(const OMPPartialClause &C) {
+ return Partial{/*UnrollFactor=*/C.getFactor()};
+}
+
+Priority make(const OMPPriorityClause &C) {
+ return Priority{/*PriorityValue=*/C.getPriority()};
+}
+
+Private make(const OMPPrivateClause &C) {
+ return Private{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+ProcBind make(const OMPProcBindClause &C) {
+ return ProcBind{/*AffinityPolicy=*/*ext::conv(C.getProcBindKind())};
+}
+
+Reduction make(const OMPReductionClause &C) {
+ auto OpsRange = C.reduction_ops();
+ List<ReductionOperator> RedOps = makeReductionOperators(
+ C.getNameInfo().getName(), {OpsRange.begin(), OpsRange.end()});
+ assert(RedOps.size() == 1 || RedOps.size() == C.getVarRefs().size());
+
+ return Reduction{
+ {/*ReductionModifier=*/ext::conv(C.getModifier()),
+ /*ReductionIdentifiers=*/RedOps,
+ /*List=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+Safelen make(const OMPSafelenClause &C) {
+ return Safelen{/*Length=*/C.getSafelen()};
+}
+
+Schedule make(const OMPScheduleClause &C) {
+ CLAUSET_ENUM_CONVERT( //
+ convertKind, OpenMPScheduleClauseKind, Schedule::Kind,
+ // clang-format off
+ MU(OMPC_SCHEDULE_static, Static)
+ MU(OMPC_SCHEDULE_dynamic, Dynamic)
+ MU(OMPC_SCHEDULE_guided, Guided)
+ MU(OMPC_SCHEDULE_auto, Auto)
+ MU(OMPC_SCHEDULE_runtime, Runtime)
+ // clang-format on
+ );
+
+ CLAUSET_ENUM_CONVERT( //
+ convertOrdMod, OpenMPScheduleClauseModifier, Schedule::OrderingModifier,
+ // clang-format off
+ MU(OMPC_SCHEDULE_MODIFIER_monotonic, Monotonic)
+ MU(OMPC_SCHEDULE_MODIFIER_nonmonotonic, Nonmonotonic)
+ // clang-format on
+ );
+
+ CLAUSET_ENUM_CONVERT( //
+ convertChkMod, OpenMPScheduleClauseModifier, Schedule::ChunkModifier,
+ // clang-format off
+ MU(OMPC_SCHEDULE_MODIFIER_simd, Simd)
+ // clang-format on
+ );
+
+ OpenMPScheduleClauseModifier OrdMod = C.getFirstScheduleModifier();
+ OpenMPScheduleClauseModifier ChkMod = C.getSecondScheduleModifier();
+ if (OrdMod == OMPC_SCHEDULE_MODIFIER_simd)
+ std::swap(OrdMod, ChkMod);
+
+ const Expr *ChkSize = C.getChunkSize();
+
+ // clang-format off
+ return Schedule{
+ {/*Kind=*/convertKind(C.getScheduleKind()),
+ /*OrderingModifier=*/maybeIf(convertOrdMod(OrdMod),
+ OrdMod != OMPC_SCHEDULE_MODIFIER_unknown),
+ /*ChunkModifier=*/maybeIf(convertChkMod(ChkMod),
+ ChkMod != OMPC_SCHEDULE_MODIFIER_unknown),
+ /*ChunkSize=*/maybeIf(ChkSize, ChkSize != nullptr)},
+ };
+ // clang-format on
+}
+
+Severity make(const OMPSeverityClause &C) {
+ return Severity{/*SevLevel=*/*ext::conv(C.getSeverityKind())};
+}
+
+Shared make(const OMPSharedClause &C) {
+ return Shared{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+Simdlen make(const OMPSimdlenClause &C) {
+ return Simdlen{/*Length=*/C.getSimdlen()};
+}
+
+Sizes make(const OMPSizesClause &C) {
+ llvm::ArrayRef<const Expr *> S = C.getSizesRefs();
+ return Sizes{/*SizeList=*/Sizes::SizeList(S.begin(), S.end())};
+}
+
+TaskReduction make(const OMPTaskReductionClause &C) {
+ auto OpsRange = C.reduction_ops();
+ List<ReductionOperator> RedOps = makeReductionOperators(
+ C.getNameInfo().getName(), {OpsRange.begin(), OpsRange.end()});
+ assert(RedOps.size() == 1 || RedOps.size() == C.getVarRefs().size());
+
+ using T = decltype(TaskReduction::t);
+ return TaskReduction{
+ T{/*ReductionIdentifiers=*/RedOps,
+ /*List=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+ThreadLimit make(const OMPThreadLimitClause &C) {
+ /// XXX
+ // return ThreadLimit{/*Threadlim=*/C.getThreadLimit()};
+ return ThreadLimit{/*Threadlim=*/C.getVarRefs()[0]};
+}
+
+To make(const OMPToClause &C) {
+ std::optional<tomp::type::MotionExpectation> maybeExp;
+ if (llvm::is_contained(C.getMotionModifiers(), OMPC_MOTION_MODIFIER_present))
+ maybeExp = tomp::type::MotionExpectation::Present;
+
+ List<Mapper> Mappers = makeMappers(C.mapperlists());
+ if (!Mappers.empty())
+ assert(Mappers.size() == 1 || Mappers.size() == C.getVarRefs().size());
+
+ return To{
+ {/*Expectation=*/std::move(maybeExp),
+ /*Mapper=*/maybeIf(Mappers, !Mappers.empty()),
+ /*Iterator=*/std::nullopt,
+ /*LocatorList=*/makeObjects(C.getVarRefs())},
+ };
+}
+
+// Uniform
+
+Update make(const OMPUpdateClause &C) {
+ if (!C.isExtended())
+ return Update{/*TaskDependenceType=*/std::nullopt};
+
+ using TaskDependenceType = tomp::type::TaskDependenceType;
+ CLAUSET_ENUM_CONVERT( //
+ convert, OpenMPDependClauseKind, TaskDependenceType,
+ // clang-format off
+ MU(OMPC_DEPEND_in, In)
+ MU(OMPC_DEPEND_out, Out)
+ MU(OMPC_DEPEND_inout, Inout)
+ MU(OMPC_DEPEND_mutexinoutset, Mutexinoutset)
+ MU(OMPC_DEPEND_inoutset, Inoutset)
+ // OMPC_DEPEND_depobj is not allowed
+ // clang-format on
+ );
+
+ OpenMPDependClauseKind DepType = C.getDependencyKind();
+ return Update{/*TaskDependenceType=*/maybeIf(convert(DepType),
+ DepType != OMPC_DEPEND_unknown)};
+}
+
+Use make(const OMPUseClause &C) {
+ return Use{/*InteropVar=*/makeObject(C.getInteropVar())};
+}
+
+UseDeviceAddr make(const OMPUseDeviceAddrClause &C) {
+ return UseDeviceAddr{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+UseDevicePtr make(const OMPUseDevicePtrClause &C) {
+ return UseDevicePtr{/*List=*/makeObjects(C.getVarRefs())};
+}
+
+UsesAllocators make(const OMPUsesAllocatorsClause &C) {
+ UsesAllocators::Allocators AllocList;
+ AllocList.reserve(C.getNumberOfAllocators());
+
+ using S = decltype(UsesAllocators::AllocatorSpec::t);
+ for (int i = 0, e = C.getNumberOfAllocators(); i != e; ++i) {
+ OMPUsesAllocatorsClause::Data Data = C.getAllocatorData(i);
+ AllocList.push_back(UsesAllocators::AllocatorSpec{
+ S{/*MemSpace=*/std::nullopt, /*TraitsArray=*/
+ maybeIf(makeObject(Data.AllocatorTraits),
+ Data.AllocatorTraits != nullptr),
+ /*Allocator=*/Data.Allocator}});
+ }
+
+ return UsesAllocators{/*Allocators=*/std::move(AllocList)};
+}
+
+// When
+
+} // namespace clause
+
+Clause makeClause(OMPClause *C) {
+#define GEN_CLANG_CLAUSE_CLASS
+#define CLAUSE_CLASS(Enum, Str, Class) \
+ if (auto S = llvm::dyn_cast<Class>(C)) \
+ return Clause{/*Base class*/ {C->getClauseKind(), clause::make(*S)}, C};
+#include "llvm/Frontend/OpenMP/OMP.inc"
+ llvm_unreachable("Unexpected clause");
+}
+
+List<Clause> makeClauses(llvm::ArrayRef<OMPClause *> Clauses) {
+ return makeList(Clauses, [](OMPClause *C) { return makeClause(C); });
+}
+} // namespace omp
+
+namespace clang {
+bool ExtConstructDecomposition::ExtConstruct::addClause(const omp::Clause &C) {
+ if (llvm::omp::isUniqueClause(C.id)) {
+ // If C is a unique clause, only add it if one like this isn't
+ // already there.
+ auto F = llvm::find_if(
+ clauses, [Id = C.id](const omp::Clause &T) { return T.id == Id; });
+ if (F != clauses.end())
+ return false;
+ } else {
+ // Don't add multiple clauses that correspond to the same AST clause.
+ if (C.tag.getFlags() == C.tag.Explicit && C.tag.getPointer()) {
+ void *Ptr = C.tag.getPointer();
+ auto F = llvm::find_if(clauses, [=](const omp::Clause &T) {
+ return T.tag.getFlags() == T.tag.Explicit && T.tag.getPointer() == Ptr;
+ });
+ if (F != clauses.end())
+ return false;
+ }
+ }
+ clauses.push_back(C);
+ return true;
+}
+
+ExtConstructDecomposition::ExtConstructDecomposition(
+ OpenMPDirectiveKind DKind, llvm::ArrayRef<omp::Clause> Clauses,
+ uint32_t OMPVersion)
+ : InputDKind(DKind), ClauseStorage(Clauses.begin(), Clauses.end()) {
+
+ Decomposer =
+ std::make_unique<DecomposerTy>(OMPVersion, *this, DKind, ClauseStorage,
+ /*makeImplicit=*/false);
+ if (Decomposer->output.empty())
+ return;
+
+ llvm::SmallVector<OpenMPDirectiveKind> UnitKinds;
+ std::ignore = llvm::omp::getLeafOrCompositeConstructs(DKind, UnitKinds);
+ for (OpenMPDirectiveKind Unit : UnitKinds) {
+ Output.push_back(ExtConstruct(Unit));
+ for (OpenMPDirectiveKind Leaf : llvm::omp::getLeafConstructsOrSelf(Unit)) {
+ auto P = CompositionMap.insert(std::make_pair(Leaf, Unit));
+ assert(P.second && "Repeated leaf in compound directive");
+ }
+ }
+
+ for (tomp::DirectiveWithClauses<omp::Clause> &DWC : Decomposer->output) {
+ ExtConstruct &Con = getConstruct(DWC.id);
+ for (const omp::Clause &C : DWC.clauses)
+ Con.addClause(C);
+ }
+}
+
+bool ExtConstructDecomposition::postApply(
+ const omp::Clause &C, llvm::SmallVector<OpenMPDirectiveKind> *Modified) {
+ llvm::SmallVector<size_t> ClauseCount;
+
+ for (tomp::DirectiveWithClauses<omp::Clause> &DWC : Decomposer->output)
+ ClauseCount.push_back(DWC.clauses.size());
+
+ ClauseStorage.push_back(C);
+ bool Applied = Decomposer->postApply(C);
+
+ if (!Applied)
+ return false;
+
+ for (size_t I = 0, E = Decomposer->output.size(); I != E; ++I) {
+ tomp::DirectiveWithClauses<omp::Clause> &DWC = Decomposer->output[I];
+ size_t SizeThen = ClauseCount[I], SizeNow = DWC.clauses.size();
+ if (SizeThen < SizeNow) {
+ ExtConstruct &Con = getConstruct(DWC.id);
+ for (size_t J = SizeThen; J != SizeNow; ++J)
+ Con.addClause(DWC.clauses[J]);
+ if (Modified)
+ Modified->push_back(Con.DKind);
+ }
+ }
+ return true;
+}
+
+ExtConstructDecomposition::ExtConstruct &
+ExtConstructDecomposition::getConstruct(OpenMPDirectiveKind Leaf) {
+ assert(llvm::omp::isLeafConstruct(Leaf) && "Expecting leaf construct");
+ OpenMPDirectiveKind ConKind = CompositionMap.at(Leaf);
+ auto F = llvm::find_if(
+ Output, [=](const ExtConstruct &T) { return T.DKind == ConKind; });
+ assert(F != Output.end() && "Constituent not found");
+ return *F;
+}
+
+// Given an object, return its base object if one exists.
+std::optional<omp::Object>
+ExtConstructDecomposition::getBaseObject(const omp::Object &Obj) {
+ return std::nullopt; // XXX
+}
+
+// Return the iteration variable of the associated loop if any.
+std::optional<omp::Object> ExtConstructDecomposition::getLoopIterVar() {
+ return std::nullopt; // XXX
+}
+} // namespace clang
diff --git a/clang/lib/Sema/SemaOpenMPExt.h b/clang/lib/Sema/SemaOpenMPExt.h
new file mode 100644
index 00000000000000..7e3c158466d075
--- /dev/null
+++ b/clang/lib/Sema/SemaOpenMPExt.h
@@ -0,0 +1,428 @@
+#ifndef CLANG_SEMA_SEMAOPENMPEXT_H
+#define CLANG_SEMA_SEMAOPENMPEXT_H
+
+#include "clang/AST/ExprCXX.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/OpenMPKinds.h"
+#include "llvm/ADT/PointerIntPair.h"
+#include "llvm/Frontend/OpenMP/ClauseT.h"
+#include "llvm/Frontend/OpenMP/ConstructDecompositionT.h"
+#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include "llvm/Support/MathExtras.h"
+
+#include <iterator>
+#include <memory>
+#include <optional>
+#include <type_traits>
+#include <utility>
+#include <variant>
+
+namespace clang {
+class Decl;
+class Expr;
+class OMPClause;
+} // namespace clang
+
+namespace omp {
+using TypeTy = clang::QualType;
+using IdentTy = std::variant<std::monostate, const clang::Decl *,
+ const clang::CXXThisExpr *>;
+using ExprTy = const clang::Expr *;
+} // namespace omp
+
+template <> struct tomp::type::ObjectT<omp::IdentTy, omp::ExprTy> {
+ using IdType = omp::IdentTy;
+ using ExprType = omp::ExprTy;
+
+ IdType id() const { return declaration; }
+ ExprType ref() const { return reference; }
+
+ IdType declaration;
+ ExprType reference;
+};
+
+namespace omp {
+template <typename T> //
+using List = tomp::type::ListT<T>;
+
+using Object = tomp::type::ObjectT<IdentTy, ExprTy>;
+using ObjectList = tomp::type::ObjectListT<IdentTy, ExprTy>;
+using Iterator = tomp::type::IteratorT<TypeTy, IdentTy, ExprTy>;
+using Range = tomp::type::RangeT<ExprTy>;
+using Mapper = tomp::type::MapperT<IdentTy, ExprTy>;
+
+namespace clause {
+using DefinedOperator = tomp::type::DefinedOperatorT<IdentTy, ExprTy>;
+using ProcedureDesignator = tomp::type::ProcedureDesignatorT<IdentTy, ExprTy>;
+using ReductionOperator = tomp::type::ReductionIdentifierT<IdentTy, ExprTy>;
+
+using Absent = tomp::clause::AbsentT<TypeTy, IdentTy, ExprTy>;
+using AcqRel = tomp::clause::AcqRelT<TypeTy, IdentTy, ExprTy>;
+using Acquire = tomp::clause::AcquireT<TypeTy, IdentTy, ExprTy>;
+using AdjustArgs = tomp::clause::AdjustArgsT<TypeTy, IdentTy, ExprTy>;
+using Affinity = tomp::clause::AffinityT<TypeTy, IdentTy, ExprTy>;
+using Align = tomp::clause::AlignT<TypeTy, IdentTy, ExprTy>;
+using Aligned = tomp::clause::AlignedT<TypeTy, IdentTy, ExprTy>;
+using Allocate = tomp::clause::AllocateT<TypeTy, IdentTy, ExprTy>;
+using Allocator = tomp::clause::AllocatorT<TypeTy, IdentTy, ExprTy>;
+using AppendArgs = tomp::clause::AppendArgsT<TypeTy, IdentTy, ExprTy>;
+using At = tomp::clause::AtT<TypeTy, IdentTy, ExprTy>;
+using AtomicDefaultMemOrder =
+ tomp::clause::AtomicDefaultMemOrderT<TypeTy, IdentTy, ExprTy>;
+using Bind = tomp::clause::BindT<TypeTy, IdentTy, ExprTy>;
+using Capture = tomp::clause::CaptureT<TypeTy, IdentTy, ExprTy>;
+using Collapse = tomp::clause::CollapseT<TypeTy, IdentTy, ExprTy>;
+using Compare = tomp::clause::CompareT<TypeTy, IdentTy, ExprTy>;
+using Contains = tomp::clause::ContainsT<TypeTy, IdentTy, ExprTy>;
+using Copyin = tomp::clause::CopyinT<TypeTy, IdentTy, ExprTy>;
+using Copyprivate = tomp::clause::CopyprivateT<TypeTy, IdentTy, ExprTy>;
+using Default = tomp::clause::DefaultT<TypeTy, IdentTy, ExprTy>;
+using Defaultmap = tomp::clause::DefaultmapT<TypeTy, IdentTy, ExprTy>;
+using Depend = tomp::clause::DependT<TypeTy, IdentTy, ExprTy>;
+using Destroy = tomp::clause::DestroyT<TypeTy, IdentTy, ExprTy>;
+using Detach = tomp::clause::DetachT<TypeTy, IdentTy, ExprTy>;
+using Device = tomp::clause::DeviceT<TypeTy, IdentTy, ExprTy>;
+using DeviceType = tomp::clause::DeviceTypeT<TypeTy, IdentTy, ExprTy>;
+using DistSchedule = tomp::clause::DistScheduleT<TypeTy, IdentTy, ExprTy>;
+using Doacross = tomp::clause::DoacrossT<TypeTy, IdentTy, ExprTy>;
+using DynamicAllocators =
+ tomp::clause::DynamicAllocatorsT<TypeTy, IdentTy, ExprTy>;
+using Enter = tomp::clause::EnterT<TypeTy, IdentTy, ExprTy>;
+using Exclusive = tomp::clause::ExclusiveT<TypeTy, IdentTy, ExprTy>;
+using Fail = tomp::clause::FailT<TypeTy, IdentTy, ExprTy>;
+using Filter = tomp::clause::FilterT<TypeTy, IdentTy, ExprTy>;
+using Final = tomp::clause::FinalT<TypeTy, IdentTy, ExprTy>;
+using Firstprivate = tomp::clause::FirstprivateT<TypeTy, IdentTy, ExprTy>;
+using From = tomp::clause::FromT<TypeTy, IdentTy, ExprTy>;
+using Full = tomp::clause::FullT<TypeTy, IdentTy, ExprTy>;
+using Grainsize = tomp::clause::GrainsizeT<TypeTy, IdentTy, ExprTy>;
+using HasDeviceAddr = tomp::clause::HasDeviceAddrT<TypeTy, IdentTy, ExprTy>;
+using Hint = tomp::clause::HintT<TypeTy, IdentTy, ExprTy>;
+using Holds = tomp::clause::HoldsT<TypeTy, IdentTy, ExprTy>;
+using If = tomp::clause::IfT<TypeTy, IdentTy, ExprTy>;
+using Inbranch = tomp::clause::InbranchT<TypeTy, IdentTy, ExprTy>;
+using Inclusive = tomp::clause::InclusiveT<TypeTy, IdentTy, ExprTy>;
+using Indirect = tomp::clause::IndirectT<TypeTy, IdentTy, ExprTy>;
+using Init = tomp::clause::InitT<TypeTy, IdentTy, ExprTy>;
+using Initializer = tomp::clause::InitializerT<TypeTy, IdentTy, ExprTy>;
+using InReduction = tomp::clause::InReductionT<TypeTy, IdentTy, ExprTy>;
+using IsDevicePtr = tomp::clause::IsDevicePtrT<TypeTy, IdentTy, ExprTy>;
+using Lastprivate = tomp::clause::LastprivateT<TypeTy, IdentTy, ExprTy>;
+using Linear = tomp::clause::LinearT<TypeTy, IdentTy, ExprTy>;
+using Link = tomp::clause::LinkT<TypeTy, IdentTy, ExprTy>;
+using Map = tomp::clause::MapT<TypeTy, IdentTy, ExprTy>;
+using Match = tomp::clause::MatchT<TypeTy, IdentTy, ExprTy>;
+using Mergeable = tomp::clause::MergeableT<TypeTy, IdentTy, ExprTy>;
+using Message = tomp::clause::MessageT<TypeTy, IdentTy, ExprTy>;
+using Nocontext = tomp::clause::NocontextT<TypeTy, IdentTy, ExprTy>;
+using Nogroup = tomp::clause::NogroupT<TypeTy, IdentTy, ExprTy>;
+using Nontemporal = tomp::clause::NontemporalT<TypeTy, IdentTy, ExprTy>;
+using NoOpenmp = tomp::clause::NoOpenmpT<TypeTy, IdentTy, ExprTy>;
+using NoOpenmpRoutines =
+ tomp::clause::NoOpenmpRoutinesT<TypeTy, IdentTy, ExprTy>;
+using NoParallelism = tomp::clause::NoParallelismT<TypeTy, IdentTy, ExprTy>;
+using Notinbranch = tomp::clause::NotinbranchT<TypeTy, IdentTy, ExprTy>;
+using Novariants = tomp::clause::NovariantsT<TypeTy, IdentTy, ExprTy>;
+using Nowait = tomp::clause::NowaitT<TypeTy, IdentTy, ExprTy>;
+using NumTasks = tomp::clause::NumTasksT<TypeTy, IdentTy, ExprTy>;
+using NumTeams = tomp::clause::NumTeamsT<TypeTy, IdentTy, ExprTy>;
+using NumThreads = tomp::clause::NumThreadsT<TypeTy, IdentTy, ExprTy>;
+using OmpxAttribute = tomp::clause::OmpxAttributeT<TypeTy, IdentTy, ExprTy>;
+using OmpxBare = tomp::clause::OmpxBareT<TypeTy, IdentTy, ExprTy>;
+using OmpxDynCgroupMem =
+ tomp::clause::OmpxDynCgroupMemT<TypeTy, IdentTy, ExprTy>;
+using Order = tomp::clause::OrderT<TypeTy, IdentTy, ExprTy>;
+using Ordered = tomp::clause::OrderedT<TypeTy, IdentTy, ExprTy>;
+using Otherwise = tomp::clause::OtherwiseT<TypeTy, IdentTy, ExprTy>;
+using Partial = tomp::clause::PartialT<TypeTy, IdentTy, ExprTy>;
+using Priority = tomp::clause::PriorityT<TypeTy, IdentTy, ExprTy>;
+using Private = tomp::clause::PrivateT<TypeTy, IdentTy, ExprTy>;
+using ProcBind = tomp::clause::ProcBindT<TypeTy, IdentTy, ExprTy>;
+using Read = tomp::clause::ReadT<TypeTy, IdentTy, ExprTy>;
+using Reduction = tomp::clause::ReductionT<TypeTy, IdentTy, ExprTy>;
+using Relaxed = tomp::clause::RelaxedT<TypeTy, IdentTy, ExprTy>;
+using Release = tomp::clause::ReleaseT<TypeTy, IdentTy, ExprTy>;
+using ReverseOffload = tomp::clause::ReverseOffloadT<TypeTy, IdentTy, ExprTy>;
+using Safelen = tomp::clause::SafelenT<TypeTy, IdentTy, ExprTy>;
+using Schedule = tomp::clause::ScheduleT<TypeTy, IdentTy, ExprTy>;
+using SeqCst = tomp::clause::SeqCstT<TypeTy, IdentTy, ExprTy>;
+using Severity = tomp::clause::SeverityT<TypeTy, IdentTy, ExprTy>;
+using Shared = tomp::clause::SharedT<TypeTy, IdentTy, ExprTy>;
+using Simd = tomp::clause::SimdT<TypeTy, IdentTy, ExprTy>;
+using Simdlen = tomp::clause::SimdlenT<TypeTy, IdentTy, ExprTy>;
+using Sizes = tomp::clause::SizesT<TypeTy, IdentTy, ExprTy>;
+using TaskReduction = tomp::clause::TaskReductionT<TypeTy, IdentTy, ExprTy>;
+using ThreadLimit = tomp::clause::ThreadLimitT<TypeTy, IdentTy, ExprTy>;
+using Threads = tomp::clause::ThreadsT<TypeTy, IdentTy, ExprTy>;
+using To = tomp::clause::ToT<TypeTy, IdentTy, ExprTy>;
+using UnifiedAddress = tomp::clause::UnifiedAddressT<TypeTy, IdentTy, ExprTy>;
+using UnifiedSharedMemory =
+ tomp::clause::UnifiedSharedMemoryT<TypeTy, IdentTy, ExprTy>;
+using Uniform = tomp::clause::UniformT<TypeTy, IdentTy, ExprTy>;
+using Unknown = tomp::clause::UnknownT<TypeTy, IdentTy, ExprTy>;
+using Untied = tomp::clause::UntiedT<TypeTy, IdentTy, ExprTy>;
+using Update = tomp::clause::UpdateT<TypeTy, IdentTy, ExprTy>;
+using Use = tomp::clause::UseT<TypeTy, IdentTy, ExprTy>;
+using UseDeviceAddr = tomp::clause::UseDeviceAddrT<TypeTy, IdentTy, ExprTy>;
+using UseDevicePtr = tomp::clause::UseDevicePtrT<TypeTy, IdentTy, ExprTy>;
+using UsesAllocators = tomp::clause::UsesAllocatorsT<TypeTy, IdentTy, ExprTy>;
+using Weak = tomp::clause::WeakT<TypeTy, IdentTy, ExprTy>;
+using When = tomp::clause::WhenT<TypeTy, IdentTy, ExprTy>;
+using Write = tomp::clause::WriteT<TypeTy, IdentTy, ExprTy>;
+} // namespace clause
+
+using tomp::type::operator==;
+
+// Manually define artificial clauses
+struct Depobj {
+ using EmptyTrait = std::true_type;
+};
+struct Flush {
+ using EmptyTrait = std::true_type;
+};
+
+using ClauseBase = tomp::ClauseT<TypeTy, IdentTy, ExprTy,
+ // Artificial clauses:
+ Depobj, Flush>;
+
+struct Clause : public ClauseBase {
+ struct TagType;
+
+ Clause(ClauseBase &&Base, TagType Tag)
+ : ClauseBase(std::move(Base)), tag(Tag) {}
+ Clause(ClauseBase &&Base, const clang::OMPClause *C = nullptr)
+ : Clause(std::move(Base), TagType::get(C)) {}
+
+ struct TagType {
+ using StorageTy = std::common_type_t<uint64_t, uintptr_t>;
+
+ enum : unsigned {
+ Explicit = 0, // The clause should be treated as explicit. If the clause
+ // originated from AST, Storage contains the OMPClause*,
+ // otherwise nullptr.
+ // This is the value when TagType is default-initialized.
+ // Explicit clauses will be applied early (before captured
+ // region is closed), non-explicit clauses may be applied
+ // after closing of the region.
+ Simple, // The clause is implicit, and should be turned into an
+ // AST node with default settings (empty location, etc.).
+ // Storage is ignored.
+ Mapping, // The clause implicit and is "map", Storage is A[2]:
+ // A[0] = Defaultmap category, A[1] = MapType.
+ };
+
+ static TagType get(const clang::OMPClause *C) {
+ return TagType{Explicit, reinterpret_cast<StorageTy>(C)};
+ }
+ static TagType get() { return TagType{Simple, 0x0}; }
+ static TagType get(unsigned DefType, unsigned MapType) {
+ return TagType{Mapping, llvm::Make_64(/*Hi=*/MapType, /*Lo=*/DefType)};
+ }
+
+ unsigned getFlags() const { return Flags; }
+ void *getPointer() const { return reinterpret_cast<void *>(Storage); }
+ std::pair<unsigned, unsigned> getMapKinds() const {
+ return {llvm::Lo_32(Storage), llvm::Hi_32(Storage)};
+ }
+
+ unsigned Flags = 0x0;
+ StorageTy Storage = 0x0;
+ };
+
+ TagType tag;
+};
+
+Clause makeClause(clang::OMPClause *C);
+List<Clause> makeClauses(llvm::ArrayRef<clang::OMPClause *> AstClauses);
+
+Object makeObject(const clang::Expr *E);
+ObjectList makeObjects(llvm::ArrayRef<const clang::Expr *> Vars);
+} // namespace omp
+
+namespace ext {
+// "Rename" the omp namespace to ext to make it visibly distinct from
+// other OpenMP symbols.
+using namespace omp;
+
+using MemoryOrder = tomp::type::MemoryOrder;
+
+inline std::optional<tomp::type::DirectiveName> conv(llvm::omp::Directive T) {
+ if (T != llvm::omp::Directive::OMPD_unknown)
+ return T;
+ return std::nullopt;
+}
+
+// Conversions between enums used by omp::Clause and clang.
+// Using trailing return, otherwise these declarations are visually unparseable.
+auto conv(llvm::omp::DefaultKind T)
+ -> std::optional<clause::Default::DataSharingAttribute>;
+auto conv(llvm::omp::ProcBindKind T)
+ -> std::optional<clause::ProcBind::AffinityPolicy>;
+auto conv(clang::OpenMPAtClauseKind T) //
+ -> std::optional<clause::At::ActionTime>;
+auto conv(clang::OpenMPAtomicDefaultMemOrderClauseKind T)
+ -> std::optional<MemoryOrder>;
+auto conv(clang::OpenMPBindClauseKind T)
+ -> std::optional<clause::Bind::Binding>;
+auto conv(clang::OpenMPDefaultmapClauseKind T)
+ -> std::optional<clause::Defaultmap::VariableCategory>;
+auto conv(clang::OpenMPDefaultmapClauseModifier T)
+ -> std::optional<clause::Defaultmap::ImplicitBehavior>;
+auto conv(clang::OpenMPDeviceClauseModifier T)
+ -> std::optional<clause::Device::DeviceModifier>;
+auto conv(clang::OpenMPDistScheduleClauseKind T)
+ -> std::optional<clause::DistSchedule::Kind>;
+auto conv(clang::OpenMPGrainsizeClauseModifier T)
+ -> std::optional<clause::Grainsize::Prescriptiveness>;
+auto conv(clang::OpenMPLastprivateModifier T)
+ -> std::optional<clause::Lastprivate::LastprivateModifier>;
+auto conv(clang::OpenMPLinearClauseKind T)
+ -> std::optional<clause::Linear::LinearModifier>;
+auto conv(clang::OpenMPMapClauseKind T) //
+ -> std::optional<clause::Map::MapType>;
+auto conv(clang::OpenMPMapModifierKind T)
+ -> std::optional<clause::Map::MapTypeModifier>;
+auto conv(clang::OpenMPNumTasksClauseModifier T)
+ -> std::optional<clause::NumTasks::Prescriptiveness>;
+auto conv(clang::OpenMPOrderClauseKind T)
+ -> std::optional<clause::Order::Ordering>;
+auto conv(clang::OpenMPOrderClauseModifier T)
+ -> std::optional<clause::Order::OrderModifier>;
+auto conv(clang::OpenMPReductionClauseModifier T)
+ -> std::optional<clause::Reduction::ReductionModifier>;
+auto conv(clang::OpenMPSeverityClauseKind T)
+ -> std::optional<clause::Severity::SevLevel>;
+auto conv(clang::OverloadedOperatorKind T)
+ -> clause::DefinedOperator::IntrinsicOperator;
+
+auto vnoc(clause::Default::DataSharingAttribute T) -> llvm::omp::DefaultKind;
+auto vnoc(clause::ProcBind::AffinityPolicy T) -> llvm::omp::ProcBindKind;
+auto vnoc(clause::At::ActionTime T) -> clang::OpenMPAtClauseKind;
+auto vnoc(MemoryOrder T) -> clang::OpenMPAtomicDefaultMemOrderClauseKind;
+auto vnoc(clause::Bind::Binding T) -> clang::OpenMPBindClauseKind;
+auto vnoc(clause::Defaultmap::VariableCategory T)
+ -> clang::OpenMPDefaultmapClauseKind;
+auto vnoc(clause::Defaultmap::ImplicitBehavior T)
+ -> clang::OpenMPDefaultmapClauseModifier;
+auto vnoc(clause::Device::DeviceModifier T)
+ -> clang::OpenMPDeviceClauseModifier;
+auto vnoc(clause::DistSchedule::Kind T) -> clang::OpenMPDistScheduleClauseKind;
+auto vnoc(clause::Grainsize::Prescriptiveness T)
+ -> clang::OpenMPGrainsizeClauseModifier;
+auto vnoc(clause::Lastprivate::LastprivateModifier T)
+ -> clang::OpenMPLastprivateModifier;
+auto vnoc(clause::Linear::LinearModifier T) -> clang::OpenMPLinearClauseKind;
+auto vnoc(clause::Map::MapType T) -> clang::OpenMPMapClauseKind;
+auto vnoc(clause::Map::MapTypeModifier T) -> clang::OpenMPMapModifierKind;
+auto vnoc(clause::NumTasks::Prescriptiveness)
+ -> clang::OpenMPNumTasksClauseModifier;
+auto vnoc(clause::Order::Ordering T) -> clang::OpenMPOrderClauseKind;
+auto vnoc(clause::Order::OrderModifier T) -> clang::OpenMPOrderClauseModifier;
+auto vnoc(clause::Reduction::ReductionModifier T)
+ -> clang::OpenMPReductionClauseModifier;
+auto vnoc(clause::Severity::SevLevel T) -> clang::OpenMPSeverityClauseKind;
+} // namespace ext
+
+namespace clang {
+using OpenMPDirectiveKind = llvm::omp::Directive;
+using OpenMPClauseKind = llvm::omp::Clause;
+
+template <typename ContainerTy> struct QueueAdapter {
+ using value_type = typename ContainerTy::value_type;
+ using iterator = typename ContainerTy::iterator;
+ using const_iterator = typename ContainerTy::const_iterator;
+
+ QueueAdapter() : Container(nullptr), StartIdx(0) {}
+ QueueAdapter(ContainerTy &C) : Container(&C), StartIdx(C.size()) {}
+ template <typename OtherTy,
+ std::enable_if_t<std::is_same_v<value_type, OtherTy::value_type>,
+ int> = 0>
+ QueueAdapter &operator=(OtherTy &C) {
+ Container = &C;
+ StartIdx = C.size();
+ }
+
+ value_type &take() {
+ assert(StartIdx < Container->size() && "Taking from empty queue");
+ return (*Container)[StartIdx++];
+ }
+
+ ArrayRef<value_type> takeAll() {
+ ArrayRef Res(begin(), end());
+ StartIdx += Res.size();
+ return Res;
+ }
+
+ size_t size() const { return Container->size() - StartIdx; }
+ bool empty() const { return size() == 0; }
+
+ ContainerTy *Container;
+
+ iterator begin() {
+ iterator it = Container->begin();
+ std::advance(it, StartIdx);
+ return it;
+ }
+ iterator end() { return Container->end(); }
+ const iterator begin() const {
+ const iterator it = Container->begin();
+ std::advance(it, StartIdx);
+ return it;
+ }
+ const_iterator end() const { return Container->end(); }
+
+private:
+ size_t StartIdx;
+};
+
+template <typename ContainerTy>
+QueueAdapter(ContainerTy) -> QueueAdapter<ContainerTy>;
+
+struct ExtConstructDecomposition {
+ struct ExtConstruct : private tomp::DirectiveWithClauses<omp::Clause> {
+ using BaseTy = tomp::DirectiveWithClauses<omp::Clause>;
+
+ ExtConstruct(const ExtConstruct &Con)
+ : BaseTy(Con), DKind(id), ClausesQ(clauses) {}
+ ExtConstruct(ExtConstruct &&Con)
+ : BaseTy(std::move(Con)), DKind(id), ClausesQ(clauses) {}
+ ExtConstruct(OpenMPDirectiveKind DK = llvm::omp::OMPD_unknown)
+ : DKind(id), ClausesQ(clauses) {
+ id = DK;
+ }
+ bool addClause(const omp::Clause &C);
+
+ OpenMPDirectiveKind &DKind;
+ QueueAdapter<decltype(clauses)> ClausesQ;
+ };
+
+ ExtConstructDecomposition(OpenMPDirectiveKind DKind,
+ llvm::ArrayRef<omp::Clause> Clauses,
+ uint32_t OMPVersion);
+
+ bool postApply(const omp::Clause &C,
+ llvm::SmallVector<OpenMPDirectiveKind> *Modified);
+
+ // Given an object, return its base object if one exists.
+ std::optional<omp::Object> getBaseObject(const omp::Object &Obj);
+
+ // Return the iteration variable of the associated loop if any.
+ std::optional<omp::Object> getLoopIterVar();
+
+ OpenMPDirectiveKind InputDKind;
+ llvm::SmallVector<omp::Clause> ClauseStorage;
+ // Map: leaf -> leaf-or-composite construct containing the leaf,
+ // for each leaf constituent of the original directive.
+ llvm::DenseMap<OpenMPDirectiveKind, OpenMPDirectiveKind> CompositionMap;
+ llvm::SmallVector<ExtConstruct> Output;
+
+private:
+ using DecomposerTy =
+ tomp::ConstructDecompositionT<omp::Clause, ExtConstructDecomposition>;
+ std::unique_ptr<DecomposerTy> Decomposer;
+
+ ExtConstruct &getConstruct(OpenMPDirectiveKind Leaf);
+};
+} // namespace clang
+
+#endif // CLANG_SEMA_SEMAOPENMPEXT_H
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 183c29d607f8c0..db644635c1e43b 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -9233,32 +9233,31 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
}
}
StmtResult AssociatedStmt;
- if (D->hasAssociatedStmt() && D->getAssociatedStmt()) {
- getDerived().getSema().OpenMP().ActOnOpenMPRegionStart(
- D->getDirectiveKind(),
- /*CurScope=*/nullptr);
- StmtResult Body;
- {
- Sema::CompoundScopeRAII CompoundScope(getSema());
- Stmt *CS;
- if (D->getDirectiveKind() == OMPD_atomic ||
- D->getDirectiveKind() == OMPD_critical ||
- D->getDirectiveKind() == OMPD_section ||
- D->getDirectiveKind() == OMPD_master)
- CS = D->getAssociatedStmt();
- else
- CS = D->getRawStmt();
- Body = getDerived().TransformStmt(CS);
- if (Body.isUsable() && isOpenMPLoopDirective(D->getDirectiveKind()) &&
- getSema().getLangOpts().OpenMPIRBuilder)
- Body = getDerived().RebuildOMPCanonicalLoop(Body.get());
- }
- AssociatedStmt =
- getDerived().getSema().OpenMP().ActOnOpenMPRegionEnd(Body, TClauses);
- if (AssociatedStmt.isInvalid()) {
- return StmtError();
- }
- }
+ bool HasAssociatedStatement =
+ D->hasAssociatedStmt() && D->getAssociatedStmt();
+ getDerived().getSema().OpenMP().ActOnOpenMPRegionStart(
+ D->getDirectiveKind(), /*CurScope=*/nullptr, HasAssociatedStatement);
+ if (HasAssociatedStatement) {
+ Sema::CompoundScopeRAII CompoundScope(getSema());
+ Stmt *CS;
+ if (D->getDirectiveKind() == OMPD_atomic ||
+ D->getDirectiveKind() == OMPD_critical ||
+ D->getDirectiveKind() == OMPD_section ||
+ D->getDirectiveKind() == OMPD_master)
+ CS = D->getAssociatedStmt();
+ else
+ CS = D->getRawStmt();
+ AssociatedStmt = getDerived().TransformStmt(CS);
+ if (AssociatedStmt.isUsable() &&
+ isOpenMPLoopDirective(D->getDirectiveKind()) &&
+ getSema().getLangOpts().OpenMPIRBuilder)
+ AssociatedStmt =
+ getDerived().RebuildOMPCanonicalLoop(AssociatedStmt.get());
+ }
+ AssociatedStmt = getDerived().getSema().OpenMP().ActOnOpenMPRegionEnd(
+ AssociatedStmt, TClauses);
+ if (AssociatedStmt.isInvalid())
+ return StmtError();
if (TClauses.size() != Clauses.size()) {
return StmtError();
}
@@ -9321,23 +9320,21 @@ StmtResult TreeTransform<Derived>::TransformOMPInformationalDirective(
}
}
StmtResult AssociatedStmt;
- if (D->hasAssociatedStmt() && D->getAssociatedStmt()) {
- getDerived().getSema().OpenMP().ActOnOpenMPRegionStart(
- D->getDirectiveKind(),
- /*CurScope=*/nullptr);
- StmtResult Body;
- {
- Sema::CompoundScopeRAII CompoundScope(getSema());
- assert(D->getDirectiveKind() == OMPD_assume &&
- "Unexpected informational directive");
- Stmt *CS = D->getAssociatedStmt();
- Body = getDerived().TransformStmt(CS);
- }
- AssociatedStmt =
- getDerived().getSema().OpenMP().ActOnOpenMPRegionEnd(Body, TClauses);
- if (AssociatedStmt.isInvalid())
- return StmtError();
- }
+ bool HasAssociatedStatement =
+ D->hasAssociatedStmt() && D->getAssociatedStmt();
+ getDerived().getSema().OpenMP().ActOnOpenMPRegionStart(
+ D->getDirectiveKind(), /*CurScope=*/nullptr, HasAssociatedStatement);
+ if (HasAssociatedStatement) {
+ Sema::CompoundScopeRAII CompoundScope(getSema());
+ assert(D->getDirectiveKind() == OMPD_assume &&
+ "Unexpected informational directive");
+ Stmt *CS = D->getAssociatedStmt();
+ AssociatedStmt = getDerived().TransformStmt(CS);
+ }
+ AssociatedStmt = getDerived().getSema().OpenMP().ActOnOpenMPRegionEnd(
+ AssociatedStmt, TClauses);
+ if (AssociatedStmt.isInvalid())
+ return StmtError();
if (TClauses.size() != Clauses.size())
return StmtError();
diff --git a/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h b/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h
index b93bc594a82bf3..e15f78909d6b0a 100644
--- a/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h
+++ b/llvm/include/llvm/Frontend/OpenMP/ConstructDecompositionT.h
@@ -75,10 +75,11 @@ namespace tomp {
// HelperType - A class that implements two member functions:
//
// // Return the base object of the given object, if any.
-// std::optional<Object> getBaseObject(const Object &object) const
+// - std::optional<Object> getBaseObject(const Object &object) const
// // Return the iteration variable of the outermost loop associated
// // with the construct being worked on, if any.
-// std::optional<Object> getLoopIterVar() const
+// - std::optional<Object> getLoopIterVar() const
+//
template <typename ClauseType, typename HelperType>
struct ConstructDecompositionT {
using ClauseTy = ClauseType;
@@ -93,8 +94,9 @@ struct ConstructDecompositionT {
ConstructDecompositionT(uint32_t ver, HelperType &helper,
llvm::omp::Directive dir,
- llvm::ArrayRef<ClauseTy> clauses)
- : version(ver), construct(dir), helper(helper) {
+ llvm::ArrayRef<ClauseTy> clauses,
+ bool makeImplicit = true)
+ : version(ver), construct(dir), makeImplicit(makeImplicit), helper(helper) {
for (const ClauseTy &clause : clauses)
nodes.push_back(&clause);
@@ -114,6 +116,15 @@ struct ConstructDecompositionT {
}
}
+ // Apply a clause to the prior split.
+ // Note that in some cases the order in which clauses are processed
+ // is important (e.g. linear, allocate). This function will simply process
+ // the clause as per OpenMP rules for clauses on compound constructs.
+ // NOTE: In order for this function to work, the caller must keep alive
+ // the original clauses (passed to the constructor as `clauses`), and any
+ // clauses passed to prior calls to postApply.
+ bool postApply(const ClauseTy &clause);
+
tomp::ListT<DirectiveWithClauses<ClauseType>> output;
private:
@@ -242,6 +253,7 @@ struct ConstructDecompositionT {
uint32_t version;
llvm::omp::Directive construct;
+ bool makeImplicit; // Whether to create implicit clauses.
HelperType &helper;
ListT<LeafReprInternal> leafs;
tomp::ListT<const ClauseTy *> nodes;
@@ -539,7 +551,7 @@ bool ConstructDecompositionT<C, H>::applyClause(
dirDistribute->clauses.push_back(node);
applied = true;
// [5.2:340:17]
- if (dirTeams != nullptr) {
+ if (makeImplicit && dirTeams != nullptr) {
auto *shared = makeClause(
llvm::omp::Clause::OMPC_shared,
tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/clause.v});
@@ -580,7 +592,7 @@ bool ConstructDecompositionT<C, H>::applyClause(
if (dirTaskloop == nullptr && dirWorksharing == nullptr) {
dirParallel->clauses.push_back(node);
applied = true;
- } else {
+ } else if (makeImplicit) {
// [5.2:340:15]
auto *shared = makeClause(
llvm::omp::Clause::OMPC_shared,
@@ -607,10 +619,17 @@ bool ConstructDecompositionT<C, H>::applyClause(
return !inLastprivate(object) && !mapBases.count(object.id());
});
if (!objects.empty()) {
- auto *firstp = makeClause(
- llvm::omp::Clause::OMPC_firstprivate,
- tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>{/*List=*/objects});
- dirTarget->clauses.push_back(firstp);
+ if (objects.size() == clause.v.size()) {
+ // If copied everything, then just add the original clause.
+ dirTarget->clauses.push_back(node);
+ } else {
+ auto *firstp =
+ makeClause(llvm::omp::Clause::OMPC_firstprivate,
+ tomp::clause::FirstprivateT<TypeTy, IdTy, ExprTy>{
+ /*List=*/objects});
+ addClauseSymsToMap(objects, firstp);
+ dirTarget->clauses.push_back(firstp);
+ }
applied = true;
}
}
@@ -654,6 +673,9 @@ bool ConstructDecompositionT<C, H>::applyClause(
if (!applied)
return false;
+ if (!makeImplicit)
+ return applied;
+
auto inFirstprivate = [&](const ObjectTy &object) {
if (ClauseSet *set = findClausesWith(object)) {
return llvm::find_if(*set, [](const ClauseTy *c) {
@@ -678,7 +700,6 @@ bool ConstructDecompositionT<C, H>::applyClause(
llvm::omp::Clause::OMPC_shared,
tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
dirParallel->clauses.push_back(shared);
- applied = true;
}
// [5.2:340:24]
@@ -687,7 +708,6 @@ bool ConstructDecompositionT<C, H>::applyClause(
llvm::omp::Clause::OMPC_shared,
tomp::clause::SharedT<TypeTy, IdTy, ExprTy>{/*List=*/sharedObjects});
dirTeams->clauses.push_back(shared);
- applied = true;
}
}
@@ -707,9 +727,9 @@ bool ConstructDecompositionT<C, H>::applyClause(
{/*MapType=*/MapType::Tofrom,
/*MapTypeModifier=*/std::nullopt,
/*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
- /*LocatorList=*/std::move(tofrom)}});
+ /*LocatorList=*/tofrom}});
+ addClauseSymsToMap(tofrom, map);
dirTarget->clauses.push_back(map);
- applied = true;
}
}
@@ -793,7 +813,7 @@ bool ConstructDecompositionT<C, H>::applyClause(
// assigned to which leaf constructs.
// [5.2:340:33]
- auto canMakePrivateCopy = [](llvm::omp::Clause id) {
+ auto hasPrivatizationProperty = [](llvm::omp::Clause id) {
switch (id) {
// Clauses with "privatization" property:
case llvm::omp::Clause::OMPC_firstprivate:
@@ -809,9 +829,20 @@ bool ConstructDecompositionT<C, H>::applyClause(
}
};
+ using Allocate = tomp::clause::AllocateT<TypeTy, IdTy, ExprTy>;
+ auto &objects = std::get<typename Allocate::List>(clause.t);
+
bool applied = applyIf(node, [&](const auto &leaf) {
return llvm::any_of(leaf.clauses, [&](const ClauseTy *n) {
- return canMakePrivateCopy(n->id);
+ if (!hasPrivatizationProperty(n->id))
+ return false;
+ for (auto &object : objects) {
+ if (auto *clauses = findClausesWith(object)) {
+ if (clauses->count(n))
+ return true;
+ }
+ }
+ return false;
});
});
@@ -909,12 +940,13 @@ bool ConstructDecompositionT<C, H>::applyClause(
llvm_unreachable("Unexpected modifier");
};
- auto *unmodified = makeClause(
+ auto *demodified = makeClause(
llvm::omp::Clause::OMPC_reduction,
ReductionTy{
{/*ReductionModifier=*/std::nullopt,
/*ReductionIdentifiers=*/std::get<ReductionIdentifiers>(clause.t),
/*List=*/objects}});
+ addClauseSymsToMap(objects, demodified);
ReductionModifier effective =
modifier.has_value() ? *modifier : ReductionModifier::Default;
@@ -935,14 +967,14 @@ bool ConstructDecompositionT<C, H>::applyClause(
effectiveApplied = true;
} else {
// Apply clause without modifier.
- leaf.clauses.push_back(unmodified);
+ leaf.clauses.push_back(demodified);
}
// The modifier must be applied to some construct.
applied = effectiveApplied;
}
- if (!applied)
- return false;
+ if (!applied || !makeImplicit)
+ return applied;
tomp::ObjectListT<IdTy, ExprTy> sharedObjects;
llvm::transform(objects, std::back_inserter(sharedObjects),
@@ -985,8 +1017,8 @@ bool ConstructDecompositionT<C, H>::applyClause(
tomp::clause::MapT<TypeTy, IdTy, ExprTy>{
{/*MapType=*/MapType::Tofrom, /*MapTypeModifier=*/std::nullopt,
/*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
- /*LocatorList=*/std::move(tofrom)}});
-
+ /*LocatorList=*/tofrom}});
+ addClauseSymsToMap(tofrom, map);
dirTarget->clauses.push_back(map);
applied = true;
}
@@ -1017,14 +1049,16 @@ bool ConstructDecompositionT<C, H>::applyClause(
if (modifier) {
llvm::omp::Directive dirId = *modifier;
- auto *unmodified =
+ if (!isAllowedClauseForDirective(dirId, node->id, version))
+ return false;
+ auto *demodified =
makeClause(llvm::omp::Clause::OMPC_if,
tomp::clause::IfT<TypeTy, IdTy, ExprTy>{
{/*DirectiveNameModifier=*/std::nullopt,
/*IfExpression=*/std::get<IfExpression>(clause.t)}});
if (auto *hasDir = findDirective(dirId)) {
- hasDir->clauses.push_back(unmodified);
+ hasDir->clauses.push_back(demodified);
return true;
}
return false;
@@ -1057,6 +1091,8 @@ bool ConstructDecompositionT<C, H>::applyClause(
// [5.2:341:15.1]
if (!applyToInnermost(node))
return false;
+ if (!makeImplicit)
+ return true;
// [5.2:341:15.2], [5.2:341:19]
auto dirSimd = findDirective(llvm::omp::Directive::OMPD_simd);
@@ -1176,6 +1212,28 @@ template <typename C, typename H> bool ConstructDecompositionT<C, H>::split() {
return success;
}
+template <typename C, typename H>
+bool ConstructDecompositionT<C, H>::postApply(const ClauseTy &clause) {
+ nodes.push_back(&clause);
+ addClauseSymsToMap(clause, &clause);
+ if (output.size() == 0)
+ return false;
+
+ bool success =
+ std::visit([&](auto &&s) { return applyClause(s, &clause); }, clause.u);
+
+ // Transfer the updates to the clause lists to the output.
+ assert(output.size() == leafs.size() && "Internal lists differ in lengths");
+ for (size_t i = 0, e = output.size(); i != e; ++i) {
+ auto &leaf = leafs[i];
+ auto &out = output[i];
+ assert(leaf.clauses.size() >= out.clauses.size() &&
+ "Output longer than internal worklist");
+ for (size_t j = out.clauses.size(), f = leaf.clauses.size(); j != f; ++j)
+ out.clauses.push_back(*leaf.clauses[j]);
+ }
+ return success;
+}
} // namespace tomp
#endif // LLVM_FRONTEND_OPENMP_CONSTRUCTDECOMPOSITIONT_H
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.h b/llvm/include/llvm/Frontend/OpenMP/OMP.h
index 54ae672755ba89..985b98f6c13ead 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.h
@@ -32,6 +32,8 @@ bool isLeafConstruct(Directive D);
bool isCompositeConstruct(Directive D);
bool isCombinedConstruct(Directive D);
+bool isUniqueClause(Clause C);
+
/// Create a nicer version of a function name for humans to look at.
std::string prettifyFunctionName(StringRef FunctionName);
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 1f747df43eeb80..b7097431025080 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -970,6 +970,7 @@ def OMP_Target : Directive<"target"> {
VersionedClause<OMPC_IsDevicePtr>,
VersionedClause<OMPC_Map>,
VersionedClause<OMPC_OMPX_Attribute>,
+ VersionedClause<OMPC_OMPX_Bare>,
VersionedClause<OMPC_Private>,
VersionedClause<OMPC_UsesAllocators, 50>,
];
diff --git a/llvm/lib/Frontend/OpenMP/OMP.cpp b/llvm/lib/Frontend/OpenMP/OMP.cpp
index 5720655442be3d..8e804abd1c1812 100644
--- a/llvm/lib/Frontend/OpenMP/OMP.cpp
+++ b/llvm/lib/Frontend/OpenMP/OMP.cpp
@@ -193,6 +193,60 @@ bool isCombinedConstruct(Directive D) {
return !getLeafConstructs(D).empty() && !isCompositeConstruct(D);
}
+bool isUniqueClause(Clause C) {
+ switch (C) {
+ case OMPC_affinity:
+ case OMPC_align:
+ case OMPC_allocator:
+ case OMPC_append_args:
+ case OMPC_at:
+ case OMPC_bind:
+ case OMPC_collapse:
+ case OMPC_default:
+ case OMPC_defaultmap:
+ case OMPC_detach:
+ case OMPC_device:
+ case OMPC_device_type:
+ case OMPC_dist_schedule:
+ case OMPC_exclusive:
+ case OMPC_filter:
+ case OMPC_final:
+ case OMPC_full:
+ case OMPC_grainsize:
+ case OMPC_hint:
+ case OMPC_inclusive:
+ case OMPC_indirect:
+ // case OMPC_initializer: present in spec, but not defined in header
+ case OMPC_match:
+ case OMPC_mergeable:
+ case OMPC_message:
+ // case OMPC_nocontext: present in spec, but not defined in header
+ case OMPC_nogroup:
+ case OMPC_novariants:
+ case OMPC_nowait:
+ case OMPC_num_tasks:
+ case OMPC_num_teams:
+ case OMPC_num_threads:
+ case OMPC_order:
+ case OMPC_ordered:
+ // case OMPC_otherwise: present in spec, but not defined in header
+ case OMPC_partial:
+ case OMPC_priority:
+ case OMPC_proc_bind:
+ case OMPC_safelen:
+ case OMPC_schedule:
+ case OMPC_severity:
+ case OMPC_simdlen:
+ case OMPC_sizes:
+ case OMPC_thread_limit:
+ case OMPC_untied:
+ case OMPC_update:
+ return true;
+ default:
+ return false;
+ }
+}
+
std::string prettifyFunctionName(StringRef FunctionName) {
// Internalized functions have the right name, but simply a suffix.
if (FunctionName.ends_with(".internalized"))
More information about the llvm-branch-commits
mailing list