aboutsummaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOpenMP.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Sema/SemaOpenMP.cpp')
-rw-r--r--lib/Sema/SemaOpenMP.cpp1880
1 files changed, 1597 insertions, 283 deletions
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index bd68011c18b2..c7e0d2aee036 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -139,6 +139,7 @@ private:
/// clause, false otherwise.
llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
unsigned AssociatedLoops = 1;
+ bool HasMutipleLoops = false;
const Decl *PossiblyLoopCounter = nullptr;
bool NowaitRegion = false;
bool CancelRegion = false;
@@ -169,7 +170,7 @@ private:
OpenMPClauseKind ClauseKindMode = OMPC_unknown;
Sema &SemaRef;
bool ForceCapturing = false;
- /// true if all the vaiables in the target executable directives must be
+ /// true if all the variables in the target executable directives must be
/// captured by reference.
bool ForceCaptureByReferenceInTargetExecutable = false;
CriticalsWithHintsTy Criticals;
@@ -521,6 +522,13 @@ public:
assert(!isStackEmpty() && "No directive at specified level.");
return getStackElemAtLevel(Level).Directive;
}
+ /// Returns the capture region at the specified level.
+ OpenMPDirectiveKind getCaptureRegion(unsigned Level,
+ unsigned OpenMPCaptureLevel) const {
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, getDirective(Level));
+ return CaptureRegions[OpenMPCaptureLevel];
+ }
/// Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
const SharingMapTy *Parent = getSecondOnStackOrNull();
@@ -678,12 +686,19 @@ public:
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
getTopOfStack().AssociatedLoops = Val;
+ if (Val > 1)
+ getTopOfStack().HasMutipleLoops = true;
}
/// Return collapse value for region.
unsigned getAssociatedLoops() const {
const SharingMapTy *Top = getTopOfStackOrNull();
return Top ? Top->AssociatedLoops : 0;
}
+ /// Returns true if the construct is associated with multiple loops.
+ bool hasMutipleLoops() const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->HasMutipleLoops : false;
+ }
/// Marks current target region as one with closely nested teams
/// region.
@@ -951,7 +966,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
// In a parallel construct, if no default clause is present, these
// variables are shared.
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
- if (isOpenMPParallelDirective(DVar.DKind) ||
+ if ((isOpenMPParallelDirective(DVar.DKind) &&
+ !isOpenMPTaskLoopDirective(DVar.DKind)) ||
isOpenMPTeamsDirective(DVar.DKind)) {
DVar.CKind = OMPC_shared;
return DVar;
@@ -1332,7 +1348,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
}
const_iterator End = end();
if (!SemaRef.isOpenMPCapturedByRef(
- D, std::distance(ParentIterTarget, End))) {
+ D, std::distance(ParentIterTarget, End),
+ /*OpenMPCaptureLevel=*/0)) {
DVar.RefExpr =
buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
IterTarget->ConstructLoc);
@@ -1540,49 +1557,150 @@ static bool isOpenMPDeviceDelayedContext(Sema &S) {
!S.isInOpenMPDeclareTargetContext();
}
-/// Do we know that we will eventually codegen the given function?
-static bool isKnownEmitted(Sema &S, FunctionDecl *FD) {
- assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
- "Expected OpenMP device compilation.");
- // Templates are emitted when they're instantiated.
- if (FD->isDependentContext())
- return false;
-
- if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
- FD->getCanonicalDecl()))
- return true;
-
- // Otherwise, the function is known-emitted if it's in our set of
- // known-emitted functions.
- return S.DeviceKnownEmittedFns.count(FD) > 0;
-}
+namespace {
+/// Status of the function emission on the host/device.
+enum class FunctionEmissionStatus {
+ Emitted,
+ Discarded,
+ Unknown,
+};
+} // anonymous namespace
Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
- return DeviceDiagBuilder((isOpenMPDeviceDelayedContext(*this) &&
- !isKnownEmitted(*this, getCurFunctionDecl()))
- ? DeviceDiagBuilder::K_Deferred
- : DeviceDiagBuilder::K_Immediate,
- Loc, DiagID, getCurFunctionDecl(), *this);
+ FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+ DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred
+ : DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ case FunctionEmissionStatus::CUDADiscarded:
+ llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
+ break;
+ }
+
+ return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
}
-void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
+Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc,
+ unsigned DiagID) {
+ assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP host compilation.");
+ FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+ DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = DeviceDiagBuilder::K_Deferred;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ case FunctionEmissionStatus::CUDADiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ }
+
+ return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
+}
+
+void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckForDelayedContext) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
assert(Callee && "Callee may not be null.");
+ Callee = Callee->getMostRecentDecl();
FunctionDecl *Caller = getCurFunctionDecl();
+ // host only function are not available on the device.
+ if (Caller) {
+ FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
+ FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
+ assert(CallerS != FunctionEmissionStatus::CUDADiscarded &&
+ CalleeS != FunctionEmissionStatus::CUDADiscarded &&
+ "CUDADiscarded unexpected in OpenMP device function check");
+ if ((CallerS == FunctionEmissionStatus::Emitted ||
+ (!isOpenMPDeviceDelayedContext(*this) &&
+ CallerS == FunctionEmissionStatus::Unknown)) &&
+ CalleeS == FunctionEmissionStatus::OMPDiscarded) {
+ StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
+ Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ return;
+ }
+ }
// If the caller is known-emitted, mark the callee as known-emitted.
// Otherwise, mark the call in our call graph so we can traverse it later.
- if (!isOpenMPDeviceDelayedContext(*this) ||
- (Caller && isKnownEmitted(*this, Caller)))
- markKnownEmitted(*this, Caller, Callee, Loc, isKnownEmitted);
+ if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) ||
+ (!Caller && !CheckForDelayedContext) ||
+ (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
+ markKnownEmitted(*this, Caller, Callee, Loc,
+ [CheckForDelayedContext](Sema &S, FunctionDecl *FD) {
+ return CheckForDelayedContext &&
+ S.getEmissionStatus(FD) ==
+ FunctionEmissionStatus::Emitted;
+ });
else if (Caller)
DeviceCallGraph[Caller].insert({Callee, Loc});
}
+void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee,
+ bool CheckCaller) {
+ assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP host compilation.");
+ assert(Callee && "Callee may not be null.");
+ Callee = Callee->getMostRecentDecl();
+ FunctionDecl *Caller = getCurFunctionDecl();
+
+ // device only function are not available on the host.
+ if (Caller) {
+ FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
+ FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
+ assert(
+ (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded &&
+ CalleeS != FunctionEmissionStatus::CUDADiscarded)) &&
+ "CUDADiscarded unexpected in OpenMP host function check");
+ if (CallerS == FunctionEmissionStatus::Emitted &&
+ CalleeS == FunctionEmissionStatus::OMPDiscarded) {
+ StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
+ Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << NoHostDevTy;
+ return;
+ }
+ }
+ // If the caller is known-emitted, mark the callee as known-emitted.
+ // Otherwise, mark the call in our call graph so we can traverse it later.
+ if (!shouldIgnoreInHostDeviceCheck(Callee)) {
+ if ((!CheckCaller && !Caller) ||
+ (Caller &&
+ getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
+ markKnownEmitted(
+ *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) {
+ return CheckCaller &&
+ S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
+ });
+ else if (Caller)
+ DeviceCallGraph[Caller].insert({Callee, Loc});
+ }
+}
+
void Sema::checkOpenMPDeviceExpr(const Expr *E) {
assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
"OpenMP device compilation mode is expected.");
@@ -1598,7 +1716,8 @@ void Sema::checkOpenMPDeviceExpr(const Expr *E) {
<< Context.getTargetInfo().getTriple().str() << E->getSourceRange();
}
-bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
+bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
+ unsigned OpenMPCaptureLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
ASTContext &Ctx = getASTContext();
@@ -1608,6 +1727,7 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
D = cast<ValueDecl>(D->getCanonicalDecl());
QualType Ty = D->getType();
+ bool IsVariableUsedInMapClause = false;
if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) {
// This table summarizes how a given variable should be passed to the device
// given its type and the clauses where it appears. This table is based on
@@ -1669,7 +1789,6 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
// Locate map clauses and see if the variable being captured is referred to
// in any of those clauses. Here we only care about variables, not fields,
// because fields are part of aggregates.
- bool IsVariableUsedInMapClause = false;
bool IsVariableAssociatedWithSection = false;
DSAStack->checkMappableExprComponentListsForDeclAtLevel(
@@ -1727,10 +1846,13 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
IsByRef =
- !DSAStack->hasExplicitDSA(
- D,
- [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
- Level, /*NotLastprivate=*/true) &&
+ ((IsVariableUsedInMapClause &&
+ DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) ==
+ OMPD_target) ||
+ !DSAStack->hasExplicitDSA(
+ D,
+ [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
+ Level, /*NotLastprivate=*/true)) &&
// If the variable is artificial and must be captured by value - try to
// capture by value.
!(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
@@ -1788,7 +1910,8 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
if (isInOpenMPDeclareTargetContext()) {
// Try to mark variable as declare target if it is used in capturing
// regions.
- if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
+ if (LangOpts.OpenMP <= 45 &&
+ !OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
checkDeclIsAllowedInOpenMPTarget(nullptr, VD);
return nullptr;
} else if (isInOpenMPTargetExecutionDirective()) {
@@ -1858,6 +1981,14 @@ void Sema::startOpenMPLoop() {
DSAStack->loopInit();
}
+void Sema::startOpenMPCXXRangeFor() {
+ assert(LangOpts.OpenMP && "OpenMP must be enabled.");
+ if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
+ DSAStack->resetPossibleLoopCounter();
+ DSAStack->loopStart();
+ }
+}
+
bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
@@ -1874,6 +2005,13 @@ bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
!isOpenMPSimdDirective(DSAStack->getCurrentDirective()))
return true;
}
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) &&
+ DSAStack->isForceVarCapturing() &&
+ !DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level))
+ return true;
+ }
return DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
(DSAStack->isClauseParsingMode() &&
@@ -1937,6 +2075,54 @@ bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D,
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
+void Sema::finalizeOpenMPDelayedAnalysis() {
+ assert(LangOpts.OpenMP && "Expected OpenMP compilation mode.");
+ // Diagnose implicit declare target functions and their callees.
+ for (const auto &CallerCallees : DeviceCallGraph) {
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(
+ CallerCallees.getFirst()->getMostRecentDecl());
+ // Ignore host functions during device analyzis.
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ continue;
+ // Ignore nohost functions during host analyzis.
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ continue;
+ for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation>
+ &Callee : CallerCallees.getSecond()) {
+ const FunctionDecl *FD = Callee.first->getMostRecentDecl();
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
+ // Diagnose host function called during device codegen.
+ StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Callee.second, diag::err_omp_wrong_device_function_call)
+ << HostDevTy << 0;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ continue;
+ }
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
+ // Diagnose nohost function called during host codegen.
+ StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
+ OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
+ Diag(Callee.second, diag::err_omp_wrong_device_function_call)
+ << NoHostDevTy << 1;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << NoHostDevTy;
+ continue;
+ }
+ }
+ }
+}
+
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
@@ -2034,7 +2220,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<VarDeclFilterCCC>(*this);
+ return std::make_unique<VarDeclFilterCCC>(*this);
}
};
@@ -2056,7 +2242,7 @@ public:
}
std::unique_ptr<CorrectionCandidateCallback> clone() override {
- return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this);
+ return std::make_unique<VarOrFuncDeclFilterCCC>(*this);
}
};
@@ -2944,18 +3130,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTarget);
+ ParamsTarget, /*OpenMPCaptureLevel=*/1);
Sema::CapturedParamNameType ParamsTeamsOrParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
@@ -2964,7 +3151,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeamsOrParallel);
+ ParamsTeamsOrParallel, /*OpenMPCaptureLevel=*/2);
break;
}
case OMPD_target:
@@ -2988,14 +3175,16 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- std::make_pair(StringRef(), QualType()));
+ std::make_pair(StringRef(), QualType()),
+ /*OpenMPCaptureLevel=*/1);
break;
}
case OMPD_simd:
@@ -3044,11 +3233,14 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_taskloop:
- case OMPD_taskloop_simd: {
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd: {
QualType KmpInt32Ty =
Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
.withConst();
@@ -3086,7 +3278,58 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
+ break;
+ }
+ case OMPD_parallel_master_taskloop: {
+ QualType KmpInt32Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1)
+ .withConst();
+ QualType KmpUInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0)
+ .withConst();
+ QualType KmpInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1)
+ .withConst();
+ QualType VoidPtrTy = Context.VoidPtrTy.withConst().withRestrict();
+ QualType KmpInt32PtrTy =
+ Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+ Sema::CapturedParamNameType ParamsParallel[] = {
+ std::make_pair(".global_tid.", KmpInt32PtrTy),
+ std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ // Start a captured region for 'parallel'.
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ ParamsParallel, /*OpenMPCaptureLevel=*/1);
+ QualType Args[] = {VoidPtrTy};
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = true;
+ QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
+ Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".global_tid.", KmpInt32Ty),
+ std::make_pair(".part_id.", KmpInt32PtrTy),
+ std::make_pair(".privates.", VoidPtrTy),
+ std::make_pair(
+ ".copy_fn.",
+ Context.getPointerType(CopyFnType).withConst().withRestrict()),
+ std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
+ std::make_pair(".lb.", KmpUInt64Ty),
+ std::make_pair(".ub.", KmpUInt64Ty),
+ std::make_pair(".st.", KmpInt64Ty),
+ std::make_pair(".liter.", KmpInt32Ty),
+ std::make_pair(".reductions.", VoidPtrTy),
+ std::make_pair(StringRef(), QualType()) // __context with shared vars
+ };
+ ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
+ Params, /*OpenMPCaptureLevel=*/2);
+ // Mark this captured region as inlined, because we don't use outlined
+ // function directly.
+ getCurCapturedRegion()->TheCapturedDecl->addAttr(
+ AlwaysInlineAttr::CreateImplicit(
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_distribute_parallel_for_simd:
@@ -3127,18 +3370,19 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
+ Params, /*OpenMPCaptureLevel=*/0);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
Sema::CapturedParamNameType ParamsTarget[] = {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTarget);
+ ParamsTarget, /*OpenMPCaptureLevel=*/1);
Sema::CapturedParamNameType ParamsTeams[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3147,7 +3391,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeams);
+ ParamsTeams, /*OpenMPCaptureLevel=*/2);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3159,7 +3403,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel);
+ ParamsParallel, /*OpenMPCaptureLevel=*/3);
break;
}
@@ -3176,7 +3420,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'target' with no implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsTeams);
+ ParamsTeams, /*OpenMPCaptureLevel=*/0);
Sema::CapturedParamNameType ParamsParallel[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
@@ -3188,7 +3432,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// Start a captured region for 'teams' or 'parallel'. Both regions have
// the same implicit parameters.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel);
+ ParamsParallel, /*OpenMPCaptureLevel=*/1);
break;
}
case OMPD_target_update:
@@ -3218,7 +3462,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
AlwaysInlineAttr::CreateImplicit(
- Context, AlwaysInlineAttr::Keyword_forceinline));
+ Context, {}, AttributeCommonInfo::AS_Keyword,
+ AlwaysInlineAttr::Keyword_forceinline));
break;
}
case OMPD_threadprivate:
@@ -3235,12 +3480,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_requires:
+ case OMPD_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
}
+int Sema::getNumberOfConstructScopes(unsigned Level) const {
+ return getOpenMPCaptureLevels(DSAStack->getDirective(Level));
+}
+
int Sema::getOpenMPCaptureLevels(OpenMPDirectiveKind DKind) {
SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
getOpenMPCaptureRegions(CaptureRegions, DKind);
@@ -3670,7 +3920,10 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
// OpenMP [2.16, Nesting of Regions]
// If specified, a teams construct must be contained within a target
// construct.
- NestingProhibited = ParentRegion != OMPD_target;
+ NestingProhibited =
+ (SemaRef.LangOpts.OpenMP <= 45 && ParentRegion != OMPD_target) ||
+ (SemaRef.LangOpts.OpenMP >= 50 && ParentRegion != OMPD_unknown &&
+ ParentRegion != OMPD_target);
OrphanSeen = ParentRegion == OMPD_unknown;
Recommend = ShouldBeInTargetRegion;
}
@@ -4214,6 +4467,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
EndLoc, VarsWithInheritedDSA);
AllowedNameModifiers.push_back(OMPD_taskloop);
break;
+ case OMPD_master_taskloop:
+ Res = ActOnOpenMPMasterTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_master_taskloop_simd:
+ Res = ActOnOpenMPMasterTaskLoopSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ break;
+ case OMPD_parallel_master_taskloop:
+ Res = ActOnOpenMPParallelMasterTaskLoopDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_taskloop);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
case OMPD_distribute:
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
@@ -4301,6 +4570,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_requires:
+ case OMPD_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -4326,18 +4596,22 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
continue;
case OMPC_schedule:
break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_final:
+ case OMPC_priority:
+ // Do not analyze if no parent parallel directive.
+ if (isOpenMPParallelDirective(DSAStack->getCurrentDirective()))
+ break;
+ continue;
case OMPC_ordered:
case OMPC_device:
case OMPC_num_teams:
case OMPC_thread_limit:
- case OMPC_priority:
- case OMPC_grainsize:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_collapse:
case OMPC_safelen:
case OMPC_simdlen:
- case OMPC_final:
case OMPC_default:
case OMPC_proc_bind:
case OMPC_private:
@@ -4381,6 +4655,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Unexpected clause");
}
for (Stmt *CC : C->children()) {
@@ -4437,8 +4713,10 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
if (!DG || DG.get().isNull())
return DeclGroupPtrTy();
+ const int SimdId = 0;
if (!DG.get().isSingleDecl()) {
- Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd);
+ Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant)
+ << SimdId;
return DG;
}
Decl *ADecl = DG.get().getSingleDecl();
@@ -4447,7 +4725,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
auto *FD = dyn_cast<FunctionDecl>(ADecl);
if (!FD) {
- Diag(ADecl->getLocation(), diag::err_omp_function_expected);
+ Diag(ADecl->getLocation(), diag::err_omp_function_expected) << SimdId;
return DeclGroupPtrTy();
}
@@ -4669,7 +4947,266 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(),
NewSteps.data(), NewSteps.size(), SR);
ADecl->addAttr(NewAttr);
- return ConvertDeclToDeclGroup(ADecl);
+ return DG;
+}
+
+Optional<std::pair<FunctionDecl *, Expr *>>
+Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
+ Expr *VariantRef, SourceRange SR) {
+ if (!DG || DG.get().isNull())
+ return None;
+
+ const int VariantId = 1;
+ // Must be applied only to single decl.
+ if (!DG.get().isSingleDecl()) {
+ Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd_variant)
+ << VariantId << SR;
+ return None;
+ }
+ Decl *ADecl = DG.get().getSingleDecl();
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
+ ADecl = FTD->getTemplatedDecl();
+
+ // Decl must be a function.
+ auto *FD = dyn_cast<FunctionDecl>(ADecl);
+ if (!FD) {
+ Diag(ADecl->getLocation(), diag::err_omp_function_expected)
+ << VariantId << SR;
+ return None;
+ }
+
+ auto &&HasMultiVersionAttributes = [](const FunctionDecl *FD) {
+ return FD->hasAttrs() &&
+ (FD->hasAttr<CPUDispatchAttr>() || FD->hasAttr<CPUSpecificAttr>() ||
+ FD->hasAttr<TargetAttr>());
+ };
+ // OpenMP is not compatible with CPU-specific attributes.
+ if (HasMultiVersionAttributes(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_incompat_attributes)
+ << SR;
+ return None;
+ }
+
+ // Allow #pragma omp declare variant only if the function is not used.
+ if (FD->isUsed(false))
+ Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_used)
+ << FD->getLocation();
+
+ // Check if the function was emitted already.
+ const FunctionDecl *Definition;
+ if (!FD->isThisDeclarationADefinition() && FD->isDefined(Definition) &&
+ (LangOpts.EmitAllDecls || Context.DeclMustBeEmitted(Definition)))
+ Diag(SR.getBegin(), diag::warn_omp_declare_variant_after_emitted)
+ << FD->getLocation();
+
+ // The VariantRef must point to function.
+ if (!VariantRef) {
+ Diag(SR.getBegin(), diag::err_omp_function_expected) << VariantId;
+ return None;
+ }
+
+ // Do not check templates, wait until instantiation.
+ if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() ||
+ VariantRef->containsUnexpandedParameterPack() ||
+ VariantRef->isInstantiationDependent() || FD->isDependentContext())
+ return std::make_pair(FD, VariantRef);
+
+ // Convert VariantRef expression to the type of the original function to
+ // resolve possible conflicts.
+ ExprResult VariantRefCast;
+ if (LangOpts.CPlusPlus) {
+ QualType FnPtrType;
+ auto *Method = dyn_cast<CXXMethodDecl>(FD);
+ if (Method && !Method->isStatic()) {
+ const Type *ClassType =
+ Context.getTypeDeclType(Method->getParent()).getTypePtr();
+ FnPtrType = Context.getMemberPointerType(FD->getType(), ClassType);
+ ExprResult ER;
+ {
+ // Build adrr_of unary op to correctly handle type checks for member
+ // functions.
+ Sema::TentativeAnalysisScope Trap(*this);
+ ER = CreateBuiltinUnaryOp(VariantRef->getBeginLoc(), UO_AddrOf,
+ VariantRef);
+ }
+ if (!ER.isUsable()) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+ VariantRef = ER.get();
+ } else {
+ FnPtrType = Context.getPointerType(FD->getType());
+ }
+ ImplicitConversionSequence ICS =
+ TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(),
+ /*SuppressUserConversions=*/false,
+ /*AllowExplicit=*/false,
+ /*InOverloadResolution=*/false,
+ /*CStyle=*/false,
+ /*AllowObjCWritebackConversion=*/false);
+ if (ICS.isFailure()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::err_omp_declare_variant_incompat_types)
+ << VariantRef->getType() << FnPtrType << VariantRef->getSourceRange();
+ return None;
+ }
+ VariantRefCast = PerformImplicitConversion(
+ VariantRef, FnPtrType.getUnqualifiedType(), AA_Converting);
+ if (!VariantRefCast.isUsable())
+ return None;
+ // Drop previously built artificial addr_of unary op for member functions.
+ if (Method && !Method->isStatic()) {
+ Expr *PossibleAddrOfVariantRef = VariantRefCast.get();
+ if (auto *UO = dyn_cast<UnaryOperator>(
+ PossibleAddrOfVariantRef->IgnoreImplicit()))
+ VariantRefCast = UO->getSubExpr();
+ }
+ } else {
+ VariantRefCast = VariantRef;
+ }
+
+ ExprResult ER = CheckPlaceholderExpr(VariantRefCast.get());
+ if (!ER.isUsable() ||
+ !ER.get()->IgnoreParenImpCasts()->getType()->isFunctionType()) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+
+ // The VariantRef must point to function.
+ auto *DRE = dyn_cast<DeclRefExpr>(ER.get()->IgnoreParenImpCasts());
+ if (!DRE) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+ auto *NewFD = dyn_cast_or_null<FunctionDecl>(DRE->getDecl());
+ if (!NewFD) {
+ Diag(VariantRef->getExprLoc(), diag::err_omp_function_expected)
+ << VariantId << VariantRef->getSourceRange();
+ return None;
+ }
+
+ // Check if variant function is not marked with declare variant directive.
+ if (NewFD->hasAttrs() && NewFD->hasAttr<OMPDeclareVariantAttr>()) {
+ Diag(VariantRef->getExprLoc(),
+ diag::warn_omp_declare_variant_marked_as_declare_variant)
+ << VariantRef->getSourceRange();
+ SourceRange SR =
+ NewFD->specific_attr_begin<OMPDeclareVariantAttr>()->getRange();
+ Diag(SR.getBegin(), diag::note_omp_marked_declare_variant_here) << SR;
+ return None;
+ }
+
+ enum DoesntSupport {
+ VirtFuncs = 1,
+ Constructors = 3,
+ Destructors = 4,
+ DeletedFuncs = 5,
+ DefaultedFuncs = 6,
+ ConstexprFuncs = 7,
+ ConstevalFuncs = 8,
+ };
+ if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) {
+ if (CXXFD->isVirtual()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << VirtFuncs;
+ return None;
+ }
+
+ if (isa<CXXConstructorDecl>(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << Constructors;
+ return None;
+ }
+
+ if (isa<CXXDestructorDecl>(FD)) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << Destructors;
+ return None;
+ }
+ }
+
+ if (FD->isDeleted()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << DeletedFuncs;
+ return None;
+ }
+
+ if (FD->isDefaulted()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << DefaultedFuncs;
+ return None;
+ }
+
+ if (FD->isConstexpr()) {
+ Diag(FD->getLocation(), diag::err_omp_declare_variant_doesnt_support)
+ << (NewFD->isConsteval() ? ConstevalFuncs : ConstexprFuncs);
+ return None;
+ }
+
+ // Check general compatibility.
+ if (areMultiversionVariantFunctionsCompatible(
+ FD, NewFD, PDiag(diag::err_omp_declare_variant_noproto),
+ PartialDiagnosticAt(
+ SR.getBegin(),
+ PDiag(diag::note_omp_declare_variant_specified_here) << SR),
+ PartialDiagnosticAt(
+ VariantRef->getExprLoc(),
+ PDiag(diag::err_omp_declare_variant_doesnt_support)),
+ PartialDiagnosticAt(VariantRef->getExprLoc(),
+ PDiag(diag::err_omp_declare_variant_diff)
+ << FD->getLocation()),
+ /*TemplatesSupported=*/true, /*ConstexprSupported=*/false,
+ /*CLinkageMayDiffer=*/true))
+ return None;
+ return std::make_pair(FD, cast<Expr>(DRE));
+}
+
+void Sema::ActOnOpenMPDeclareVariantDirective(
+ FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
+ const Sema::OpenMPDeclareVariantCtsSelectorData &Data) {
+ if (Data.CtxSet == OMPDeclareVariantAttr::CtxSetUnknown ||
+ Data.Ctx == OMPDeclareVariantAttr::CtxUnknown)
+ return;
+ Expr *Score = nullptr;
+ OMPDeclareVariantAttr::ScoreType ST = OMPDeclareVariantAttr::ScoreUnknown;
+ if (Data.CtxScore.isUsable()) {
+ ST = OMPDeclareVariantAttr::ScoreSpecified;
+ Score = Data.CtxScore.get();
+ if (!Score->isTypeDependent() && !Score->isValueDependent() &&
+ !Score->isInstantiationDependent() &&
+ !Score->containsUnexpandedParameterPack()) {
+ llvm::APSInt Result;
+ ExprResult ICE = VerifyIntegerConstantExpression(Score, &Result);
+ if (ICE.isInvalid())
+ return;
+ }
+ }
+ auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
+ Context, VariantRef, Score, Data.CtxSet, ST, Data.Ctx,
+ Data.ImplVendors.begin(), Data.ImplVendors.size(), SR);
+ FD->addAttr(NewAttr);
+}
+
+void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
+ FunctionDecl *Func,
+ bool MightBeOdrUse) {
+ assert(LangOpts.OpenMP && "Expected OpenMP mode.");
+
+ if (!Func->isDependentContext() && Func->hasAttrs()) {
+ for (OMPDeclareVariantAttr *A :
+ Func->specific_attrs<OMPDeclareVariantAttr>()) {
+ // TODO: add checks for active OpenMP context where possible.
+ Expr *VariantRef = A->getVariantFuncRef();
+ auto *DRE = dyn_cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
+ auto *F = cast<FunctionDecl>(DRE->getDecl());
+ if (!F->isDefined() && F->isTemplateInstantiation())
+ InstantiateFunctionDefinition(Loc, F->getFirstDecl());
+ MarkFunctionReferenced(Loc, F, MightBeOdrUse);
+ }
+ }
}
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
@@ -4694,6 +5231,54 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
}
namespace {
+/// Iteration space of a single for loop.
+struct LoopIterationSpace final {
+ /// True if the condition operator is the strict compare operator (<, > or
+ /// !=).
+ bool IsStrictCompare = false;
+ /// Condition of the loop.
+ Expr *PreCond = nullptr;
+ /// This expression calculates the number of iterations in the loop.
+ /// It is always possible to calculate it before starting the loop.
+ Expr *NumIterations = nullptr;
+ /// The loop counter variable.
+ Expr *CounterVar = nullptr;
+ /// Private loop counter variable.
+ Expr *PrivateCounterVar = nullptr;
+ /// This is initializer for the initial value of #CounterVar.
+ Expr *CounterInit = nullptr;
+ /// This is step for the #CounterVar used to generate its update:
+ /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
+ Expr *CounterStep = nullptr;
+ /// Should step be subtracted?
+ bool Subtract = false;
+ /// Source range of the loop init.
+ SourceRange InitSrcRange;
+ /// Source range of the loop condition.
+ SourceRange CondSrcRange;
+ /// Source range of the loop increment.
+ SourceRange IncSrcRange;
+ /// Minimum value that can have the loop control variable. Used to support
+ /// non-rectangular loops. Applied only for LCV with the non-iterator types,
+ /// since only such variables can be used in non-loop invariant expressions.
+ Expr *MinValue = nullptr;
+ /// Maximum value that can have the loop control variable. Used to support
+ /// non-rectangular loops. Applied only for LCV with the non-iterator type,
+ /// since only such variables can be used in non-loop invariant expressions.
+ Expr *MaxValue = nullptr;
+ /// true, if the lower bound depends on the outer loop control var.
+ bool IsNonRectangularLB = false;
+ /// true, if the upper bound depends on the outer loop control var.
+ bool IsNonRectangularUB = false;
+ /// Index of the loop this loop depends on and forms non-rectangular loop
+ /// nest.
+ unsigned LoopDependentIdx = 0;
+ /// Final condition for the non-rectangular loop nest support. It is used to
+ /// check that the number of iterations for this particular counter must be
+ /// finished.
+ Expr *FinalCondition = nullptr;
+};
+
/// Helper class for checking canonical form of the OpenMP loops and
/// extracting iteration space of each loop in the loop nest, that will be used
/// for IR generation.
@@ -4743,6 +5328,9 @@ class OpenMPIterationSpaceChecker {
Optional<unsigned> CondDependOnLC;
/// Checks if the provide statement depends on the loop counter.
Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer);
+ /// Original condition required for checking of the exit condition for
+ /// non-rectangular loop.
+ Expr *Condition = nullptr;
public:
OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack,
@@ -4774,7 +5362,7 @@ public:
bool isStrictTestOp() const { return TestIsStrictOp; }
/// Build the expression to calculate the number of iterations.
Expr *buildNumIterations(
- Scope *S, const bool LimitedType,
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
/// Build the precondition expression for the loops.
Expr *
@@ -4798,8 +5386,21 @@ public:
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures,
SourceLocation Loc, Expr *Inc = nullptr,
OverloadedOperatorKind OOK = OO_Amp);
+ /// Builds the minimum value for the loop counter.
+ std::pair<Expr *, Expr *> buildMinMaxValues(
+ Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const;
+ /// Builds final condition for the non-rectangular loops.
+ Expr *buildFinalCondition(Scope *S) const;
/// Return true if any expression is dependent.
bool dependent() const;
+ /// Returns true if the initializer forms non-rectangular loop.
+ bool doesInitDependOnLC() const { return InitDependOnLC.hasValue(); }
+ /// Returns true if the condition forms non-rectangular loop.
+ bool doesCondDependOnLC() const { return CondDependOnLC.hasValue(); }
+ /// Returns index of the loop we depend on (starting from 1), or 0 otherwise.
+ unsigned getLoopDependentIdx() const {
+ return InitDependOnLC.getValueOr(CondDependOnLC.getValueOr(0));
+ }
private:
/// Check the right-hand side of an assignment in the increment
@@ -4998,9 +5599,9 @@ public:
return false;
}
bool VisitStmt(const Stmt *S) {
- bool Res = true;
+ bool Res = false;
for (const Stmt *Child : S->children())
- Res = Child && Visit(Child) && Res;
+ Res = (Child && Visit(Child)) || Res;
return Res;
}
explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack,
@@ -5142,14 +5743,17 @@ static const ValueDecl *getInitLCDecl(const Expr *E) {
bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
// Check test-expr for canonical form, save upper-bound UB, flags for
// less/greater and for strict/non-strict comparison.
- // OpenMP [2.6] Canonical loop form. Test-expr may be one of the following:
+ // OpenMP [2.9] Canonical loop form. Test-expr may be one of the following:
// var relational-op b
// b relational-op var
//
+ bool IneqCondIsCanonical = SemaRef.getLangOpts().OpenMP >= 50;
if (!S) {
- SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl;
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond)
+ << (IneqCondIsCanonical ? 1 : 0) << LCDecl;
return true;
}
+ Condition = S;
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getBeginLoc();
if (auto *BO = dyn_cast<BinaryOperator>(S)) {
@@ -5164,12 +5768,11 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
(BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
- } else if (BO->getOpcode() == BO_NE)
- return setUB(getInitLCDecl(BO->getLHS()) == LCDecl ?
- BO->getRHS() : BO->getLHS(),
- /*LessOp=*/llvm::None,
- /*StrictOp=*/true,
- BO->getSourceRange(), BO->getOperatorLoc());
+ } else if (IneqCondIsCanonical && BO->getOpcode() == BO_NE)
+ return setUB(
+ getInitLCDecl(BO->getLHS()) == LCDecl ? BO->getRHS() : BO->getLHS(),
+ /*LessOp=*/llvm::None,
+ /*StrictOp=*/true, BO->getSourceRange(), BO->getOperatorLoc());
} else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) {
if (CE->getNumArgs() == 2) {
auto Op = CE->getOperator();
@@ -5188,12 +5791,12 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
CE->getOperatorLoc());
break;
case OO_ExclaimEqual:
- return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ?
- CE->getArg(1) : CE->getArg(0),
- /*LessOp=*/llvm::None,
- /*StrictOp=*/true,
- CE->getSourceRange(),
- CE->getOperatorLoc());
+ if (IneqCondIsCanonical)
+ return setUB(getInitLCDecl(CE->getArg(0)) == LCDecl ? CE->getArg(1)
+ : CE->getArg(0),
+ /*LessOp=*/llvm::None,
+ /*StrictOp=*/true, CE->getSourceRange(),
+ CE->getOperatorLoc());
break;
default:
break;
@@ -5203,7 +5806,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetCond(Expr *S) {
if (dependent() || SemaRef.CurContext->isDependentContext())
return false;
SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
- << S->getSourceRange() << LCDecl;
+ << (IneqCondIsCanonical ? 1 : 0) << S->getSourceRange() << LCDecl;
return true;
}
@@ -5336,15 +5939,177 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture,
/// Build the expression to calculate the number of iterations.
Expr *OpenMPIterationSpaceChecker::buildNumIterations(
- Scope *S, const bool LimitedType,
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
+ Expr *LBVal = LB;
+ Expr *UBVal = UB;
+ // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
+ // max(LB(MinVal), LB(MaxVal))
+ if (InitDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, LBVal
+ LBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal);
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, LBVal)
+ LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, LBVal
+ LBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal);
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, LBVal)
+ LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get();
+ Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get();
+ if (!LBMin || !LBMax)
+ return nullptr;
+ // LB(MinVal) < LB(MaxVal)
+ ExprResult MinLessMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
+ if (!MinLessMaxRes.isUsable())
+ return nullptr;
+ Expr *MinLessMax =
+ tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
+ if (!MinLessMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMin, LBMax);
+ if (!MinLB.isUsable())
+ return nullptr;
+ LBVal = MinLB.get();
+ } else {
+ // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMax, LBMin);
+ if (!MaxLB.isUsable())
+ return nullptr;
+ LBVal = MaxLB.get();
+ }
+ }
+ // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
+ // min(UB(MinVal), UB(MaxVal))
+ if (CondDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, UBVal
+ UBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal);
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, UBVal)
+ UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, UBVal
+ UBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal);
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, UBVal)
+ UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get();
+ Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get();
+ if (!UBMin || !UBMax)
+ return nullptr;
+ // UB(MinVal) > UB(MaxVal)
+ ExprResult MinGreaterMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax);
+ if (!MinGreaterMaxRes.isUsable())
+ return nullptr;
+ Expr *MinGreaterMax =
+ tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
+ if (!MinGreaterMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MaxUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax);
+ if (!MaxUB.isUsable())
+ return nullptr;
+ UBVal = MaxUB.get();
+ } else {
+ // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MinUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin);
+ if (!MinUB.isUsable())
+ return nullptr;
+ UBVal = MinUB.get();
+ }
+ }
// Upper - Lower
- Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
- Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
@@ -5431,12 +6196,142 @@ Expr *OpenMPIterationSpaceChecker::buildNumIterations(
return Diff.get();
}
+std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
+ Scope *S, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ // Do not build for iterators, they cannot be used in non-rectangular loop
+ // nests.
+ if (LCDecl->getType()->isRecordType())
+ return std::make_pair(nullptr, nullptr);
+ // If we subtract, the min is in the condition, otherwise the min is in the
+ // init value.
+ Expr *MinExpr = nullptr;
+ Expr *MaxExpr = nullptr;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LB : UB;
+ Expr *UBExpr = TestIsLessOp.getValue() ? UB : LB;
+ bool LBNonRect = TestIsLessOp.getValue() ? InitDependOnLC.hasValue()
+ : CondDependOnLC.hasValue();
+ bool UBNonRect = TestIsLessOp.getValue() ? CondDependOnLC.hasValue()
+ : InitDependOnLC.hasValue();
+ Expr *Lower =
+ LBNonRect ? LBExpr : tryBuildCapture(SemaRef, LBExpr, Captures).get();
+ Expr *Upper =
+ UBNonRect ? UBExpr : tryBuildCapture(SemaRef, UBExpr, Captures).get();
+ if (!Upper || !Lower)
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue())
+ MinExpr = Lower;
+ else
+ MaxExpr = Upper;
+
+ // Build minimum/maximum value based on number of iterations.
+ ExprResult Diff;
+ QualType VarType = LCDecl->getType().getNonReferenceType();
+
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Upper - Lower [- 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Upper - Lower [- 1] + Step
+ ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
+ if (!NewStep.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // (Upper - Lower [- 1]) / Step
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // ((Upper - Lower [- 1]) / Step) * Step
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Convert to the original type or ptrdiff_t, if original type is pointer.
+ if (!VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) {
+ Diff = SemaRef.PerformImplicitConversion(
+ Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true);
+ } else if (VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(
+ Diff.get()->getType(),
+ SemaRef.Context.getUnsignedPointerDiffType())) {
+ Diff = SemaRef.PerformImplicitConversion(
+ Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(),
+ Sema::AA_Converting, /*AllowExplicit=*/true);
+ }
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue()) {
+ // MinExpr = Lower;
+ // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step)
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ MaxExpr = Diff.get();
+ } else {
+ // MaxExpr = Upper;
+ // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step)
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get());
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+ MinExpr = Diff.get();
+ }
+
+ return std::make_pair(MinExpr, MaxExpr);
+}
+
+Expr *OpenMPIterationSpaceChecker::buildFinalCondition(Scope *S) const {
+ if (InitDependOnLC || CondDependOnLC)
+ return Condition;
+ return nullptr;
+}
+
Expr *OpenMPIterationSpaceChecker::buildPreCond(
Scope *S, Expr *Cond,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ // Do not build a precondition when the condition/initialization is dependent
+ // to prevent pessimistic early loop exit.
+ // TODO: this can be improved by calculating min/max values but not sure that
+ // it will be very effective.
+ if (CondDependOnLC || InitDependOnLC)
+ return SemaRef.PerformImplicitConversion(
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(),
+ SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
+ /*AllowExplicit=*/true).get();
+
// Try to build LB <op> UB, where <op> is <, >, <=, or >=.
- bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ Sema::TentativeAnalysisScope Trap(SemaRef);
ExprResult NewLB = tryBuildCapture(SemaRef, LB, Captures);
ExprResult NewUB = tryBuildCapture(SemaRef, UB, Captures);
@@ -5456,7 +6351,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
/*AllowExplicit=*/true);
}
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
+
// Otherwise use original loop condition and evaluate it in runtime.
return CondExpr.isUsable() ? CondExpr.get() : Cond;
}
@@ -5561,36 +6456,6 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
return Diff.get();
}
-
-/// Iteration space of a single for loop.
-struct LoopIterationSpace final {
- /// True if the condition operator is the strict compare operator (<, > or
- /// !=).
- bool IsStrictCompare = false;
- /// Condition of the loop.
- Expr *PreCond = nullptr;
- /// This expression calculates the number of iterations in the loop.
- /// It is always possible to calculate it before starting the loop.
- Expr *NumIterations = nullptr;
- /// The loop counter variable.
- Expr *CounterVar = nullptr;
- /// Private loop counter variable.
- Expr *PrivateCounterVar = nullptr;
- /// This is initializer for the initial value of #CounterVar.
- Expr *CounterInit = nullptr;
- /// This is step for the #CounterVar used to generate its update:
- /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
- Expr *CounterStep = nullptr;
- /// Should step be subtracted?
- bool Subtract = false;
- /// Source range of the loop init.
- SourceRange InitSrcRange;
- /// Source range of the loop condition.
- SourceRange CondSrcRange;
- /// Source range of the loop increment.
- SourceRange IncSrcRange;
-};
-
} // namespace
void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
@@ -5604,13 +6469,14 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
if (ValueDecl *D = ISC.getLoopDecl()) {
auto *VD = dyn_cast<VarDecl>(D);
+ DeclRefExpr *PrivateRef = nullptr;
if (!VD) {
if (VarDecl *Private = isOpenMPCapturedDecl(D)) {
VD = Private;
} else {
- DeclRefExpr *Ref = buildCapture(*this, D, ISC.getLoopDeclRefExpr(),
- /*WithInit=*/false);
- VD = cast<VarDecl>(Ref->getDecl());
+ PrivateRef = buildCapture(*this, D, ISC.getLoopDeclRefExpr(),
+ /*WithInit=*/false);
+ VD = cast<VarDecl>(PrivateRef->getDecl());
}
}
DSAStack->addLoopControlVariable(D, VD);
@@ -5623,6 +6489,51 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
Var->getType().getNonLValueExprType(Context),
ForLoc, /*RefersToCapture=*/true));
}
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables
+ // Referenced in a Construct, C/C++]. The loop iteration variable in the
+ // associated for-loop of a simd construct with just one associated
+ // for-loop may be listed in a linear clause with a constant-linear-step
+ // that is the increment of the associated for-loop. The loop iteration
+ // variable(s) in the associated for-loop(s) of a for or parallel for
+ // construct may be listed in a private or lastprivate clause.
+ DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ // If LoopVarRefExpr is nullptr it means the corresponding loop variable
+ // is declared in the loop and it is predetermined as a private.
+ Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
+ OpenMPClauseKind PredeterminedCKind =
+ isOpenMPSimdDirective(DKind)
+ ? (DSAStack->hasMutipleLoops() ? OMPC_lastprivate : OMPC_linear)
+ : OMPC_private;
+ if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
+ (LangOpts.OpenMP <= 45 || (DVar.CKind != OMPC_lastprivate &&
+ DVar.CKind != OMPC_private))) ||
+ ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
+ DKind == OMPD_master_taskloop ||
+ DKind == OMPD_parallel_master_taskloop ||
+ isOpenMPDistributeDirective(DKind)) &&
+ !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr)) {
+ Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(PredeterminedCKind);
+ if (DVar.RefExpr == nullptr)
+ DVar.CKind = PredeterminedCKind;
+ reportOriginalDsa(*this, DSAStack, D, DVar,
+ /*IsLoopIterVar=*/true);
+ } else if (LoopDeclRefExpr) {
+ // Make the loop iteration variable private (for worksharing
+ // constructs), linear (for simd directives with the only one
+ // associated loop) or lastprivate (for simd directives with several
+ // collapsed or ordered loops).
+ if (DVar.CKind == OMPC_unknown)
+ DSAStack->addDSA(D, LoopDeclRefExpr, PredeterminedCKind,
+ PrivateRef);
+ }
}
}
DSAStack->setAssociatedLoops(AssociatedLoops - 1);
@@ -5637,12 +6548,15 @@ static bool checkOpenMPIterationSpace(
unsigned TotalNestedLoopCount, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr,
Sema::VarsWithInheritedDSAType &VarsWithImplicitDSA,
- LoopIterationSpace &ResultIterSpace,
+ llvm::MutableArrayRef<LoopIterationSpace> ResultIterSpaces,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
- // OpenMP [2.6, Canonical Loop Form]
+ // OpenMP [2.9.1, Canonical Loop Form]
// for (init-expr; test-expr; incr-expr) structured-block
+ // for (range-decl: range-expr) structured-block
auto *For = dyn_cast_or_null<ForStmt>(S);
- if (!For) {
+ auto *CXXFor = dyn_cast_or_null<CXXForRangeStmt>(S);
+ // Ranged for is supported only in OpenMP 5.0.
+ if (!For && (SemaRef.LangOpts.OpenMP <= 45 || !CXXFor)) {
SemaRef.Diag(S->getBeginLoc(), diag::err_omp_not_for)
<< (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr)
<< getOpenMPDirectiveName(DKind) << TotalNestedLoopCount
@@ -5664,12 +6578,14 @@ static bool checkOpenMPIterationSpace(
}
return true;
}
- assert(For->getBody());
+ assert(((For && For->getBody()) || (CXXFor && CXXFor->getBody())) &&
+ "No loop body.");
- OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc());
+ OpenMPIterationSpaceChecker ISC(SemaRef, DSA,
+ For ? For->getForLoc() : CXXFor->getForLoc());
// Check init.
- Stmt *Init = For->getInit();
+ Stmt *Init = For ? For->getInit() : CXXFor->getBeginStmt();
if (ISC.checkAndSetInit(Init))
return true;
@@ -5677,8 +6593,6 @@ static bool checkOpenMPIterationSpace(
// Check loop variable's type.
if (ValueDecl *LCDecl = ISC.getLoopDecl()) {
- Expr *LoopDeclRefExpr = ISC.getLoopDeclRefExpr();
-
// OpenMP [2.6, Canonical Loop Form]
// Var is one of the following:
// A variable of signed or unsigned integer type.
@@ -5704,90 +6618,70 @@ static bool checkOpenMPIterationSpace(
// sharing attributes.
VarsWithImplicitDSA.erase(LCDecl);
- // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
- // in a Construct, C/C++].
- // The loop iteration variable in the associated for-loop of a simd
- // construct with just one associated for-loop may be listed in a linear
- // clause with a constant-linear-step that is the increment of the
- // associated for-loop.
- // The loop iteration variable(s) in the associated for-loop(s) of a for or
- // parallel for construct may be listed in a private or lastprivate clause.
- DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false);
- // If LoopVarRefExpr is nullptr it means the corresponding loop variable is
- // declared in the loop and it is predetermined as a private.
- OpenMPClauseKind PredeterminedCKind =
- isOpenMPSimdDirective(DKind)
- ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
- : OMPC_private;
- if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != PredeterminedCKind && DVar.RefExpr &&
- (SemaRef.getLangOpts().OpenMP <= 45 ||
- (DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_private))) ||
- ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
- isOpenMPDistributeDirective(DKind)) &&
- !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
- (DVar.CKind != OMPC_private || DVar.RefExpr)) {
- SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
- << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
- << getOpenMPClauseName(PredeterminedCKind);
- if (DVar.RefExpr == nullptr)
- DVar.CKind = PredeterminedCKind;
- reportOriginalDsa(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true);
- HasErrors = true;
- } else if (LoopDeclRefExpr != nullptr) {
- // Make the loop iteration variable private (for worksharing constructs),
- // linear (for simd directives with the only one associated loop) or
- // lastprivate (for simd directives with several collapsed or ordered
- // loops).
- if (DVar.CKind == OMPC_unknown)
- DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
- }
-
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
// Check test-expr.
- HasErrors |= ISC.checkAndSetCond(For->getCond());
+ HasErrors |= ISC.checkAndSetCond(For ? For->getCond() : CXXFor->getCond());
// Check incr-expr.
- HasErrors |= ISC.checkAndSetInc(For->getInc());
+ HasErrors |= ISC.checkAndSetInc(For ? For->getInc() : CXXFor->getInc());
}
if (ISC.dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
return HasErrors;
// Build the loop's iteration space representation.
- ResultIterSpace.PreCond =
- ISC.buildPreCond(DSA.getCurScope(), For->getCond(), Captures);
- ResultIterSpace.NumIterations = ISC.buildNumIterations(
- DSA.getCurScope(),
- (isOpenMPWorksharingDirective(DKind) ||
- isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)),
- Captures);
- ResultIterSpace.CounterVar = ISC.buildCounterVar(Captures, DSA);
- ResultIterSpace.PrivateCounterVar = ISC.buildPrivateCounterVar();
- ResultIterSpace.CounterInit = ISC.buildCounterInit();
- ResultIterSpace.CounterStep = ISC.buildCounterStep();
- ResultIterSpace.InitSrcRange = ISC.getInitSrcRange();
- ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange();
- ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange();
- ResultIterSpace.Subtract = ISC.shouldSubtractStep();
- ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp();
-
- HasErrors |= (ResultIterSpace.PreCond == nullptr ||
- ResultIterSpace.NumIterations == nullptr ||
- ResultIterSpace.CounterVar == nullptr ||
- ResultIterSpace.PrivateCounterVar == nullptr ||
- ResultIterSpace.CounterInit == nullptr ||
- ResultIterSpace.CounterStep == nullptr);
+ ResultIterSpaces[CurrentNestedLoopCount].PreCond = ISC.buildPreCond(
+ DSA.getCurScope(), For ? For->getCond() : CXXFor->getCond(), Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations =
+ ISC.buildNumIterations(DSA.getCurScope(), ResultIterSpaces,
+ (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) ||
+ isOpenMPDistributeDirective(DKind)),
+ Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar =
+ ISC.buildCounterVar(Captures, DSA);
+ ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar =
+ ISC.buildPrivateCounterVar();
+ ResultIterSpaces[CurrentNestedLoopCount].CounterInit = ISC.buildCounterInit();
+ ResultIterSpaces[CurrentNestedLoopCount].CounterStep = ISC.buildCounterStep();
+ ResultIterSpaces[CurrentNestedLoopCount].InitSrcRange = ISC.getInitSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].CondSrcRange =
+ ISC.getConditionSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].IncSrcRange =
+ ISC.getIncrementSrcRange();
+ ResultIterSpaces[CurrentNestedLoopCount].Subtract = ISC.shouldSubtractStep();
+ ResultIterSpaces[CurrentNestedLoopCount].IsStrictCompare =
+ ISC.isStrictTestOp();
+ std::tie(ResultIterSpaces[CurrentNestedLoopCount].MinValue,
+ ResultIterSpaces[CurrentNestedLoopCount].MaxValue) =
+ ISC.buildMinMaxValues(DSA.getCurScope(), Captures);
+ ResultIterSpaces[CurrentNestedLoopCount].FinalCondition =
+ ISC.buildFinalCondition(DSA.getCurScope());
+ ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularLB =
+ ISC.doesInitDependOnLC();
+ ResultIterSpaces[CurrentNestedLoopCount].IsNonRectangularUB =
+ ISC.doesCondDependOnLC();
+ ResultIterSpaces[CurrentNestedLoopCount].LoopDependentIdx =
+ ISC.getLoopDependentIdx();
+
+ HasErrors |=
+ (ResultIterSpaces[CurrentNestedLoopCount].PreCond == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].PrivateCounterVar == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterInit == nullptr ||
+ ResultIterSpaces[CurrentNestedLoopCount].CounterStep == nullptr);
if (!HasErrors && DSA.isOrderedRegion()) {
if (DSA.getOrderedRegionParam().second->getNumForLoops()) {
if (CurrentNestedLoopCount <
DSA.getOrderedRegionParam().second->getLoopNumIterations().size()) {
DSA.getOrderedRegionParam().second->setLoopNumIterations(
- CurrentNestedLoopCount, ResultIterSpace.NumIterations);
+ CurrentNestedLoopCount,
+ ResultIterSpaces[CurrentNestedLoopCount].NumIterations);
DSA.getOrderedRegionParam().second->setLoopCounter(
- CurrentNestedLoopCount, ResultIterSpace.CounterVar);
+ CurrentNestedLoopCount,
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar);
}
}
for (auto &Pair : DSA.getDoacrossDependClauses()) {
@@ -5804,11 +6698,13 @@ static bool checkOpenMPIterationSpace(
Expr *CntValue;
if (Pair.first->getDependencyKind() == OMPC_DEPEND_source)
CntValue = ISC.buildOrderedLoopData(
- DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
+ DSA.getCurScope(),
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
Pair.first->getDependencyLoc());
else
CntValue = ISC.buildOrderedLoopData(
- DSA.getCurScope(), ResultIterSpace.CounterVar, Captures,
+ DSA.getCurScope(),
+ ResultIterSpaces[CurrentNestedLoopCount].CounterVar, Captures,
Pair.first->getDependencyLoc(),
Pair.second[CurrentNestedLoopCount].first,
Pair.second[CurrentNestedLoopCount].second);
@@ -5822,10 +6718,12 @@ static bool checkOpenMPIterationSpace(
/// Build 'VarRef = Start.
static ExprResult
buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
- ExprResult Start,
+ ExprResult Start, bool IsNonRectangularLB,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
// Build 'VarRef = Start.
- ExprResult NewStart = tryBuildCapture(SemaRef, Start.get(), Captures);
+ ExprResult NewStart = IsNonRectangularLB
+ ? Start.get()
+ : tryBuildCapture(SemaRef, Start.get(), Captures);
if (!NewStart.isUsable())
return ExprError();
if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
@@ -5846,6 +6744,7 @@ buildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
static ExprResult buildCounterUpdate(
Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
ExprResult Start, ExprResult Iter, ExprResult Step, bool Subtract,
+ bool IsNonRectangularLB,
llvm::MapVector<const Expr *, DeclRefExpr *> *Captures = nullptr) {
// Add parentheses (for debugging purposes only).
Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get());
@@ -5865,8 +6764,12 @@ static ExprResult buildCounterUpdate(
// Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or
// 'VarRef = Start (+|-) Iter * Step'.
- ExprResult NewStart = Start;
- if (Captures)
+ if (!Start.isUsable())
+ return ExprError();
+ ExprResult NewStart = SemaRef.ActOnParenExpr(Loc, Loc, Start.get());
+ if (!NewStart.isUsable())
+ return ExprError();
+ if (Captures && !IsNonRectangularLB)
NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures);
if (NewStart.isInvalid())
return ExprError();
@@ -5877,8 +6780,8 @@ static ExprResult buildCounterUpdate(
if (VarRef.get()->getType()->isOverloadableType() ||
NewStart.get()->getType()->isOverloadableType() ||
Update.get()->getType()->isOverloadableType()) {
- bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ Sema::TentativeAnalysisScope Trap(SemaRef);
+
Update =
SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get());
if (Update.isUsable()) {
@@ -5890,7 +6793,6 @@ static ExprResult buildCounterUpdate(
UpdateVal.get());
}
}
- SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
}
// Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'.
@@ -6037,22 +6939,27 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
- OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
- Captures))
+ OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures))
return 0;
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
- CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
+ CurStmt = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(CurStmt) &&
+ "Expected canonical for or range-based for loops.");
+ CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
+ }
+ CurStmt = CurStmt->IgnoreContainers();
}
for (unsigned Cnt = NestedLoopCount; Cnt < OrderedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount,
std::max(OrderedLoopCount, NestedLoopCount), CollapseLoopCountExpr,
- OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces[Cnt],
- Captures))
+ OrderedLoopCountExpr, VarsWithImplicitDSA, IterSpaces, Captures))
return 0;
if (Cnt > 0 && IterSpaces[Cnt].CounterVar) {
// Handle initialization of captured loop iterator variables.
@@ -6066,7 +6973,14 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// All loops associated with the construct must be perfectly nested; that
// is, there must be no intervening code nor any OpenMP directive between
// any two loops.
- CurStmt = cast<ForStmt>(CurStmt)->getBody()->IgnoreContainers();
+ if (auto *For = dyn_cast<ForStmt>(CurStmt)) {
+ CurStmt = For->getBody();
+ } else {
+ assert(isa<CXXForRangeStmt>(CurStmt) &&
+ "Expected canonical for or range-based for loops.");
+ CurStmt = cast<CXXForRangeStmt>(CurStmt)->getBody();
+ }
+ CurStmt = CurStmt->IgnoreContainers();
}
Built.clear(/* size */ NestedLoopCount);
@@ -6513,6 +7427,9 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits.resize(NestedLoopCount);
Built.Updates.resize(NestedLoopCount);
Built.Finals.resize(NestedLoopCount);
+ Built.DependentCounters.resize(NestedLoopCount);
+ Built.DependentInits.resize(NestedLoopCount);
+ Built.FinalsConditions.resize(NestedLoopCount);
{
// We implement the following algorithm for obtaining the
// original loop iteration variable values based on the
@@ -6572,24 +7489,26 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
DeclRefExpr *CounterVar = buildDeclRefExpr(
SemaRef, VD, IS.CounterVar->getType(), IS.CounterVar->getExprLoc(),
/*RefersToCapture=*/true);
- ExprResult Init = buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
- IS.CounterInit, Captures);
+ ExprResult Init =
+ buildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
+ IS.CounterInit, IS.IsNonRectangularLB, Captures);
if (!Init.isUsable()) {
HasErrors = true;
break;
}
ExprResult Update = buildCounterUpdate(
SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter,
- IS.CounterStep, IS.Subtract, &Captures);
+ IS.CounterStep, IS.Subtract, IS.IsNonRectangularLB, &Captures);
if (!Update.isUsable()) {
HasErrors = true;
break;
}
// Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step
- ExprResult Final = buildCounterUpdate(
- SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit,
- IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures);
+ ExprResult Final =
+ buildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar,
+ IS.CounterInit, IS.NumIterations, IS.CounterStep,
+ IS.Subtract, IS.IsNonRectangularLB, &Captures);
if (!Final.isUsable()) {
HasErrors = true;
break;
@@ -6605,6 +7524,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits[Cnt] = Init.get();
Built.Updates[Cnt] = Update.get();
Built.Finals[Cnt] = Final.get();
+ Built.DependentCounters[Cnt] = nullptr;
+ Built.DependentInits[Cnt] = nullptr;
+ Built.FinalsConditions[Cnt] = nullptr;
+ if (IS.IsNonRectangularLB || IS.IsNonRectangularUB) {
+ Built.DependentCounters[Cnt] =
+ Built.Counters[NestedLoopCount - 1 - IS.LoopDependentIdx];
+ Built.DependentInits[Cnt] =
+ Built.Inits[NestedLoopCount - 1 - IS.LoopDependentIdx];
+ Built.FinalsConditions[Cnt] = IS.FinalCondition;
+ }
}
}
@@ -6617,7 +7546,7 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.NumIterations = NumIterations.get();
Built.CalcLastIteration = SemaRef
.ActOnFinishFullExpr(CalcLastIteration.get(),
- /*DiscardedValue*/ false)
+ /*DiscardedValue=*/false)
.get();
Built.PreCond = PreCond.get();
Built.PreInits = buildPreInits(C, Captures);
@@ -8398,6 +9327,146 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_master_taskloop, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ checkOpenMPLoop(OMPD_master_taskloop_simd, getCollapseNumberExpr(Clauses),
+ /*OrderedLoopCountExpr=*/nullptr, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (OMPClause *C : Clauses) {
+ if (auto *LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPMasterTaskLoopSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ auto *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ for (int ThisCaptureLevel =
+ getOpenMPCaptureLevels(OMPD_parallel_master_taskloop);
+ ThisCaptureLevel > 1; --ThisCaptureLevel) {
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+ }
+
+ OMPLoopDirective::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, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // The grainsize clause and num_tasks clause are mutually exclusive and may
+ // not appear on the same taskloop directive.
+ if (checkGrainsizeNumTasksClauses(*this, Clauses))
+ return StmtError();
+ // OpenMP, [2.9.2 taskloop Construct, Restrictions]
+ // If a reduction clause is present on the taskloop directive, the nogroup
+ // clause must not be specified.
+ if (checkReductionClauseWithNogroup(*this, Clauses))
+ return StmtError();
+
+ setFunctionHasBranchProtectedScope();
+ return OMPParallelMasterTaskLoopDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc, VarsWithInheritedDSAType &VarsWithImplicitDSA) {
@@ -9246,6 +10315,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -9287,6 +10358,10 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_exit_data:
CaptureRegion = OMPD_task;
break;
+ case OMPD_parallel_master_taskloop:
+ if (NameModifier == OMPD_unknown || NameModifier == OMPD_taskloop)
+ CaptureRegion = OMPD_parallel;
+ break;
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -9302,6 +10377,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
case OMPD_target_data:
// Do not capture if-clause expressions.
break;
@@ -9315,6 +10392,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -9358,6 +10436,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel_for_simd:
case OMPD_distribute_parallel_for:
case OMPD_distribute_parallel_for_simd:
+ case OMPD_parallel_master_taskloop:
// Do not capture num_threads-clause expressions.
break;
case OMPD_target_data:
@@ -9373,6 +10452,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
case OMPD_threadprivate:
case OMPD_allocate:
case OMPD_taskyield:
@@ -9383,6 +10464,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -9428,6 +10510,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9452,6 +10537,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9494,6 +10580,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9518,6 +10607,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9560,6 +10650,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9585,6 +10678,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9630,6 +10724,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_target_data:
case OMPD_target_enter_data:
case OMPD_target_exit_data:
@@ -9651,6 +10748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9701,6 +10799,9 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_task:
case OMPD_taskloop:
case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ case OMPD_parallel_master_taskloop:
case OMPD_cancel:
case OMPD_parallel:
case OMPD_parallel_sections:
@@ -9716,6 +10817,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
+ case OMPD_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -9737,6 +10839,78 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
llvm_unreachable("Unknown OpenMP directive");
}
break;
+ case OMPC_grainsize:
+ case OMPC_num_tasks:
+ case OMPC_final:
+ case OMPC_priority:
+ switch (DKind) {
+ case OMPD_task:
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd:
+ case OMPD_master_taskloop:
+ case OMPD_master_taskloop_simd:
+ break;
+ case OMPD_parallel_master_taskloop:
+ CaptureRegion = OMPD_parallel;
+ break;
+ case OMPD_target_update:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_target:
+ case OMPD_target_simd:
+ case OMPD_target_teams:
+ case OMPD_target_parallel:
+ case OMPD_target_teams_distribute:
+ case OMPD_target_teams_distribute_simd:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd:
+ case OMPD_target_teams_distribute_parallel_for:
+ case OMPD_target_teams_distribute_parallel_for_simd:
+ case OMPD_target_data:
+ case OMPD_teams_distribute_parallel_for:
+ case OMPD_teams_distribute_parallel_for_simd:
+ case OMPD_teams:
+ case OMPD_teams_distribute:
+ case OMPD_teams_distribute_simd:
+ case OMPD_distribute_parallel_for:
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_cancel:
+ case OMPD_parallel:
+ case OMPD_parallel_sections:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_threadprivate:
+ case OMPD_allocate:
+ case OMPD_taskyield:
+ case OMPD_barrier:
+ case OMPD_taskwait:
+ case OMPD_cancellation_point:
+ case OMPD_flush:
+ case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
+ case OMPD_declare_simd:
+ case OMPD_declare_variant:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_distribute_simd:
+ case OMPD_requires:
+ llvm_unreachable("Unexpected OpenMP directive with grainsize-clause");
+ case OMPD_unknown:
+ llvm_unreachable("Unknown OpenMP directive");
+ }
+ break;
case OMPC_firstprivate:
case OMPC_lastprivate:
case OMPC_reduction:
@@ -9745,7 +10919,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_linear:
case OMPC_default:
case OMPC_proc_bind:
- case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
case OMPC_allocator:
@@ -9771,10 +10944,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
- case OMPC_priority:
- case OMPC_grainsize:
case OMPC_nogroup:
- case OMPC_num_tasks:
case OMPC_hint:
case OMPC_defaultmap:
case OMPC_unknown:
@@ -9788,6 +10958,8 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -9832,6 +11004,8 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Condition;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
@@ -9840,10 +11014,21 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
return nullptr;
ValExpr = MakeFullExpr(Val.get()).get();
+
+ OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
+ CaptureRegion = getOpenMPCaptureRegionForClause(DKind, OMPC_final);
+ if (CaptureRegion != OMPD_unknown && !CurContext->isDependentContext()) {
+ ValExpr = MakeFullExpr(ValExpr).get();
+ llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
}
- return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPFinalClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
+
ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
Expr *Op) {
if (!Op)
@@ -9888,9 +11073,12 @@ ExprResult Sema::PerformOpenMPImplicitIntegerConversion(SourceLocation Loc,
return PerformContextualImplicitConversion(Loc, Op, ConvertDiagnoser);
}
-static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
- OpenMPClauseKind CKind,
- bool StrictlyPositive) {
+static bool
+isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef, OpenMPClauseKind CKind,
+ bool StrictlyPositive, bool BuildCapture = false,
+ OpenMPDirectiveKind DKind = OMPD_unknown,
+ OpenMPDirectiveKind *CaptureRegion = nullptr,
+ Stmt **HelperValStmt = nullptr) {
if (!ValExpr->isTypeDependent() && !ValExpr->isValueDependent() &&
!ValExpr->isInstantiationDependent()) {
SourceLocation Loc = ValExpr->getExprLoc();
@@ -9911,6 +11099,16 @@ static bool isNonNegativeIntegerValue(Expr *&ValExpr, Sema &SemaRef,
<< ValExpr->getSourceRange();
return false;
}
+ if (!BuildCapture)
+ return true;
+ *CaptureRegion = getOpenMPCaptureRegionForClause(DKind, CKind);
+ 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);
+ }
}
return true;
}
@@ -10181,6 +11379,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_unified_shared_memory:
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10359,6 +11559,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10568,6 +11770,8 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_use_device_ptr:
case OMPC_is_device_ptr:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10774,6 +11978,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_reverse_offload:
case OMPC_dynamic_allocators:
case OMPC_atomic_default_mem_order:
+ case OMPC_device_type:
+ case OMPC_match:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10874,7 +12080,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (isOpenMPTargetExecutionDirective(CurrDir)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if ((LangOpts.OpenMP <= 45 && isOpenMPTargetExecutionDirective(CurrDir)) ||
+ CurrDir == OMPD_target) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
@@ -11109,7 +12321,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (isOpenMPTargetExecutionDirective(CurrDir)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if ((LangOpts.OpenMP <= 45 &&
+ isOpenMPTargetExecutionDirective(CurrDir)) ||
+ CurrDir == OMPD_target) {
OpenMPClauseKind ConflictKind;
if (DSAStack->checkMappableExprComponentListsForDecl(
VD, /*CurrentRegionOnly=*/true,
@@ -12133,8 +13352,9 @@ static bool actOnOMPReductionKindClause(
// If we don't have a single element, we must emit a constant array type.
if (ConstantLengthOASE && !SingleElement) {
for (llvm::APSInt &Size : ArraySizes)
- PrivateTy = Context.getConstantArrayType(
- PrivateTy, Size, ArrayType::Normal, /*IndexTypeQuals=*/0);
+ PrivateTy = Context.getConstantArrayType(PrivateTy, Size, nullptr,
+ ArrayType::Normal,
+ /*IndexTypeQuals=*/0);
}
}
@@ -12707,6 +13927,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
// Walk the vars and build update/final expressions for the CodeGen.
SmallVector<Expr *, 8> Updates;
SmallVector<Expr *, 8> Finals;
+ SmallVector<Expr *, 8> UsedExprs;
Expr *Step = Clause.getStep();
Expr *CalcStep = Clause.getCalcStep();
// OpenMP [2.14.3.7, linear clause]
@@ -12760,9 +13981,9 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
// Build update: Var = InitExpr + IV * Step
ExprResult Update;
if (!Info.first)
- Update =
- buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate,
- InitExpr, IV, Step, /* Subtract */ false);
+ Update = buildCounterUpdate(
+ SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, InitExpr, IV, Step,
+ /*Subtract=*/false, /*IsNonRectangularLB=*/false);
else
Update = *CurPrivate;
Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getBeginLoc(),
@@ -12773,7 +13994,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
if (!Info.first)
Final =
buildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef,
- InitExpr, NumIterations, Step, /*Subtract=*/false);
+ InitExpr, NumIterations, Step, /*Subtract=*/false,
+ /*IsNonRectangularLB=*/false);
else
Final = *CurPrivate;
Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getBeginLoc(),
@@ -12782,16 +14004,24 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
if (!Update.isUsable() || !Final.isUsable()) {
Updates.push_back(nullptr);
Finals.push_back(nullptr);
+ UsedExprs.push_back(nullptr);
HasErrors = true;
} else {
Updates.push_back(Update.get());
Finals.push_back(Final.get());
+ if (!Info.first)
+ UsedExprs.push_back(SimpleRefExpr);
}
++CurInit;
++CurPrivate;
}
+ if (Expr *S = Clause.getStep())
+ UsedExprs.push_back(S);
+ // Fill the remaining part with the nullptr.
+ UsedExprs.append(Clause.varlist_size() + 1 - UsedExprs.size(), nullptr);
Clause.setUpdates(Updates);
Clause.setFinals(Finals);
+ Clause.setUsedExprs(UsedExprs);
return HasErrors;
}
@@ -13216,11 +14446,13 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
<< RefExpr->getSourceRange();
continue;
}
- bool Suppress = getDiagnostics().getSuppressAllDiagnostics();
- getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
- ExprResult Res =
- CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RefExpr->IgnoreParenImpCasts());
- getDiagnostics().setSuppressAllDiagnostics(Suppress);
+
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ }
if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
<< RefExpr->getSourceRange();
@@ -13884,6 +15116,11 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
Expr *UnresolvedMapper) {
if (MapperIdScopeSpec.isInvalid())
return ExprError();
+ // Get the actual type for the array type.
+ if (Type->isArrayType()) {
+ assert(Type->getAsArrayTypeUnsafe() && "Expect to get a valid array type");
+ Type = Type->getAsArrayTypeUnsafe()->getElementType().getCanonicalType();
+ }
// Find all user-defined mappers with the given MapperId.
SmallVector<UnresolvedSet<8>, 4> Lookups;
LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
@@ -13930,11 +15167,14 @@ static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
/*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end());
}
+ SourceLocation Loc = MapperId.getLoc();
// [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
// The type must be of struct, union or class type in C and C++
- if (!Type->isStructureOrClassType() && !Type->isUnionType())
- return ExprEmpty();
- SourceLocation Loc = MapperId.getLoc();
+ if (!Type->isStructureOrClassType() && !Type->isUnionType() &&
+ (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default")) {
+ SemaRef.Diag(Loc, diag::err_omp_mapper_wrong_type);
+ return ExprError();
+ }
// Perform argument dependent lookup.
if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet())
argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups);
@@ -14211,7 +15451,14 @@ static void checkMappableExpressionList(
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
- if (VD && isOpenMPTargetExecutionDirective(DKind)) {
+ //
+ // OpenMP 5.0 [2.19.7.1, Restrictions, p.7]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct unless the construct is a
+ // combined construct.
+ if (VD && ((SemaRef.LangOpts.OpenMP <= 45 &&
+ isOpenMPTargetExecutionDirective(DKind)) ||
+ DKind == OMPD_target)) {
DSAStackTy::DSAVarData DVar = DSAS->getTopDSA(VD, /*FromParent=*/false);
if (isOpenMPPrivate(DVar.CKind)) {
SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa)
@@ -14745,14 +15992,19 @@ OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Priority;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.1, task Constrcut]
// The priority-value is a non-negative numerical scalar expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_priority,
- /*StrictlyPositive=*/false))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_priority,
+ /*StrictlyPositive=*/false, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPPriorityClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPPriorityClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
@@ -14760,15 +16012,20 @@ OMPClause *Sema::ActOnOpenMPGrainsizeClause(Expr *Grainsize,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = Grainsize;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the grainsize clause must be a positive integer
// expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_grainsize,
- /*StrictlyPositive=*/true))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_grainsize,
+ /*StrictlyPositive=*/true, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPGrainsizeClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPGrainsizeClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
@@ -14776,15 +16033,20 @@ OMPClause *Sema::ActOnOpenMPNumTasksClause(Expr *NumTasks,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
Expr *ValExpr = NumTasks;
+ Stmt *HelperValStmt = nullptr;
+ OpenMPDirectiveKind CaptureRegion = OMPD_unknown;
// OpenMP [2.9.2, taskloop Constrcut]
// The parameter of the num_tasks clause must be a positive integer
// expression.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_num_tasks,
- /*StrictlyPositive=*/true))
+ if (!isNonNegativeIntegerValue(
+ ValExpr, *this, OMPC_num_tasks,
+ /*StrictlyPositive=*/true, /*BuildCapture=*/true,
+ DSAStack->getCurrentDirective(), &CaptureRegion, &HelperValStmt))
return nullptr;
- return new (Context) OMPNumTasksClause(ValExpr, StartLoc, LParenLoc, EndLoc);
+ return new (Context) OMPNumTasksClause(ValExpr, HelperValStmt, CaptureRegion,
+ StartLoc, LParenLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
@@ -14905,16 +16167,15 @@ void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
--DeclareTargetNestingLevel;
}
-void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
- CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id,
- OMPDeclareTargetDeclAttr::MapTypeTy MT,
- NamedDeclSetType &SameDirectiveDecls) {
+NamedDecl *
+Sema::lookupOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id,
+ NamedDeclSetType &SameDirectiveDecls) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
if (Lookup.isAmbiguous())
- return;
+ return nullptr;
Lookup.suppressDiagnostics();
if (!Lookup.isSingleResult()) {
@@ -14925,33 +16186,56 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Id.getName());
checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl());
- return;
+ return nullptr;
}
Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName();
- return;
+ return nullptr;
}
NamedDecl *ND = Lookup.getAsSingle<NamedDecl>();
- if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
- isa<FunctionTemplateDecl>(ND)) {
- if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
- Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
- llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
- OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
- cast<ValueDecl>(ND));
- if (!Res) {
- auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT);
- ND->addAttr(A);
- if (ASTMutationListener *ML = Context.getASTMutationListener())
- ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
- checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Id.getLoc());
- } else if (*Res != MT) {
- Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link)
- << Id.getName();
- }
- } else {
+ if (!isa<VarDecl>(ND) && !isa<FunctionDecl>(ND) &&
+ !isa<FunctionTemplateDecl>(ND)) {
Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName();
+ return nullptr;
+ }
+ if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
+ Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
+ return ND;
+}
+
+void Sema::ActOnOpenMPDeclareTargetName(
+ NamedDecl *ND, SourceLocation Loc, OMPDeclareTargetDeclAttr::MapTypeTy MT,
+ OMPDeclareTargetDeclAttr::DevTypeTy DT) {
+ assert((isa<VarDecl>(ND) || isa<FunctionDecl>(ND) ||
+ isa<FunctionTemplateDecl>(ND)) &&
+ "Expected variable, function or function template.");
+
+ // Diagnose marking after use as it may lead to incorrect diagnosis and
+ // codegen.
+ if (LangOpts.OpenMP >= 50 &&
+ (ND->isUsed(/*CheckUsedAttr=*/false) || ND->isReferenced()))
+ Diag(Loc, diag::warn_omp_declare_target_after_first_use);
+
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(cast<ValueDecl>(ND));
+ if (DevTy.hasValue() && *DevTy != DT) {
+ Diag(Loc, diag::err_omp_device_type_mismatch)
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(DT)
+ << OMPDeclareTargetDeclAttr::ConvertDevTypeTyToStr(*DevTy);
+ return;
+ }
+ Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(cast<ValueDecl>(ND));
+ if (!Res) {
+ auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT, DT,
+ SourceRange(Loc, Loc));
+ ND->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
+ checkDeclIsAllowedInOpenMPTarget(nullptr, ND, Loc);
+ } else if (*Res != MT) {
+ Diag(Loc, diag::err_omp_declare_target_to_and_link) << ND;
}
}
@@ -14960,7 +16244,28 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
if (!D || !isa<VarDecl>(D))
return;
auto *VD = cast<VarDecl>(D);
- if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
+ Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
+ if (SemaRef.LangOpts.OpenMP >= 50 &&
+ (SemaRef.getCurLambda(/*IgnoreNonLambdaCapturingScope=*/true) ||
+ SemaRef.getCurBlock() || SemaRef.getCurCapturedRegion()) &&
+ VD->hasGlobalStorage()) {
+ llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> MapTy =
+ OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
+ if (!MapTy || *MapTy != OMPDeclareTargetDeclAttr::MT_To) {
+ // OpenMP 5.0, 2.12.7 declare target Directive, Restrictions
+ // If a lambda declaration and definition appears between a
+ // declare target directive and the matching end declare target
+ // directive, all variables that are captured by the lambda
+ // expression must also appear in a to clause.
+ SemaRef.Diag(VD->getLocation(),
+ diag::err_omp_lambda_capture_in_declare_target_not_to);
+ SemaRef.Diag(SL, diag::note_var_explicitly_captured_here)
+ << VD << 0 << SR;
+ return;
+ }
+ }
+ if (MapTy.hasValue())
return;
SemaRef.Diag(VD->getLocation(), diag::warn_omp_not_in_target_context);
SemaRef.Diag(SL, diag::note_used_here) << SR;
@@ -14969,7 +16274,7 @@ static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
Sema &SemaRef, DSAStackTy *Stack,
ValueDecl *VD) {
- return VD->hasAttr<OMPDeclareTargetDeclAttr>() ||
+ return OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) ||
checkTypeMappable(SL, SR, SemaRef, Stack, VD->getType(),
/*FullCheck=*/false);
}
@@ -14995,15 +16300,23 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
}
if (const auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
D = FTD->getTemplatedDecl();
- if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+ if (auto *FD = dyn_cast<FunctionDecl>(D)) {
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(FD);
- if (Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
- assert(IdLoc.isValid() && "Source location is expected");
+ if (IdLoc.isValid() && Res && *Res == OMPDeclareTargetDeclAttr::MT_Link) {
Diag(IdLoc, diag::err_omp_function_in_link_clause);
Diag(FD->getLocation(), diag::note_defined_here) << FD;
return;
}
+ // Mark the function as must be emitted for the device.
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
+ *DevTy != OMPDeclareTargetDeclAttr::DT_Host)
+ checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false);
+ if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
+ *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost)
+ checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false);
}
if (auto *VD = dyn_cast<ValueDecl>(D)) {
// Problem if any with var declared with incomplete type will be reported
@@ -15016,7 +16329,8 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
if (isa<VarDecl>(D) || isa<FunctionDecl>(D) ||
isa<FunctionTemplateDecl>(D)) {
auto *A = OMPDeclareTargetDeclAttr::CreateImplicit(
- Context, OMPDeclareTargetDeclAttr::MT_To);
+ Context, OMPDeclareTargetDeclAttr::MT_To,
+ OMPDeclareTargetDeclAttr::DT_Any, SourceRange(IdLoc, IdLoc));
D->addAttr(A);
if (ASTMutationListener *ML = Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPDeclareTarget(D, A);