summaryrefslogtreecommitdiff
path: root/lib/Sema/SemaOpenMP.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:49 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:49 +0000
commit2298981669bf3bd63335a4be179bc0f96823a8f4 (patch)
tree1cbe2eb27f030d2d70b80ee5ca3c86bee7326a9f /lib/Sema/SemaOpenMP.cpp
parent9a83721404652cea39e9f02ae3e3b5c964602a5c (diff)
Diffstat (limited to 'lib/Sema/SemaOpenMP.cpp')
-rw-r--r--lib/Sema/SemaOpenMP.cpp2385
1 files changed, 1867 insertions, 518 deletions
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 36048a38b999..bd68011c18b2 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -1,9 +1,8 @@
//===--- SemaOpenMP.cpp - Semantic Analysis for OpenMP constructs ---------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
@@ -135,7 +134,7 @@ private:
/// get the data (loop counters etc.) about enclosing loop-based construct.
/// This data is required during codegen.
DoacrossDependMapTy DoacrossDepends;
- /// first argument (Expr *) contains optional argument of the
+ /// First argument (Expr *) contains optional argument of the
/// 'ordered' clause, the second one is true if the regions has 'ordered'
/// clause, false otherwise.
llvm::Optional<std::pair<const Expr *, OMPOrderedClause *>> OrderedRegion;
@@ -144,10 +143,14 @@ private:
bool NowaitRegion = false;
bool CancelRegion = false;
bool LoopStart = false;
+ bool BodyComplete = false;
SourceLocation InnerTeamsRegionLoc;
/// Reference to the taskgroup task_reduction reference expression.
Expr *TaskgroupReductionRef = nullptr;
llvm::DenseSet<QualType> MappedClassesQualTypes;
+ /// List of globals marked as declare target link in this target region
+ /// (isOpenMPTargetExecutionDirective(Directive) == true).
+ llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -170,26 +173,112 @@ private:
/// captured by reference.
bool ForceCaptureByReferenceInTargetExecutable = false;
CriticalsWithHintsTy Criticals;
+ unsigned IgnoredStackElements = 0;
- using iterator = StackTy::const_reverse_iterator;
+ /// Iterators over the stack iterate in order from innermost to outermost
+ /// directive.
+ using const_iterator = StackTy::const_reverse_iterator;
+ const_iterator begin() const {
+ return Stack.empty() ? const_iterator()
+ : Stack.back().first.rbegin() + IgnoredStackElements;
+ }
+ const_iterator end() const {
+ return Stack.empty() ? const_iterator() : Stack.back().first.rend();
+ }
+ using iterator = StackTy::reverse_iterator;
+ iterator begin() {
+ return Stack.empty() ? iterator()
+ : Stack.back().first.rbegin() + IgnoredStackElements;
+ }
+ iterator end() {
+ return Stack.empty() ? iterator() : Stack.back().first.rend();
+ }
- DSAVarData getDSA(iterator &Iter, ValueDecl *D) const;
-
- /// Checks if the variable is a local for OpenMP region.
- bool isOpenMPLocal(VarDecl *D, iterator Iter) const;
+ // Convenience operations to get at the elements of the stack.
bool isStackEmpty() const {
return Stack.empty() ||
Stack.back().second != CurrentNonCapturingFunctionScope ||
- Stack.back().first.empty();
+ Stack.back().first.size() <= IgnoredStackElements;
+ }
+ size_t getStackSize() const {
+ return isStackEmpty() ? 0
+ : Stack.back().first.size() - IgnoredStackElements;
+ }
+
+ SharingMapTy *getTopOfStackOrNull() {
+ size_t Size = getStackSize();
+ if (Size == 0)
+ return nullptr;
+ return &Stack.back().first[Size - 1];
}
+ const SharingMapTy *getTopOfStackOrNull() const {
+ return const_cast<DSAStackTy&>(*this).getTopOfStackOrNull();
+ }
+ SharingMapTy &getTopOfStack() {
+ assert(!isStackEmpty() && "no current directive");
+ return *getTopOfStackOrNull();
+ }
+ const SharingMapTy &getTopOfStack() const {
+ return const_cast<DSAStackTy&>(*this).getTopOfStack();
+ }
+
+ SharingMapTy *getSecondOnStackOrNull() {
+ size_t Size = getStackSize();
+ if (Size <= 1)
+ return nullptr;
+ return &Stack.back().first[Size - 2];
+ }
+ const SharingMapTy *getSecondOnStackOrNull() const {
+ return const_cast<DSAStackTy&>(*this).getSecondOnStackOrNull();
+ }
+
+ /// Get the stack element at a certain level (previously returned by
+ /// \c getNestingLevel).
+ ///
+ /// Note that nesting levels count from outermost to innermost, and this is
+ /// the reverse of our iteration order where new inner levels are pushed at
+ /// the front of the stack.
+ SharingMapTy &getStackElemAtLevel(unsigned Level) {
+ assert(Level < getStackSize() && "no such stack element");
+ return Stack.back().first[Level];
+ }
+ const SharingMapTy &getStackElemAtLevel(unsigned Level) const {
+ return const_cast<DSAStackTy&>(*this).getStackElemAtLevel(Level);
+ }
+
+ DSAVarData getDSA(const_iterator &Iter, ValueDecl *D) const;
+
+ /// Checks if the variable is a local for OpenMP region.
+ bool isOpenMPLocal(VarDecl *D, const_iterator Iter) const;
/// Vector of previously declared requires directives
SmallVector<const OMPRequiresDecl *, 2> RequiresDecls;
+ /// omp_allocator_handle_t type.
+ QualType OMPAllocatorHandleT;
+ /// Expression for the predefined allocators.
+ Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = {
+ nullptr};
+ /// Vector of previously encountered target directives
+ SmallVector<SourceLocation, 2> TargetLocations;
public:
explicit DSAStackTy(Sema &S) : SemaRef(S) {}
+ /// Sets omp_allocator_handle_t type.
+ void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; }
+ /// Gets omp_allocator_handle_t type.
+ QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; }
+ /// Sets the given default allocator.
+ void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
+ Expr *Allocator) {
+ OMPPredefinedAllocators[AllocatorKind] = Allocator;
+ }
+ /// Returns the specified default allocator.
+ Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const {
+ return OMPPredefinedAllocators[AllocatorKind];
+ }
+
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
OpenMPClauseKind getClauseParsingMode() const {
assert(isClauseParsingMode() && "Must be in clause parsing mode.");
@@ -197,6 +286,14 @@ public:
}
void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
+ bool isBodyComplete() const {
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top && Top->BodyComplete;
+ }
+ void setBodyComplete() {
+ getTopOfStack().BodyComplete = true;
+ }
+
bool isForceVarCapturing() const { return ForceCapturing; }
void setForceVarCapturing(bool V) { ForceCapturing = V; }
@@ -209,6 +306,8 @@ public:
void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName,
Scope *CurScope, SourceLocation Loc) {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
if (Stack.empty() ||
Stack.back().second != CurrentNonCapturingFunctionScope)
Stack.emplace_back(StackTy(), CurrentNonCapturingFunctionScope);
@@ -217,46 +316,78 @@ public:
}
void pop() {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
assert(!Stack.back().first.empty() &&
"Data-sharing attributes stack is empty!");
Stack.back().first.pop_back();
}
+ /// RAII object to temporarily leave the scope of a directive when we want to
+ /// logically operate in its parent.
+ class ParentDirectiveScope {
+ DSAStackTy &Self;
+ bool Active;
+ public:
+ ParentDirectiveScope(DSAStackTy &Self, bool Activate)
+ : Self(Self), Active(false) {
+ if (Activate)
+ enable();
+ }
+ ~ParentDirectiveScope() { disable(); }
+ void disable() {
+ if (Active) {
+ --Self.IgnoredStackElements;
+ Active = false;
+ }
+ }
+ void enable() {
+ if (!Active) {
+ ++Self.IgnoredStackElements;
+ Active = true;
+ }
+ }
+ };
+
/// Marks that we're started loop parsing.
void loopInit() {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
- Stack.back().first.back().LoopStart = true;
+ getTopOfStack().LoopStart = true;
}
/// Start capturing of the variables in the loop context.
void loopStart() {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
- Stack.back().first.back().LoopStart = false;
+ getTopOfStack().LoopStart = false;
}
/// true, if variables are captured, false otherwise.
bool isLoopStarted() const {
assert(isOpenMPLoopDirective(getCurrentDirective()) &&
"Expected loop-based directive.");
- return !Stack.back().first.back().LoopStart;
+ return !getTopOfStack().LoopStart;
}
/// Marks (or clears) declaration as possibly loop counter.
void resetPossibleLoopCounter(const Decl *D = nullptr) {
- Stack.back().first.back().PossiblyLoopCounter =
+ getTopOfStack().PossiblyLoopCounter =
D ? D->getCanonicalDecl() : D;
}
/// Gets the possible loop counter decl.
const Decl *getPossiblyLoopCunter() const {
- return Stack.back().first.back().PossiblyLoopCounter;
+ return getTopOfStack().PossiblyLoopCounter;
}
/// Start new OpenMP region stack in new non-capturing function.
void pushFunction() {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
const FunctionScopeInfo *CurFnScope = SemaRef.getCurFunction();
assert(!isa<CapturingScopeInfo>(CurFnScope));
CurrentNonCapturingFunctionScope = CurFnScope;
}
/// Pop region stack for non-capturing function.
void popFunction(const FunctionScopeInfo *OldFSI) {
+ assert(!IgnoredStackElements &&
+ "cannot change stack while ignoring elements");
if (!Stack.empty() && Stack.back().second == OldFSI) {
assert(Stack.back().first.empty());
Stack.pop_back();
@@ -327,16 +458,16 @@ public:
Expr *&TaskgroupDescriptor) const;
/// Return reduction reference expression for the current taskgroup.
Expr *getTaskgroupReductionRef() const {
- assert(Stack.back().first.back().Directive == OMPD_taskgroup &&
+ assert(getTopOfStack().Directive == OMPD_taskgroup &&
"taskgroup reference expression requested for non taskgroup "
"directive.");
- return Stack.back().first.back().TaskgroupReductionRef;
+ return getTopOfStack().TaskgroupReductionRef;
}
/// Checks if the given \p VD declaration is actually a taskgroup reduction
/// descriptor variable at the \p Level of OpenMP regions.
bool isTaskgroupReductionRef(const ValueDecl *VD, unsigned Level) const {
- return Stack.back().first[Level].TaskgroupReductionRef &&
- cast<DeclRefExpr>(Stack.back().first[Level].TaskgroupReductionRef)
+ return getStackElemAtLevel(Level).TaskgroupReductionRef &&
+ cast<DeclRefExpr>(getStackElemAtLevel(Level).TaskgroupReductionRef)
->getDecl() == VD;
}
@@ -382,18 +513,18 @@ public:
/// Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
- return isStackEmpty() ? OMPD_unknown : Stack.back().first.back().Directive;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->Directive : OMPD_unknown;
}
/// Returns directive kind at specified level.
OpenMPDirectiveKind getDirective(unsigned Level) const {
assert(!isStackEmpty() && "No directive at specified level.");
- return Stack.back().first[Level].Directive;
+ return getStackElemAtLevel(Level).Directive;
}
/// Returns parent directive.
OpenMPDirectiveKind getParentDirective() const {
- if (isStackEmpty() || Stack.back().first.size() == 1)
- return OMPD_unknown;
- return std::next(Stack.back().first.rbegin())->Directive;
+ const SharingMapTy *Parent = getSecondOnStackOrNull();
+ return Parent ? Parent->Directive : OMPD_unknown;
}
/// Add requires decl to internal vector
@@ -401,6 +532,16 @@ public:
RequiresDecls.push_back(RD);
}
+ /// Checks if the defined 'requires' directive has specified type of clause.
+ template <typename ClauseType>
+ bool hasRequiresDeclWithClause() {
+ return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) {
+ return llvm::any_of(D->clauselists(), [](const OMPClause *C) {
+ return isa<ClauseType>(C);
+ });
+ });
+ }
+
/// Checks for a duplicate clause amongst previously declared requires
/// directives
bool hasDuplicateRequiresClause(ArrayRef<OMPClause *> ClauseList) const {
@@ -423,43 +564,50 @@ public:
return IsDuplicate;
}
+ /// Add location of previously encountered target to internal vector
+ void addTargetDirLocation(SourceLocation LocStart) {
+ TargetLocations.push_back(LocStart);
+ }
+
+ // Return previously encountered target region locations.
+ ArrayRef<SourceLocation> getEncounteredTargetLocs() const {
+ return TargetLocations;
+ }
+
/// Set default data sharing attribute to none.
void setDefaultDSANone(SourceLocation Loc) {
- assert(!isStackEmpty());
- Stack.back().first.back().DefaultAttr = DSA_none;
- Stack.back().first.back().DefaultAttrLoc = Loc;
+ getTopOfStack().DefaultAttr = DSA_none;
+ getTopOfStack().DefaultAttrLoc = Loc;
}
/// Set default data sharing attribute to shared.
void setDefaultDSAShared(SourceLocation Loc) {
- assert(!isStackEmpty());
- Stack.back().first.back().DefaultAttr = DSA_shared;
- Stack.back().first.back().DefaultAttrLoc = Loc;
+ getTopOfStack().DefaultAttr = DSA_shared;
+ getTopOfStack().DefaultAttrLoc = Loc;
}
/// Set default data mapping attribute to 'tofrom:scalar'.
void setDefaultDMAToFromScalar(SourceLocation Loc) {
- assert(!isStackEmpty());
- Stack.back().first.back().DefaultMapAttr = DMA_tofrom_scalar;
- Stack.back().first.back().DefaultMapAttrLoc = Loc;
+ getTopOfStack().DefaultMapAttr = DMA_tofrom_scalar;
+ getTopOfStack().DefaultMapAttrLoc = Loc;
}
DefaultDataSharingAttributes getDefaultDSA() const {
return isStackEmpty() ? DSA_unspecified
- : Stack.back().first.back().DefaultAttr;
+ : getTopOfStack().DefaultAttr;
}
SourceLocation getDefaultDSALocation() const {
return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().DefaultAttrLoc;
+ : getTopOfStack().DefaultAttrLoc;
}
DefaultMapAttributes getDefaultDMA() const {
return isStackEmpty() ? DMA_unspecified
- : Stack.back().first.back().DefaultMapAttr;
+ : getTopOfStack().DefaultMapAttr;
}
DefaultMapAttributes getDefaultDMAAtLevel(unsigned Level) const {
- return Stack.back().first[Level].DefaultMapAttr;
+ return getStackElemAtLevel(Level).DefaultMapAttr;
}
SourceLocation getDefaultDMALocation() const {
return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().DefaultMapAttrLoc;
+ : getTopOfStack().DefaultMapAttrLoc;
}
/// Checks if the specified variable is a threadprivate.
@@ -471,82 +619,77 @@ public:
/// Marks current region as ordered (it has an 'ordered' clause).
void setOrderedRegion(bool IsOrdered, const Expr *Param,
OMPOrderedClause *Clause) {
- assert(!isStackEmpty());
if (IsOrdered)
- Stack.back().first.back().OrderedRegion.emplace(Param, Clause);
+ getTopOfStack().OrderedRegion.emplace(Param, Clause);
else
- Stack.back().first.back().OrderedRegion.reset();
+ getTopOfStack().OrderedRegion.reset();
}
/// Returns true, if region is ordered (has associated 'ordered' clause),
/// false - otherwise.
bool isOrderedRegion() const {
- if (isStackEmpty())
- return false;
- return Stack.back().first.rbegin()->OrderedRegion.hasValue();
+ if (const SharingMapTy *Top = getTopOfStackOrNull())
+ return Top->OrderedRegion.hasValue();
+ return false;
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *> getOrderedRegionParam() const {
- if (isStackEmpty() ||
- !Stack.back().first.rbegin()->OrderedRegion.hasValue())
- return std::make_pair(nullptr, nullptr);
- return Stack.back().first.rbegin()->OrderedRegion.getValue();
+ if (const SharingMapTy *Top = getTopOfStackOrNull())
+ if (Top->OrderedRegion.hasValue())
+ return Top->OrderedRegion.getValue();
+ return std::make_pair(nullptr, nullptr);
}
/// Returns true, if parent region is ordered (has associated
/// 'ordered' clause), false - otherwise.
bool isParentOrderedRegion() const {
- if (isStackEmpty() || Stack.back().first.size() == 1)
- return false;
- return std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue();
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ return Parent->OrderedRegion.hasValue();
+ return false;
}
/// Returns optional parameter for the ordered region.
std::pair<const Expr *, OMPOrderedClause *>
getParentOrderedRegionParam() const {
- if (isStackEmpty() || Stack.back().first.size() == 1 ||
- !std::next(Stack.back().first.rbegin())->OrderedRegion.hasValue())
- return std::make_pair(nullptr, nullptr);
- return std::next(Stack.back().first.rbegin())->OrderedRegion.getValue();
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ if (Parent->OrderedRegion.hasValue())
+ return Parent->OrderedRegion.getValue();
+ return std::make_pair(nullptr, nullptr);
}
/// Marks current region as nowait (it has a 'nowait' clause).
void setNowaitRegion(bool IsNowait = true) {
- assert(!isStackEmpty());
- Stack.back().first.back().NowaitRegion = IsNowait;
+ getTopOfStack().NowaitRegion = IsNowait;
}
/// Returns true, if parent region is nowait (has associated
/// 'nowait' clause), false - otherwise.
bool isParentNowaitRegion() const {
- if (isStackEmpty() || Stack.back().first.size() == 1)
- return false;
- return std::next(Stack.back().first.rbegin())->NowaitRegion;
+ if (const SharingMapTy *Parent = getSecondOnStackOrNull())
+ return Parent->NowaitRegion;
+ return false;
}
/// Marks parent region as cancel region.
void setParentCancelRegion(bool Cancel = true) {
- if (!isStackEmpty() && Stack.back().first.size() > 1) {
- auto &StackElemRef = *std::next(Stack.back().first.rbegin());
- StackElemRef.CancelRegion |= StackElemRef.CancelRegion || Cancel;
- }
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->CancelRegion |= Cancel;
}
/// Return true if current region has inner cancel construct.
bool isCancelRegion() const {
- return isStackEmpty() ? false : Stack.back().first.back().CancelRegion;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->CancelRegion : false;
}
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
- assert(!isStackEmpty());
- Stack.back().first.back().AssociatedLoops = Val;
+ getTopOfStack().AssociatedLoops = Val;
}
/// Return collapse value for region.
unsigned getAssociatedLoops() const {
- return isStackEmpty() ? 0 : Stack.back().first.back().AssociatedLoops;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->AssociatedLoops : 0;
}
/// Marks current target region as one with closely nested teams
/// region.
void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) {
- if (!isStackEmpty() && Stack.back().first.size() > 1) {
- std::next(Stack.back().first.rbegin())->InnerTeamsRegionLoc =
- TeamsRegionLoc;
- }
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->InnerTeamsRegionLoc = TeamsRegionLoc;
}
/// Returns true, if current region has closely nested teams region.
bool hasInnerTeamsRegion() const {
@@ -554,16 +697,17 @@ public:
}
/// Returns location of the nested teams region (if any).
SourceLocation getInnerTeamsRegionLoc() const {
- return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().InnerTeamsRegionLoc;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->InnerTeamsRegionLoc : SourceLocation();
}
Scope *getCurScope() const {
- return isStackEmpty() ? nullptr : Stack.back().first.back().CurScope;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->CurScope : nullptr;
}
SourceLocation getConstructLoc() const {
- return isStackEmpty() ? SourceLocation()
- : Stack.back().first.back().ConstructLoc;
+ const SharingMapTy *Top = getTopOfStackOrNull();
+ return Top ? Top->ConstructLoc : SourceLocation();
}
/// Do the check specified in \a Check to all component lists and return true
@@ -576,8 +720,8 @@ public:
Check) const {
if (isStackEmpty())
return false;
- auto SI = Stack.back().first.rbegin();
- auto SE = Stack.back().first.rend();
+ auto SI = begin();
+ auto SE = end();
if (SI == SE)
return false;
@@ -606,17 +750,12 @@ public:
bool(OMPClauseMappableExprCommon::MappableExprComponentListRef,
OpenMPClauseKind)>
Check) const {
- if (isStackEmpty())
- return false;
-
- auto StartI = Stack.back().first.begin();
- auto EndI = Stack.back().first.end();
- if (std::distance(StartI, EndI) <= (int)Level)
+ if (getStackSize() <= Level)
return false;
- std::advance(StartI, Level);
- auto MI = StartI->MappedExprComponents.find(VD);
- if (MI != StartI->MappedExprComponents.end())
+ const SharingMapTy &StackElem = getStackElemAtLevel(Level);
+ auto MI = StackElem.MappedExprComponents.find(VD);
+ if (MI != StackElem.MappedExprComponents.end())
for (OMPClauseMappableExprCommon::MappableExprComponentListRef L :
MI->second.Components)
if (Check(L, MI->second.Kind))
@@ -630,10 +769,7 @@ public:
const ValueDecl *VD,
OMPClauseMappableExprCommon::MappableExprComponentListRef Components,
OpenMPClauseKind WhereFoundClauseKind) {
- assert(!isStackEmpty() &&
- "Not expecting to retrieve components from a empty stack!");
- MappedExprComponentTy &MEC =
- Stack.back().first.back().MappedExprComponents[VD];
+ MappedExprComponentTy &MEC = getTopOfStack().MappedExprComponents[VD];
// Create new entry and append the new components there.
MEC.Components.resize(MEC.Components.size() + 1);
MEC.Components.back().append(Components.begin(), Components.end());
@@ -642,19 +778,17 @@ public:
unsigned getNestingLevel() const {
assert(!isStackEmpty());
- return Stack.back().first.size() - 1;
+ return getStackSize() - 1;
}
void addDoacrossDependClause(OMPDependClause *C,
const OperatorOffsetTy &OpsOffs) {
- assert(!isStackEmpty() && Stack.back().first.size() > 1);
- SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
- assert(isOpenMPWorksharingDirective(StackElem.Directive));
- StackElem.DoacrossDepends.try_emplace(C, OpsOffs);
+ SharingMapTy *Parent = getSecondOnStackOrNull();
+ assert(Parent && isOpenMPWorksharingDirective(Parent->Directive));
+ Parent->DoacrossDepends.try_emplace(C, OpsOffs);
}
llvm::iterator_range<DoacrossDependMapTy::const_iterator>
getDoacrossDependClauses() const {
- assert(!isStackEmpty());
- const SharingMapTy &StackElem = Stack.back().first.back();
+ const SharingMapTy &StackElem = getTopOfStack();
if (isOpenMPWorksharingDirective(StackElem.Directive)) {
const DoacrossDependMapTy &Ref = StackElem.DoacrossDepends;
return llvm::make_range(Ref.begin(), Ref.end());
@@ -665,16 +799,36 @@ public:
// Store types of classes which have been explicitly mapped
void addMappedClassesQualTypes(QualType QT) {
- SharingMapTy &StackElem = Stack.back().first.back();
+ SharingMapTy &StackElem = getTopOfStack();
StackElem.MappedClassesQualTypes.insert(QT);
}
// Return set of mapped classes types
bool isClassPreviouslyMapped(QualType QT) const {
- const SharingMapTy &StackElem = Stack.back().first.back();
+ const SharingMapTy &StackElem = getTopOfStack();
return StackElem.MappedClassesQualTypes.count(QT) != 0;
}
+ /// Adds global declare target to the parent target region.
+ void addToParentTargetRegionLinkGlobals(DeclRefExpr *E) {
+ assert(*OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(
+ E->getDecl()) == OMPDeclareTargetDeclAttr::MT_Link &&
+ "Expected declare target link global.");
+ for (auto &Elem : *this) {
+ if (isOpenMPTargetExecutionDirective(Elem.Directive)) {
+ Elem.DeclareTargetLinkVarDecls.push_back(E);
+ return;
+ }
+ }
+ }
+
+ /// Returns the list of globals with declare target link if current directive
+ /// is target.
+ ArrayRef<DeclRefExpr *> getLinkGlobals() const {
+ assert(isOpenMPTargetExecutionDirective(getCurrentDirective()) &&
+ "Expected target executable directive.");
+ return getTopOfStack().DeclareTargetLinkVarDecls;
+ }
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
@@ -682,7 +836,8 @@ bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
}
bool isImplicitOrExplicitTaskingRegion(OpenMPDirectiveKind DKind) {
- return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) || DKind == OMPD_unknown;
+ return isImplicitTaskingRegion(DKind) || isOpenMPTaskingDirective(DKind) ||
+ DKind == OMPD_unknown;
}
} // namespace
@@ -728,13 +883,13 @@ static ValueDecl *getCanonicalDecl(ValueDecl *D) {
getCanonicalDecl(const_cast<const ValueDecl *>(D)));
}
-DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter,
+DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
ValueDecl *D) const {
D = getCanonicalDecl(D);
auto *VD = dyn_cast<VarDecl>(D);
const auto *FD = dyn_cast<FieldDecl>(D);
DSAVarData DVar;
- if (isStackEmpty() || Iter == Stack.back().first.rend()) {
+ if (Iter == end()) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// File-scope or namespace-scope variables referenced in called routines
@@ -809,7 +964,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(iterator &Iter,
// bound to the current team is shared.
if (isOpenMPTaskingDirective(DVar.DKind)) {
DSAVarData DVarTemp;
- iterator I = Iter, E = Stack.back().first.rend();
+ const_iterator I = Iter, E = end();
do {
++I;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
@@ -841,7 +996,7 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
const Expr *NewDE) {
assert(!isStackEmpty() && "Data sharing attributes stack is empty");
D = getCanonicalDecl(D);
- SharingMapTy &StackElem = Stack.back().first.back();
+ SharingMapTy &StackElem = getTopOfStack();
auto It = StackElem.AlignedMap.find(D);
if (It == StackElem.AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
@@ -855,7 +1010,7 @@ const Expr *DSAStackTy::addUniqueAligned(const ValueDecl *D,
void DSAStackTy::addLoopControlVariable(const ValueDecl *D, VarDecl *Capture) {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- SharingMapTy &StackElem = Stack.back().first.back();
+ SharingMapTy &StackElem = getTopOfStack();
StackElem.LCVMap.try_emplace(
D, LCDeclInfo(StackElem.LCVMap.size() + 1, Capture));
}
@@ -864,7 +1019,7 @@ const DSAStackTy::LCDeclInfo
DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- const SharingMapTy &StackElem = Stack.back().first.back();
+ const SharingMapTy &StackElem = getTopOfStack();
auto It = StackElem.LCVMap.find(D);
if (It != StackElem.LCVMap.end())
return It->second;
@@ -873,23 +1028,21 @@ DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
const DSAStackTy::LCDeclInfo
DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const {
- assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
- "Data-sharing attributes stack is empty");
+ const SharingMapTy *Parent = getSecondOnStackOrNull();
+ assert(Parent && "Data-sharing attributes stack is empty");
D = getCanonicalDecl(D);
- const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
- auto It = StackElem.LCVMap.find(D);
- if (It != StackElem.LCVMap.end())
+ auto It = Parent->LCVMap.find(D);
+ if (It != Parent->LCVMap.end())
return It->second;
return {0, nullptr};
}
const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const {
- assert(!isStackEmpty() && Stack.back().first.size() > 1 &&
- "Data-sharing attributes stack is empty");
- const SharingMapTy &StackElem = *std::next(Stack.back().first.rbegin());
- if (StackElem.LCVMap.size() < I)
+ const SharingMapTy *Parent = getSecondOnStackOrNull();
+ assert(Parent && "Data-sharing attributes stack is empty");
+ if (Parent->LCVMap.size() < I)
return nullptr;
- for (const auto &Pair : StackElem.LCVMap)
+ for (const auto &Pair : Parent->LCVMap)
if (Pair.second.first == I)
return Pair.first;
return nullptr;
@@ -904,8 +1057,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
Data.RefExpr.setPointer(E);
Data.PrivateCopy = nullptr;
} else {
- assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
- DSAInfo &Data = Stack.back().first.back().SharingMap[D];
+ DSAInfo &Data = getTopOfStack().SharingMap[D];
assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
(A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
(A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
@@ -920,8 +1072,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
Data.RefExpr.setPointerAndInt(E, IsLastprivate);
Data.PrivateCopy = PrivateCopy;
if (PrivateCopy) {
- DSAInfo &Data =
- Stack.back().first.back().SharingMap[PrivateCopy->getDecl()];
+ DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()];
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
Data.PrivateCopy = nullptr;
@@ -966,16 +1117,16 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
assert(
- Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ getTopOfStack().SharingMap[D].Attributes == OMPC_reduction &&
"Additional reduction info may be specified only for reduction items.");
- ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D];
+ ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- Stack.back().first.back().Directive == OMPD_taskgroup &&
+ getTopOfStack().Directive == OMPD_taskgroup &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(BOK, SR);
Expr *&TaskgroupReductionRef =
- Stack.back().first.back().TaskgroupReductionRef;
+ getTopOfStack().TaskgroupReductionRef;
if (!TaskgroupReductionRef) {
VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(),
SemaRef.Context.VoidPtrTy, ".task_red.");
@@ -989,16 +1140,16 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
assert(
- Stack.back().first.back().SharingMap[D].Attributes == OMPC_reduction &&
+ getTopOfStack().SharingMap[D].Attributes == OMPC_reduction &&
"Additional reduction info may be specified only for reduction items.");
- ReductionData &ReductionData = Stack.back().first.back().ReductionMap[D];
+ ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- Stack.back().first.back().Directive == OMPD_taskgroup &&
+ getTopOfStack().Directive == OMPD_taskgroup &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(ReductionRef, SR);
Expr *&TaskgroupReductionRef =
- Stack.back().first.back().TaskgroupReductionRef;
+ getTopOfStack().TaskgroupReductionRef;
if (!TaskgroupReductionRef) {
VarDecl *VD = buildVarDecl(SemaRef, SR.getBegin(),
SemaRef.Context.VoidPtrTy, ".task_red.");
@@ -1012,11 +1163,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
Expr *&TaskgroupDescriptor) const {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
- if (Stack.back().first.empty())
- return DSAVarData();
- for (iterator I = std::next(Stack.back().first.rbegin(), 1),
- E = Stack.back().first.rend();
- I != E; std::advance(I, 1)) {
+ for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
const DSAInfo &Data = I->SharingMap.lookup(D);
if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
continue;
@@ -1041,11 +1188,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
Expr *&TaskgroupDescriptor) const {
D = getCanonicalDecl(D);
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
- if (Stack.back().first.empty())
- return DSAVarData();
- for (iterator I = std::next(Stack.back().first.rbegin(), 1),
- E = Stack.back().first.rend();
- I != E; std::advance(I, 1)) {
+ for (const_iterator I = begin() + 1, E = end(); I != E; ++I) {
const DSAInfo &Data = I->SharingMap.lookup(D);
if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup)
continue;
@@ -1065,21 +1208,17 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
return DSAVarData();
}
-bool DSAStackTy::isOpenMPLocal(VarDecl *D, iterator Iter) const {
+bool DSAStackTy::isOpenMPLocal(VarDecl *D, const_iterator I) const {
D = D->getCanonicalDecl();
- if (!isStackEmpty()) {
- iterator I = Iter, E = Stack.back().first.rend();
- Scope *TopScope = nullptr;
- while (I != E && !isImplicitOrExplicitTaskingRegion(I->Directive) &&
- !isOpenMPTargetExecutionDirective(I->Directive))
- ++I;
- if (I == E)
- return false;
- TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
- Scope *CurScope = getCurScope();
- while (CurScope != TopScope && !CurScope->isDeclScope(D))
- CurScope = CurScope->getParent();
- return CurScope != TopScope;
+ for (const_iterator E = end(); I != E; ++I) {
+ if (isImplicitOrExplicitTaskingRegion(I->Directive) ||
+ isOpenMPTargetExecutionDirective(I->Directive)) {
+ Scope *TopScope = I->CurScope ? I->CurScope->getParent() : nullptr;
+ Scope *CurScope = getCurScope();
+ while (CurScope && CurScope != TopScope && !CurScope->isDeclScope(D))
+ CurScope = CurScope->getParent();
+ return CurScope != TopScope;
+ }
}
return false;
}
@@ -1167,15 +1306,14 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
if (SemaRef.getLangOpts().OpenMPCUDAMode && VD &&
VD->isLocalVarDeclOrParm() && !isStackEmpty() &&
!isLoopControlVariable(D).first) {
- iterator IterTarget =
- std::find_if(Stack.back().first.rbegin(), Stack.back().first.rend(),
- [](const SharingMapTy &Data) {
- return isOpenMPTargetExecutionDirective(Data.Directive);
- });
- if (IterTarget != Stack.back().first.rend()) {
- iterator ParentIterTarget = std::next(IterTarget, 1);
- for (iterator Iter = Stack.back().first.rbegin();
- Iter != ParentIterTarget; std::advance(Iter, 1)) {
+ const_iterator IterTarget =
+ std::find_if(begin(), end(), [](const SharingMapTy &Data) {
+ return isOpenMPTargetExecutionDirective(Data.Directive);
+ });
+ if (IterTarget != end()) {
+ const_iterator ParentIterTarget = IterTarget + 1;
+ for (const_iterator Iter = begin();
+ Iter != ParentIterTarget; ++Iter) {
if (isOpenMPLocal(VD, Iter)) {
DVar.RefExpr =
buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
@@ -1184,7 +1322,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
return DVar;
}
}
- if (!isClauseParsingMode() || IterTarget != Stack.back().first.rbegin()) {
+ if (!isClauseParsingMode() || IterTarget != begin()) {
auto DSAIter = IterTarget->SharingMap.find(D);
if (DSAIter != IterTarget->SharingMap.end() &&
isOpenMPPrivate(DSAIter->getSecond().Attributes)) {
@@ -1192,7 +1330,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
DVar.CKind = OMPC_threadprivate;
return DVar;
}
- iterator End = Stack.back().first.rend();
+ const_iterator End = end();
if (!SemaRef.isOpenMPCapturedByRef(
D, std::distance(ParentIterTarget, End))) {
DVar.RefExpr =
@@ -1216,16 +1354,28 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
// in a Construct, C/C++, predetermined, p.7]
// Variables with static storage duration that are declared in a scope
// inside the construct are shared.
- auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; };
if (VD && VD->isStaticDataMember()) {
- DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent);
- if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
+ // Check for explicitly specified attributes.
+ const_iterator I = begin();
+ const_iterator EndI = end();
+ if (FromParent && I != EndI)
+ ++I;
+ auto It = I->SharingMap.find(D);
+ if (It != I->SharingMap.end()) {
+ const DSAInfo &Data = It->getSecond();
+ DVar.RefExpr = Data.RefExpr.getPointer();
+ DVar.PrivateCopy = Data.PrivateCopy;
+ DVar.CKind = Data.Attributes;
+ DVar.ImplicitDSALoc = I->DefaultAttrLoc;
+ DVar.DKind = I->Directive;
return DVar;
+ }
DVar.CKind = OMPC_shared;
return DVar;
}
+ auto &&MatchesAlways = [](OpenMPDirectiveKind) { return true; };
// The predetermined shared attribute for const-qualified types having no
// mutable members was removed after OpenMP 3.1.
if (SemaRef.LangOpts.OpenMP <= 31) {
@@ -1252,10 +1402,10 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
// Explicitly specified attributes and local variables with predetermined
// attributes.
- iterator I = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator I = begin();
+ const_iterator EndI = end();
if (FromParent && I != EndI)
- std::advance(I, 1);
+ ++I;
auto It = I->SharingMap.find(D);
if (It != I->SharingMap.end()) {
const DSAInfo &Data = It->getSecond();
@@ -1272,14 +1422,14 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
bool FromParent) const {
if (isStackEmpty()) {
- iterator I;
+ const_iterator I;
return getDSA(I, D);
}
D = getCanonicalDecl(D);
- iterator StartI = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator StartI = begin();
+ const_iterator EndI = end();
if (FromParent && StartI != EndI)
- std::advance(StartI, 1);
+ ++StartI;
return getDSA(StartI, D);
}
@@ -1291,14 +1441,15 @@ DSAStackTy::hasDSA(ValueDecl *D,
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
- iterator I = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator I = begin();
+ const_iterator EndI = end();
if (FromParent && I != EndI)
- std::advance(I, 1);
- for (; I != EndI; std::advance(I, 1)) {
- if (!DPred(I->Directive) && !isImplicitOrExplicitTaskingRegion(I->Directive))
+ ++I;
+ for (; I != EndI; ++I) {
+ if (!DPred(I->Directive) &&
+ !isImplicitOrExplicitTaskingRegion(I->Directive))
continue;
- iterator NewI = I;
+ const_iterator NewI = I;
DSAVarData DVar = getDSA(NewI, D);
if (I == NewI && CPred(DVar.CKind))
return DVar;
@@ -1313,13 +1464,13 @@ const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
if (isStackEmpty())
return {};
D = getCanonicalDecl(D);
- iterator StartI = Stack.back().first.rbegin();
- iterator EndI = Stack.back().first.rend();
+ const_iterator StartI = begin();
+ const_iterator EndI = end();
if (FromParent && StartI != EndI)
- std::advance(StartI, 1);
+ ++StartI;
if (StartI == EndI || !DPred(StartI->Directive))
return {};
- iterator NewI = StartI;
+ const_iterator NewI = StartI;
DSAVarData DVar = getDSA(NewI, D);
return (NewI == StartI && CPred(DVar.CKind)) ? DVar : DSAVarData();
}
@@ -1327,23 +1478,19 @@ const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
bool DSAStackTy::hasExplicitDSA(
const ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
unsigned Level, bool NotLastprivate) const {
- if (isStackEmpty())
+ if (getStackSize() <= Level)
return false;
D = getCanonicalDecl(D);
- auto StartI = Stack.back().first.begin();
- auto EndI = Stack.back().first.end();
- if (std::distance(StartI, EndI) <= (int)Level)
- return false;
- std::advance(StartI, Level);
- auto I = StartI->SharingMap.find(D);
- if ((I != StartI->SharingMap.end()) &&
- I->getSecond().RefExpr.getPointer() &&
- CPred(I->getSecond().Attributes) &&
- (!NotLastprivate || !I->getSecond().RefExpr.getInt()))
+ const SharingMapTy &StackElem = getStackElemAtLevel(Level);
+ auto I = StackElem.SharingMap.find(D);
+ if (I != StackElem.SharingMap.end() &&
+ I->getSecond().RefExpr.getPointer() &&
+ CPred(I->getSecond().Attributes) &&
+ (!NotLastprivate || !I->getSecond().RefExpr.getInt()))
return true;
// Check predetermined rules for the loop control variables.
- auto LI = StartI->LCVMap.find(D);
- if (LI != StartI->LCVMap.end())
+ auto LI = StackElem.LCVMap.find(D);
+ if (LI != StackElem.LCVMap.end())
return CPred(OMPC_private);
return false;
}
@@ -1351,14 +1498,10 @@ bool DSAStackTy::hasExplicitDSA(
bool DSAStackTy::hasExplicitDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind)> DPred,
unsigned Level) const {
- if (isStackEmpty())
- return false;
- auto StartI = Stack.back().first.begin();
- auto EndI = Stack.back().first.end();
- if (std::distance(StartI, EndI) <= (int)Level)
+ if (getStackSize() <= Level)
return false;
- std::advance(StartI, Level);
- return DPred(StartI->Directive);
+ const SharingMapTy &StackElem = getStackElemAtLevel(Level);
+ return DPred(StackElem.Directive);
}
bool DSAStackTy::hasDirective(
@@ -1367,13 +1510,9 @@ bool DSAStackTy::hasDirective(
DPred,
bool FromParent) const {
// We look only in the enclosing region.
- if (isStackEmpty())
- return false;
- auto StartI = std::next(Stack.back().first.rbegin());
- auto EndI = Stack.back().first.rend();
- if (FromParent && StartI != EndI)
- StartI = std::next(StartI);
- for (auto I = StartI, EE = EndI; I != EE; ++I) {
+ size_t Skip = FromParent ? 2 : 1;
+ for (const_iterator I = begin() + std::min(Skip, getStackSize()), E = end();
+ I != E; ++I) {
if (DPred(I->Directive, I->DirectiveName, I->ConstructLoc))
return true;
}
@@ -1394,6 +1533,71 @@ void Sema::popOpenMPFunctionRegion(const FunctionScopeInfo *OldFSI) {
DSAStack->popFunction(OldFSI);
}
+static bool isOpenMPDeviceDelayedContext(Sema &S) {
+ assert(S.LangOpts.OpenMP && S.LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ return !S.isInOpenMPTargetExecutionDirective() &&
+ !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;
+}
+
+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);
+}
+
+void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) {
+ assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
+ "Expected OpenMP device compilation.");
+ assert(Callee && "Callee may not be null.");
+ FunctionDecl *Caller = getCurFunctionDecl();
+
+ // 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);
+ 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.");
+ QualType Ty = E->getType();
+ if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) ||
+ ((Ty->isFloat128Type() ||
+ (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) &&
+ !Context.getTargetInfo().hasFloat128Type()) ||
+ (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 &&
+ !Context.getTargetInfo().hasInt128Type()))
+ targetDiag(E->getExprLoc(), diag::err_omp_unsupported_type)
+ << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty
+ << Context.getTargetInfo().getTriple().str() << E->getSourceRange();
+}
+
bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
@@ -1523,12 +1727,10 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const {
if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
IsByRef =
- ((DSAStack->isForceCaptureByReferenceInTargetExecutable() &&
- !Ty->isAnyPointerType()) ||
- !DSAStack->hasExplicitDSA(
- D,
- [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
- Level, /*NotLastprivate=*/true)) &&
+ !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>() &&
@@ -1565,17 +1767,25 @@ bool Sema::isInOpenMPTargetExecutionDirective() const {
false);
}
-VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) {
+VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
+ unsigned StopAt) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
D = getCanonicalDecl(D);
+ // If we want to determine whether the variable should be captured from the
+ // perspective of the current capturing scope, and we've already left all the
+ // capturing scopes of the top directive on the stack, check from the
+ // perspective of its parent directive (if any) instead.
+ DSAStackTy::ParentDirectiveScope InParentDirectiveRAII(
+ *DSAStack, CheckScopeInfo && DSAStack->isBodyComplete());
+
// If we are attempting to capture a global variable in a directive with
// 'target' we return true so that this global is also mapped to the device.
//
auto *VD = dyn_cast<VarDecl>(D);
- if (VD && !VD->hasLocalStorage()) {
- if (isInOpenMPDeclareTargetContext() &&
- (getCurCapturedRegion() || getCurBlock() || getCurLambda())) {
+ if (VD && !VD->hasLocalStorage() &&
+ (getCurCapturedRegion() || getCurBlock() || getCurLambda())) {
+ if (isInOpenMPDeclareTargetContext()) {
// Try to mark variable as declare target if it is used in capturing
// regions.
if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
@@ -1590,48 +1800,21 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) {
return VD;
}
}
- // Capture variables captured by reference in lambdas for target-based
- // directives.
- if (VD && !DSAStack->isClauseParsingMode()) {
- if (const auto *RD = VD->getType()
- .getCanonicalType()
- .getNonReferenceType()
- ->getAsCXXRecordDecl()) {
- bool SavedForceCaptureByReferenceInTargetExecutable =
- DSAStack->isForceCaptureByReferenceInTargetExecutable();
- DSAStack->setForceCaptureByReferenceInTargetExecutable(/*V=*/true);
- if (RD->isLambda()) {
- llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
- FieldDecl *ThisCapture;
- RD->getCaptureFields(Captures, ThisCapture);
- for (const LambdaCapture &LC : RD->captures()) {
- if (LC.getCaptureKind() == LCK_ByRef) {
- VarDecl *VD = LC.getCapturedVar();
- DeclContext *VDC = VD->getDeclContext();
- if (!VDC->Encloses(CurContext))
- continue;
- DSAStackTy::DSAVarData DVarPrivate =
- DSAStack->getTopDSA(VD, /*FromParent=*/false);
- // Do not capture already captured variables.
- if (!OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD) &&
- DVarPrivate.CKind == OMPC_unknown &&
- !DSAStack->checkMappableExprComponentListsForDecl(
- D, /*CurrentRegionOnly=*/true,
- [](OMPClauseMappableExprCommon::
- MappableExprComponentListRef,
- OpenMPClauseKind) { return true; }))
- MarkVariableReferenced(LC.getLocation(), LC.getCapturedVar());
- } else if (LC.getCaptureKind() == LCK_This) {
- QualType ThisTy = getCurrentThisType();
- if (!ThisTy.isNull() &&
- Context.typesAreCompatible(ThisTy, ThisCapture->getType()))
- CheckCXXThisCapture(LC.getLocation());
- }
+
+ if (CheckScopeInfo) {
+ bool OpenMPFound = false;
+ for (unsigned I = StopAt + 1; I > 0; --I) {
+ FunctionScopeInfo *FSI = FunctionScopes[I - 1];
+ if(!isa<CapturingScopeInfo>(FSI))
+ return nullptr;
+ if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(FSI))
+ if (RSI->CapRegionKind == CR_OpenMP) {
+ OpenMPFound = true;
+ break;
}
- }
- DSAStack->setForceCaptureByReferenceInTargetExecutable(
- SavedForceCaptureByReferenceInTargetExecutable);
}
+ if (!OpenMPFound)
+ return nullptr;
}
if (DSAStack->getCurrentDirective() != OMPD_unknown &&
@@ -1647,10 +1830,16 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D) {
DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
+ // Threadprivate variables must not be captured.
+ if (isOpenMPThreadPrivate(DVarPrivate.CKind))
+ return nullptr;
+ // The variable is not private or it is the variable in the directive with
+ // default(none) clause and not used in any clause.
DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate,
[](OpenMPDirectiveKind) { return true; },
DSAStack->isClauseParsingMode());
- if (DVarPrivate.CKind != OMPC_unknown)
+ if (DVarPrivate.CKind != OMPC_unknown ||
+ (VD && DSAStack->getDefaultDSA() == DSA_none))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
}
return nullptr;
@@ -1764,6 +1953,9 @@ void Sema::EndOpenMPClause() {
DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
}
+static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses);
+
void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
// OpenMP [2.14.3.5, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a lastprivate
@@ -1794,8 +1986,10 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
*this, DE->getExprLoc(), Type.getUnqualifiedType(),
VD->getName(), VD->hasAttrs() ? &VD->getAttrs() : nullptr, DRE);
ActOnUninitializedDecl(VDPrivate);
- if (VDPrivate->isInvalidDecl())
+ if (VDPrivate->isInvalidDecl()) {
+ PrivateCopies.push_back(nullptr);
continue;
+ }
PrivateCopies.push_back(buildDeclRefExpr(
*this, VDPrivate, DE->getType(), DE->getExprLoc()));
} else {
@@ -1804,11 +1998,12 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
PrivateCopies.push_back(nullptr);
}
}
- // Set initializers to private copies if no errors were found.
- if (PrivateCopies.size() == Clause->varlist_size())
- Clause->setPrivateCopies(PrivateCopies);
+ Clause->setPrivateCopies(PrivateCopies);
}
}
+ // Check allocate clauses.
+ if (!CurContext->isDependentContext())
+ checkAllocateClauses(*this, DSAStack, D->clauses());
}
DSAStack->pop();
@@ -1837,6 +2032,11 @@ public:
}
return false;
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<VarDeclFilterCCC>(*this);
+ }
+
};
class VarOrFuncDeclFilterCCC final : public CorrectionCandidateCallback {
@@ -1847,19 +2047,25 @@ public:
explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {}
bool ValidateCandidate(const TypoCorrection &Candidate) override {
NamedDecl *ND = Candidate.getCorrectionDecl();
- if (ND && (isa<VarDecl>(ND) || isa<FunctionDecl>(ND))) {
+ if (ND && ((isa<VarDecl>(ND) && ND->getKind() == Decl::Var) ||
+ isa<FunctionDecl>(ND))) {
return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
SemaRef.getCurScope());
}
return false;
}
+
+ std::unique_ptr<CorrectionCandidateCallback> clone() override {
+ return llvm::make_unique<VarOrFuncDeclFilterCCC>(*this);
+ }
};
} // namespace
ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
CXXScopeSpec &ScopeSpec,
- const DeclarationNameInfo &Id) {
+ const DeclarationNameInfo &Id,
+ OpenMPDirectiveKind Kind) {
LookupResult Lookup(*this, Id, LookupOrdinaryName);
LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
@@ -1868,9 +2074,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
VarDecl *VD;
if (!Lookup.isSingleResult()) {
- if (TypoCorrection Corrected = CorrectTypo(
- Id, LookupOrdinaryName, CurScope, nullptr,
- llvm::make_unique<VarDeclFilterCCC>(*this), CTK_ErrorRecovery)) {
+ VarDeclFilterCCC CCC(*this);
+ if (TypoCorrection Corrected =
+ CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC,
+ CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(Lookup.empty()
? diag::err_undeclared_var_use_suggest
@@ -1892,9 +2099,9 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Syntax, C/C++]
// Variables must be file-scope, namespace-scope, or static block-scope.
- if (!VD->hasGlobalStorage()) {
+ if (Kind == OMPD_threadprivate && !VD->hasGlobalStorage()) {
Diag(Id.getLoc(), diag::err_omp_global_var_arg)
- << getOpenMPDirectiveName(OMPD_threadprivate) << !VD->isStaticLocal();
+ << getOpenMPDirectiveName(Kind) << !VD->isStaticLocal();
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1911,7 +2118,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->getDeclContext()->isTranslationUnit() &&
!getCurLexicalContext()->isTranslationUnit()) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1926,7 +2133,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (CanonicalVD->isStaticDataMember() &&
!CanonicalVD->getDeclContext()->Equals(getCurLexicalContext())) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1942,7 +2149,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
(!getCurLexicalContext()->isFileContext() ||
!getCurLexicalContext()->Encloses(CanonicalVD->getDeclContext()))) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1953,10 +2160,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Restrictions, C/C++, p.6]
// A threadprivate directive for static block-scope variables must appear
// in the scope of the variable and not in a nested scope.
- if (CanonicalVD->isStaticLocal() && CurScope &&
+ if (CanonicalVD->isLocalVarDecl() && CurScope &&
!isDeclInScope(ND, getCurLexicalContext(), CurScope)) {
Diag(Id.getLoc(), diag::err_omp_var_scope)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
bool IsDecl =
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
Diag(VD->getLocation(),
@@ -1968,9 +2175,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
// OpenMP [2.9.2, Restrictions, C/C++, p.2-6]
// A threadprivate directive must lexically precede all references to any
// of the variables in its list.
- if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) {
+ if (Kind == OMPD_threadprivate && VD->isUsed() &&
+ !DSAStack->isThreadPrivate(VD)) {
Diag(Id.getLoc(), diag::err_omp_var_used)
- << getOpenMPDirectiveName(OMPD_threadprivate) << VD;
+ << getOpenMPDirectiveName(Kind) << VD;
return ExprError();
}
@@ -2102,6 +2310,167 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
return D;
}
+static OMPAllocateDeclAttr::AllocatorTypeTy
+getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) {
+ if (!Allocator)
+ return OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ if (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
+ Allocator->isInstantiationDependent() ||
+ Allocator->containsUnexpandedParameterPack())
+ return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
+ auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc;
+ const Expr *AE = Allocator->IgnoreParenImpCasts();
+ for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
+ const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
+ llvm::FoldingSetNodeID AEId, DAEId;
+ AE->Profile(AEId, S.getASTContext(), /*Canonical=*/true);
+ DefAllocator->Profile(DAEId, S.getASTContext(), /*Canonical=*/true);
+ if (AEId == DAEId) {
+ AllocatorKindRes = AllocatorKind;
+ break;
+ }
+ }
+ return AllocatorKindRes;
+}
+
+static bool checkPreviousOMPAllocateAttribute(
+ Sema &S, DSAStackTy *Stack, Expr *RefExpr, VarDecl *VD,
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, Expr *Allocator) {
+ if (!VD->hasAttr<OMPAllocateDeclAttr>())
+ return false;
+ const auto *A = VD->getAttr<OMPAllocateDeclAttr>();
+ Expr *PrevAllocator = A->getAllocator();
+ OMPAllocateDeclAttr::AllocatorTypeTy PrevAllocatorKind =
+ getAllocatorKind(S, Stack, PrevAllocator);
+ bool AllocatorsMatch = AllocatorKind == PrevAllocatorKind;
+ if (AllocatorsMatch &&
+ AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc &&
+ Allocator && PrevAllocator) {
+ const Expr *AE = Allocator->IgnoreParenImpCasts();
+ const Expr *PAE = PrevAllocator->IgnoreParenImpCasts();
+ llvm::FoldingSetNodeID AEId, PAEId;
+ AE->Profile(AEId, S.Context, /*Canonical=*/true);
+ PAE->Profile(PAEId, S.Context, /*Canonical=*/true);
+ AllocatorsMatch = AEId == PAEId;
+ }
+ if (!AllocatorsMatch) {
+ SmallString<256> AllocatorBuffer;
+ llvm::raw_svector_ostream AllocatorStream(AllocatorBuffer);
+ if (Allocator)
+ Allocator->printPretty(AllocatorStream, nullptr, S.getPrintingPolicy());
+ SmallString<256> PrevAllocatorBuffer;
+ llvm::raw_svector_ostream PrevAllocatorStream(PrevAllocatorBuffer);
+ if (PrevAllocator)
+ PrevAllocator->printPretty(PrevAllocatorStream, nullptr,
+ S.getPrintingPolicy());
+
+ SourceLocation AllocatorLoc =
+ Allocator ? Allocator->getExprLoc() : RefExpr->getExprLoc();
+ SourceRange AllocatorRange =
+ Allocator ? Allocator->getSourceRange() : RefExpr->getSourceRange();
+ SourceLocation PrevAllocatorLoc =
+ PrevAllocator ? PrevAllocator->getExprLoc() : A->getLocation();
+ SourceRange PrevAllocatorRange =
+ PrevAllocator ? PrevAllocator->getSourceRange() : A->getRange();
+ S.Diag(AllocatorLoc, diag::warn_omp_used_different_allocator)
+ << (Allocator ? 1 : 0) << AllocatorStream.str()
+ << (PrevAllocator ? 1 : 0) << PrevAllocatorStream.str()
+ << AllocatorRange;
+ S.Diag(PrevAllocatorLoc, diag::note_omp_previous_allocator)
+ << PrevAllocatorRange;
+ return true;
+ }
+ return false;
+}
+
+static void
+applyOMPAllocateAttribute(Sema &S, VarDecl *VD,
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
+ Expr *Allocator, SourceRange SR) {
+ if (VD->hasAttr<OMPAllocateDeclAttr>())
+ return;
+ if (Allocator &&
+ (Allocator->isTypeDependent() || Allocator->isValueDependent() ||
+ Allocator->isInstantiationDependent() ||
+ Allocator->containsUnexpandedParameterPack()))
+ return;
+ auto *A = OMPAllocateDeclAttr::CreateImplicit(S.Context, AllocatorKind,
+ Allocator, SR);
+ VD->addAttr(A);
+ if (ASTMutationListener *ML = S.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPAllocate(VD, A);
+}
+
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective(
+ SourceLocation Loc, ArrayRef<Expr *> VarList,
+ ArrayRef<OMPClause *> Clauses, DeclContext *Owner) {
+ assert(Clauses.size() <= 1 && "Expected at most one clause.");
+ Expr *Allocator = nullptr;
+ if (Clauses.empty()) {
+ // OpenMP 5.0, 2.11.3 allocate Directive, Restrictions.
+ // allocate directives that appear in a target region must specify an
+ // allocator clause unless a requires directive with the dynamic_allocators
+ // clause is present in the same compilation unit.
+ if (LangOpts.OpenMPIsDevice &&
+ !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())
+ targetDiag(Loc, diag::err_expected_allocator_clause);
+ } else {
+ Allocator = cast<OMPAllocatorClause>(Clauses.back())->getAllocator();
+ }
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
+ getAllocatorKind(*this, DSAStack, Allocator);
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ auto *DE = cast<DeclRefExpr>(RefExpr);
+ auto *VD = cast<VarDecl>(DE->getDecl());
+
+ // Check if this is a TLS variable or global register.
+ if (VD->getTLSKind() != VarDecl::TLS_None ||
+ VD->hasAttr<OMPThreadPrivateDeclAttr>() ||
+ (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() &&
+ !VD->isLocalVarDecl()))
+ continue;
+
+ // If the used several times in the allocate directive, the same allocator
+ // must be used.
+ if (checkPreviousOMPAllocateAttribute(*this, DSAStack, RefExpr, VD,
+ AllocatorKind, Allocator))
+ continue;
+
+ // OpenMP, 2.11.3 allocate Directive, Restrictions, C / C++
+ // If a list item has a static storage type, the allocator expression in the
+ // allocator clause must be a constant expression that evaluates to one of
+ // the predefined memory allocator values.
+ if (Allocator && VD->hasGlobalStorage()) {
+ if (AllocatorKind == OMPAllocateDeclAttr::OMPUserDefinedMemAlloc) {
+ Diag(Allocator->getExprLoc(),
+ diag::err_omp_expected_predefined_allocator)
+ << Allocator->getSourceRange();
+ bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(VD->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << VD;
+ continue;
+ }
+ }
+
+ Vars.push_back(RefExpr);
+ applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator,
+ DE->getSourceRange());
+ }
+ if (Vars.empty())
+ return nullptr;
+ if (!Owner)
+ Owner = getCurLexicalContext();
+ auto *D = OMPAllocateDecl::Create(Context, Owner, Loc, Vars, Clauses);
+ D->setAccess(AS_public);
+ Owner->addDecl(D);
+ return DeclGroupPtrTy::make(DeclGroupRef(D));
+}
+
Sema::DeclGroupPtrTy
Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
@@ -2120,6 +2489,27 @@ Sema::ActOnOpenMPRequiresDirective(SourceLocation Loc,
OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
+ /// For target specific clauses, the requires directive cannot be
+ /// specified after the handling of any of the target regions in the
+ /// current compilation unit.
+ ArrayRef<SourceLocation> TargetLocations =
+ DSAStack->getEncounteredTargetLocs();
+ if (!TargetLocations.empty()) {
+ for (const OMPClause *CNew : ClauseList) {
+ // Check if any of the requires clauses affect target regions.
+ if (isa<OMPUnifiedSharedMemoryClause>(CNew) ||
+ isa<OMPUnifiedAddressClause>(CNew) ||
+ isa<OMPReverseOffloadClause>(CNew) ||
+ isa<OMPDynamicAllocatorsClause>(CNew)) {
+ Diag(Loc, diag::err_omp_target_before_requires)
+ << getOpenMPClauseName(CNew->getClauseKind());
+ for (SourceLocation TargetLoc : TargetLocations) {
+ Diag(TargetLoc, diag::note_omp_requires_encountered_target);
+ }
+ }
+ }
+ }
+
if (!DSAStack->hasDuplicateRequiresClause(ClauseList))
return OMPRequiresDecl::Create(Context, getCurLexicalContext(), Loc,
ClauseList);
@@ -2198,24 +2588,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
// Check implicitly captured variables.
if (!S->hasAssociatedStmt() || !S->getAssociatedStmt())
return;
- for (const CapturedStmt::Capture &Cap :
- S->getInnermostCapturedStmt()->captures()) {
- if (!Cap.capturesVariable())
- continue;
- VarDecl *VD = Cap.getCapturedVar();
- // Do not try to map the variable if it or its sub-component was mapped
- // already.
- if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
- Stack->checkMappableExprComponentListsForDecl(
- VD, /*CurrentRegionOnly=*/true,
- [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
- OpenMPClauseKind) { return true; }))
- continue;
- DeclRefExpr *DRE = buildDeclRefExpr(
- SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context),
- Cap.getLocation(), /*RefersToCapture=*/true);
- Visit(DRE);
- }
+ visitSubCaptures(S->getInnermostCapturedStmt());
}
public:
@@ -2224,9 +2597,20 @@ public:
E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
+ // Check the datasharing rules for the expressions in the clauses.
+ if (!CS) {
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
+ if (!CED->hasAttr<OMPCaptureNoInitAttr>()) {
+ Visit(CED->getInit());
+ return;
+ }
+ } else if (VD->isImplicit() || isa<OMPCapturedExprDecl>(VD))
+ // Do not analyze internal variables and do not enclose them into
+ // implicit clauses.
+ return;
VD = VD->getCanonicalDecl();
// Skip internally declared variables.
- if (VD->hasLocalStorage() && !CS->capturesVariable(VD))
+ if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD))
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
@@ -2237,8 +2621,9 @@ public:
// Skip internally declared static variables.
llvm::Optional<OMPDeclareTargetDeclAttr::MapTypeTy> Res =
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
- if (VD->hasGlobalStorage() && !CS->capturesVariable(VD) &&
- (!Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
+ if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
+ (Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
+ !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
return;
SourceLocation ELoc = E->getExprLoc();
@@ -2315,8 +2700,18 @@ public:
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false);
if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
- !Stack->isLoopControlVariable(VD).first)
+ !Stack->isLoopControlVariable(VD).first) {
ImplicitFirstprivate.push_back(E);
+ return;
+ }
+
+ // Store implicitly used globals with declare target link for parent
+ // target.
+ if (!isOpenMPTargetExecutionDirective(DKind) && Res &&
+ *Res == OMPDeclareTargetDeclAttr::MT_Link) {
+ Stack->addToParentTargetRegionLinkGlobals(E);
+ return;
+ }
}
}
void VisitMemberExpr(MemberExpr *E) {
@@ -2464,6 +2859,25 @@ public:
}
}
+ void visitSubCaptures(CapturedStmt *S) {
+ for (const CapturedStmt::Capture &Cap : S->captures()) {
+ if (!Cap.capturesVariable() && !Cap.capturesVariableByCopy())
+ continue;
+ VarDecl *VD = Cap.getCapturedVar();
+ // Do not try to map the variable if it or its sub-component was mapped
+ // already.
+ if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
+ Stack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [](OMPClauseMappableExprCommon::MappableExprComponentListRef,
+ OpenMPClauseKind) { return true; }))
+ continue;
+ DeclRefExpr *DRE = buildDeclRefExpr(
+ SemaRef, VD, VD->getType().getNonLValueExprType(SemaRef.Context),
+ Cap.getLocation(), /*RefersToCapture=*/true);
+ Visit(DRE);
+ }
+ }
bool isErrorFound() const { return ErrorFound; }
ArrayRef<Expr *> getImplicitFirstprivate() const {
return ImplicitFirstprivate;
@@ -2474,7 +2888,13 @@ public:
}
DSAAttrChecker(DSAStackTy *S, Sema &SemaRef, CapturedStmt *CS)
- : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {}
+ : Stack(S), SemaRef(SemaRef), ErrorFound(false), CS(CS) {
+ // Process declare target link variables for the target directives.
+ if (isOpenMPTargetExecutionDirective(S->getCurrentDirective())) {
+ for (DeclRefExpr *E : Stack->getLinkGlobals())
+ Visit(E);
+ }
+ }
};
} // namespace
@@ -2802,6 +3222,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
break;
}
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_taskyield:
case OMPD_barrier:
case OMPD_taskwait:
@@ -2809,6 +3230,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_cancel:
case OMPD_flush:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_target:
case OMPD_end_declare_target:
@@ -2915,6 +3337,46 @@ public:
};
} // namespace
+void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) {
+ // Capture variables captured by reference in lambdas for target-based
+ // directives.
+ if (!CurContext->isDependentContext() &&
+ (isOpenMPTargetExecutionDirective(DSAStack->getCurrentDirective()) ||
+ isOpenMPTargetDataManagementDirective(
+ DSAStack->getCurrentDirective()))) {
+ QualType Type = V->getType();
+ if (const auto *RD = Type.getCanonicalType()
+ .getNonReferenceType()
+ ->getAsCXXRecordDecl()) {
+ bool SavedForceCaptureByReferenceInTargetExecutable =
+ DSAStack->isForceCaptureByReferenceInTargetExecutable();
+ DSAStack->setForceCaptureByReferenceInTargetExecutable(
+ /*V=*/true);
+ if (RD->isLambda()) {
+ llvm::DenseMap<const VarDecl *, FieldDecl *> Captures;
+ FieldDecl *ThisCapture;
+ RD->getCaptureFields(Captures, ThisCapture);
+ for (const LambdaCapture &LC : RD->captures()) {
+ if (LC.getCaptureKind() == LCK_ByRef) {
+ VarDecl *VD = LC.getCapturedVar();
+ DeclContext *VDC = VD->getDeclContext();
+ if (!VDC->Encloses(CurContext))
+ continue;
+ MarkVariableReferenced(LC.getLocation(), VD);
+ } else if (LC.getCaptureKind() == LCK_This) {
+ QualType ThisTy = getCurrentThisType();
+ if (!ThisTy.isNull() &&
+ Context.typesAreCompatible(ThisTy, ThisCapture->getType()))
+ CheckCXXThisCapture(LC.getLocation());
+ }
+ }
+ }
+ DSAStack->setForceCaptureByReferenceInTargetExecutable(
+ SavedForceCaptureByReferenceInTargetExecutable);
+ }
+ }
+}
+
StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ArrayRef<OMPClause *> Clauses) {
bool ErrorFound = false;
@@ -3004,6 +3466,7 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
return StmtError();
}
StmtResult SR = S;
+ unsigned CompletedRegions = 0;
for (OpenMPDirectiveKind ThisCaptureRegion : llvm::reverse(CaptureRegions)) {
// Mark all variables in private list clauses as used in inner region.
// Required for proper codegen of combined directives.
@@ -3025,6 +3488,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
}
}
}
+ if (++CompletedRegions == CaptureRegions.size())
+ DSAStack->setBodyComplete();
SR = ActOnCapturedRegionEnd(SR.get());
}
return SR;
@@ -3346,6 +3811,169 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
return ErrorFound;
}
+static std::pair<ValueDecl *, bool>
+getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
+ SourceRange &ERange, bool AllowArraySection = false) {
+ if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
+ RefExpr->containsUnexpandedParameterPack())
+ return std::make_pair(nullptr, true);
+
+ // OpenMP [3.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.9.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ RefExpr = RefExpr->IgnoreParens();
+ enum {
+ NoArrayExpr = -1,
+ ArraySubscript = 0,
+ OMPArraySection = 1
+ } IsArrayExpr = NoArrayExpr;
+ if (AllowArraySection) {
+ if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) {
+ Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ RefExpr = Base;
+ IsArrayExpr = ArraySubscript;
+ } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) {
+ Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
+ Base = TempOASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ RefExpr = Base;
+ IsArrayExpr = OMPArraySection;
+ }
+ }
+ ELoc = RefExpr->getExprLoc();
+ ERange = RefExpr->getSourceRange();
+ RefExpr = RefExpr->IgnoreParenImpCasts();
+ auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
+ auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr);
+ if ((!DE || !isa<VarDecl>(DE->getDecl())) &&
+ (S.getCurrentThisType().isNull() || !ME ||
+ !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) ||
+ !isa<FieldDecl>(ME->getMemberDecl()))) {
+ if (IsArrayExpr != NoArrayExpr) {
+ S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr
+ << ERange;
+ } else {
+ S.Diag(ELoc,
+ AllowArraySection
+ ? diag::err_omp_expected_var_name_member_expr_or_array_item
+ : diag::err_omp_expected_var_name_member_expr)
+ << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange;
+ }
+ return std::make_pair(nullptr, false);
+ }
+ return std::make_pair(
+ getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
+}
+
+static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses) {
+ assert(!S.CurContext->isDependentContext() &&
+ "Expected non-dependent context.");
+ auto AllocateRange =
+ llvm::make_filter_range(Clauses, OMPAllocateClause::classof);
+ llvm::DenseMap<CanonicalDeclPtr<Decl>, CanonicalDeclPtr<VarDecl>>
+ DeclToCopy;
+ auto PrivateRange = llvm::make_filter_range(Clauses, [](const OMPClause *C) {
+ return isOpenMPPrivate(C->getClauseKind());
+ });
+ for (OMPClause *Cl : PrivateRange) {
+ MutableArrayRef<Expr *>::iterator I, It, Et;
+ if (Cl->getClauseKind() == OMPC_private) {
+ auto *PC = cast<OMPPrivateClause>(Cl);
+ I = PC->private_copies().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_firstprivate) {
+ auto *PC = cast<OMPFirstprivateClause>(Cl);
+ I = PC->private_copies().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_lastprivate) {
+ auto *PC = cast<OMPLastprivateClause>(Cl);
+ I = PC->private_copies().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_linear) {
+ auto *PC = cast<OMPLinearClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_reduction) {
+ auto *PC = cast<OMPReductionClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_task_reduction) {
+ auto *PC = cast<OMPTaskReductionClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else if (Cl->getClauseKind() == OMPC_in_reduction) {
+ auto *PC = cast<OMPInReductionClause>(Cl);
+ I = PC->privates().begin();
+ It = PC->varlist_begin();
+ Et = PC->varlist_end();
+ } else {
+ llvm_unreachable("Expected private clause.");
+ }
+ for (Expr *E : llvm::make_range(It, Et)) {
+ if (!*I) {
+ ++I;
+ continue;
+ }
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = E;
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ DeclToCopy.try_emplace(Res.first,
+ cast<VarDecl>(cast<DeclRefExpr>(*I)->getDecl()));
+ ++I;
+ }
+ }
+ for (OMPClause *C : AllocateRange) {
+ auto *AC = cast<OMPAllocateClause>(C);
+ OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
+ getAllocatorKind(S, Stack, AC->getAllocator());
+ // OpenMP, 2.11.4 allocate Clause, Restrictions.
+ // For task, taskloop or target directives, allocation requests to memory
+ // allocators with the trait access set to thread result in unspecified
+ // behavior.
+ if (AllocatorKind == OMPAllocateDeclAttr::OMPThreadMemAlloc &&
+ (isOpenMPTaskingDirective(Stack->getCurrentDirective()) ||
+ isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()))) {
+ S.Diag(AC->getAllocator()->getExprLoc(),
+ diag::warn_omp_allocate_thread_on_task_target_directive)
+ << getOpenMPDirectiveName(Stack->getCurrentDirective());
+ }
+ for (Expr *E : AC->varlists()) {
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = E;
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange);
+ ValueDecl *VD = Res.first;
+ DSAStackTy::DSAVarData Data = Stack->getTopDSA(VD, /*FromParent=*/false);
+ if (!isOpenMPPrivate(Data.CKind)) {
+ S.Diag(E->getExprLoc(),
+ diag::err_omp_expected_private_copy_for_allocate);
+ continue;
+ }
+ VarDecl *PrivateVD = DeclToCopy[VD];
+ if (checkPreviousOMPAllocateAttribute(S, Stack, E, PrivateVD,
+ AllocatorKind, AC->getAllocator()))
+ continue;
+ applyOMPAllocateAttribute(S, PrivateVD, AllocatorKind, AC->getAllocator(),
+ E->getSourceRange());
+ }
+ }
+}
+
StmtResult Sema::ActOnOpenMPExecutableDirective(
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
@@ -3371,6 +3999,17 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
while (--ThisCaptureLevel >= 0)
S = cast<CapturedStmt>(S)->getCapturedStmt();
DSAChecker.Visit(S);
+ if (!isOpenMPTargetDataManagementDirective(Kind) &&
+ !isOpenMPTaskingDirective(Kind)) {
+ // Visit subcaptures to generate implicit clauses for captured vars.
+ auto *CS = cast<CapturedStmt>(AStmt);
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, Kind);
+ // Ignore outer tasking regions for target directives.
+ if (CaptureRegions.size() > 1 && CaptureRegions.front() == OMPD_task)
+ CS = cast<CapturedStmt>(CS->getCapturedStmt());
+ DSAChecker.visitSubCaptures(CS);
+ }
if (DSAChecker.isErrorFound())
return StmtError();
// Generate list of implicitly defined firstprivate variables.
@@ -3401,11 +4040,12 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
}
}
if (!ImplicitMaps.empty()) {
+ CXXScopeSpec MapperIdScopeSpec;
+ DeclarationNameInfo MapperId;
if (OMPClause *Implicit = ActOnOpenMPMapClause(
- llvm::None, llvm::None, OMPC_MAP_tofrom,
- /*IsMapTypeImplicit=*/true, SourceLocation(), SourceLocation(),
- ImplicitMaps, SourceLocation(), SourceLocation(),
- SourceLocation())) {
+ llvm::None, llvm::None, MapperIdScopeSpec, MapperId,
+ OMPC_MAP_tofrom, /*IsMapTypeImplicit=*/true, SourceLocation(),
+ SourceLocation(), ImplicitMaps, OMPVarListLocTy())) {
ClausesWithImplicit.emplace_back(Implicit);
ErrorFound |=
cast<OMPMapClause>(Implicit)->varlist_size() != ImplicitMaps.size();
@@ -3656,7 +4296,9 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_threadprivate:
+ case OMPD_allocate:
case OMPD_declare_reduction:
+ case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_requires:
llvm_unreachable("OpenMP Directive is not allowed");
@@ -3664,11 +4306,99 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
llvm_unreachable("Unknown OpenMP directive");
}
+ ErrorFound = Res.isInvalid() || ErrorFound;
+
+ // Check variables in the clauses if default(none) was specified.
+ if (DSAStack->getDefaultDSA() == DSA_none) {
+ DSAAttrChecker DSAChecker(DSAStack, *this, nullptr);
+ for (OMPClause *C : Clauses) {
+ switch (C->getClauseKind()) {
+ case OMPC_num_threads:
+ case OMPC_dist_schedule:
+ // Do not analyse if no parent teams directive.
+ if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()))
+ break;
+ continue;
+ case OMPC_if:
+ if (isOpenMPTeamsDirective(DSAStack->getCurrentDirective()) &&
+ cast<OMPIfClause>(C)->getNameModifier() != OMPD_target)
+ break;
+ continue;
+ case OMPC_schedule:
+ break;
+ 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:
+ case OMPC_firstprivate:
+ case OMPC_lastprivate:
+ case OMPC_shared:
+ case OMPC_reduction:
+ case OMPC_task_reduction:
+ case OMPC_in_reduction:
+ case OMPC_linear:
+ case OMPC_aligned:
+ case OMPC_copyin:
+ case OMPC_copyprivate:
+ case OMPC_nowait:
+ case OMPC_untied:
+ case OMPC_mergeable:
+ case OMPC_allocate:
+ case OMPC_read:
+ case OMPC_write:
+ case OMPC_update:
+ case OMPC_capture:
+ case OMPC_seq_cst:
+ case OMPC_depend:
+ case OMPC_threads:
+ case OMPC_simd:
+ case OMPC_map:
+ case OMPC_nogroup:
+ case OMPC_defaultmap:
+ case OMPC_to:
+ case OMPC_from:
+ case OMPC_use_device_ptr:
+ case OMPC_is_device_ptr:
+ continue;
+ case OMPC_allocator:
+ case OMPC_flush:
+ case OMPC_threadprivate:
+ case OMPC_uniform:
+ case OMPC_unknown:
+ case OMPC_unified_address:
+ case OMPC_unified_shared_memory:
+ case OMPC_reverse_offload:
+ case OMPC_dynamic_allocators:
+ case OMPC_atomic_default_mem_order:
+ llvm_unreachable("Unexpected clause");
+ }
+ for (Stmt *CC : C->children()) {
+ if (CC)
+ DSAChecker.Visit(CC);
+ }
+ }
+ for (auto &P : DSAChecker.getVarsWithInheritedDSA())
+ VarsWithInheritedDSA[P.getFirst()] = P.getSecond();
+ }
for (const auto &P : VarsWithInheritedDSA) {
+ if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst()))
+ continue;
+ ErrorFound = true;
Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable)
<< P.first << P.second->getSourceRange();
+ Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none);
}
- ErrorFound = !VarsWithInheritedDSA.empty() || ErrorFound;
if (!AllowedNameModifiers.empty())
ErrorFound = checkIfClauses(*this, Kind, Clauses, AllowedNameModifiers) ||
@@ -3676,6 +4406,23 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (ErrorFound)
return StmtError();
+
+ if (!(Res.getAs<OMPExecutableDirective>()->isStandaloneDirective())) {
+ Res.getAs<OMPExecutableDirective>()
+ ->getStructuredBlock()
+ ->setIsOMPStructuredBlock(true);
+ }
+
+ if (!CurContext->isDependentContext() &&
+ isOpenMPTargetExecutionDirective(Kind) &&
+ !(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
+ DSAStack->hasRequiresDeclWithClause<OMPUnifiedAddressClause>() ||
+ DSAStack->hasRequiresDeclWithClause<OMPReverseOffloadClause>() ||
+ DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())) {
+ // Register target to DSA Stack.
+ DSAStack->addTargetDirLocation(StartLoc);
+ }
+
return Res;
}
@@ -3953,6 +4700,8 @@ namespace {
class OpenMPIterationSpaceChecker {
/// Reference to Sema.
Sema &SemaRef;
+ /// Data-sharing stack.
+ DSAStackTy &Stack;
/// A location for diagnostics (when there is no some better location).
SourceLocation DefaultLoc;
/// A location for diagnostics (when increment is not compatible).
@@ -3984,10 +4733,22 @@ class OpenMPIterationSpaceChecker {
bool TestIsStrictOp = false;
/// This flag is true when step is subtracted on each iteration.
bool SubtractStep = false;
+ /// The outer loop counter this loop depends on (if any).
+ const ValueDecl *DepDecl = nullptr;
+ /// Contains number of loop (starts from 1) on which loop counter init
+ /// expression of this loop depends on.
+ Optional<unsigned> InitDependOnLC;
+ /// Contains number of loop (starts from 1) on which loop counter condition
+ /// expression of this loop depends on.
+ Optional<unsigned> CondDependOnLC;
+ /// Checks if the provide statement depends on the loop counter.
+ Optional<unsigned> doesDependOnLoopCounter(const Stmt *S, bool IsInitializer);
public:
- OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
- : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {}
+ OpenMPIterationSpaceChecker(Sema &SemaRef, DSAStackTy &Stack,
+ SourceLocation DefaultLoc)
+ : SemaRef(SemaRef), Stack(Stack), DefaultLoc(DefaultLoc),
+ ConditionLoc(DefaultLoc) {}
/// Check init-expr for canonical loop form and save loop counter
/// variable - #Var and its initialization value - #LB.
bool checkAndSetInit(Stmt *S, bool EmitDiags = true);
@@ -4009,6 +4770,8 @@ public:
SourceRange getIncrementSrcRange() const { return IncrementSrcRange; }
/// True if the step should be subtracted.
bool shouldSubtractStep() const { return SubtractStep; }
+ /// True, if the compare operator is strict (<, > or !=).
+ bool isStrictTestOp() const { return TestIsStrictOp; }
/// Build the expression to calculate the number of iterations.
Expr *buildNumIterations(
Scope *S, const bool LimitedType,
@@ -4043,7 +4806,8 @@ private:
/// expression.
bool checkAndSetIncRHS(Expr *RHS);
/// Helper to set loop counter variable and its initializer.
- bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB);
+ bool setLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB,
+ bool EmitDiags);
/// Helper to set upper bound.
bool setUB(Expr *NewUB, llvm::Optional<bool> LessOp, bool StrictOp,
SourceRange SR, SourceLocation SL);
@@ -4063,7 +4827,7 @@ bool OpenMPIterationSpaceChecker::dependent() const {
bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
Expr *NewLCRefExpr,
- Expr *NewLB) {
+ Expr *NewLB, bool EmitDiags) {
// State consistency checking to ensure correct usage.
assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr &&
UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
@@ -4078,10 +4842,13 @@ bool OpenMPIterationSpaceChecker::setLCDeclAndLB(ValueDecl *NewLCDecl,
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
NewLB = CE->getArg(0)->IgnoreParenImpCasts();
LB = NewLB;
+ if (EmitDiags)
+ InitDependOnLC = doesDependOnLoopCounter(LB, /*IsInitializer=*/true);
return false;
}
-bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp,
+bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB,
+ llvm::Optional<bool> LessOp,
bool StrictOp, SourceRange SR,
SourceLocation SL) {
// State consistency checking to ensure correct usage.
@@ -4095,6 +4862,7 @@ bool OpenMPIterationSpaceChecker::setUB(Expr *NewUB, llvm::Optional<bool> LessOp
TestIsStrictOp = StrictOp;
ConditionSrcRange = SR;
ConditionLoc = SL;
+ CondDependOnLC = doesDependOnLoopCounter(UB, /*IsInitializer=*/false);
return false;
}
@@ -4160,6 +4928,110 @@ bool OpenMPIterationSpaceChecker::setStep(Expr *NewStep, bool Subtract) {
return false;
}
+namespace {
+/// Checker for the non-rectangular loops. Checks if the initializer or
+/// condition expression references loop counter variable.
+class LoopCounterRefChecker final
+ : public ConstStmtVisitor<LoopCounterRefChecker, bool> {
+ Sema &SemaRef;
+ DSAStackTy &Stack;
+ const ValueDecl *CurLCDecl = nullptr;
+ const ValueDecl *DepDecl = nullptr;
+ const ValueDecl *PrevDepDecl = nullptr;
+ bool IsInitializer = true;
+ unsigned BaseLoopId = 0;
+ bool checkDecl(const Expr *E, const ValueDecl *VD) {
+ if (getCanonicalDecl(VD) == getCanonicalDecl(CurLCDecl)) {
+ SemaRef.Diag(E->getExprLoc(), diag::err_omp_stmt_depends_on_loop_counter)
+ << (IsInitializer ? 0 : 1);
+ return false;
+ }
+ const auto &&Data = Stack.isLoopControlVariable(VD);
+ // OpenMP, 2.9.1 Canonical Loop Form, Restrictions.
+ // The type of the loop iterator on which we depend may not have a random
+ // access iterator type.
+ if (Data.first && VD->getType()->isRecordType()) {
+ SmallString<128> Name;
+ llvm::raw_svector_ostream OS(Name);
+ VD->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(),
+ /*Qualified=*/true);
+ SemaRef.Diag(E->getExprLoc(),
+ diag::err_omp_wrong_dependency_iterator_type)
+ << OS.str();
+ SemaRef.Diag(VD->getLocation(), diag::note_previous_decl) << VD;
+ return false;
+ }
+ if (Data.first &&
+ (DepDecl || (PrevDepDecl &&
+ getCanonicalDecl(VD) != getCanonicalDecl(PrevDepDecl)))) {
+ if (!DepDecl && PrevDepDecl)
+ DepDecl = PrevDepDecl;
+ SmallString<128> Name;
+ llvm::raw_svector_ostream OS(Name);
+ DepDecl->getNameForDiagnostic(OS, SemaRef.getPrintingPolicy(),
+ /*Qualified=*/true);
+ SemaRef.Diag(E->getExprLoc(),
+ diag::err_omp_invariant_or_linear_dependency)
+ << OS.str();
+ return false;
+ }
+ if (Data.first) {
+ DepDecl = VD;
+ BaseLoopId = Data.first;
+ }
+ return Data.first;
+ }
+
+public:
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ const ValueDecl *VD = E->getDecl();
+ if (isa<VarDecl>(VD))
+ return checkDecl(E, VD);
+ return false;
+ }
+ bool VisitMemberExpr(const MemberExpr *E) {
+ if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) {
+ const ValueDecl *VD = E->getMemberDecl();
+ if (isa<VarDecl>(VD) || isa<FieldDecl>(VD))
+ return checkDecl(E, VD);
+ }
+ return false;
+ }
+ bool VisitStmt(const Stmt *S) {
+ bool Res = true;
+ for (const Stmt *Child : S->children())
+ Res = Child && Visit(Child) && Res;
+ return Res;
+ }
+ explicit LoopCounterRefChecker(Sema &SemaRef, DSAStackTy &Stack,
+ const ValueDecl *CurLCDecl, bool IsInitializer,
+ const ValueDecl *PrevDepDecl = nullptr)
+ : SemaRef(SemaRef), Stack(Stack), CurLCDecl(CurLCDecl),
+ PrevDepDecl(PrevDepDecl), IsInitializer(IsInitializer) {}
+ unsigned getBaseLoopId() const {
+ assert(CurLCDecl && "Expected loop dependency.");
+ return BaseLoopId;
+ }
+ const ValueDecl *getDepDecl() const {
+ assert(CurLCDecl && "Expected loop dependency.");
+ return DepDecl;
+ }
+};
+} // namespace
+
+Optional<unsigned>
+OpenMPIterationSpaceChecker::doesDependOnLoopCounter(const Stmt *S,
+ bool IsInitializer) {
+ // Check for the non-rectangular loops.
+ LoopCounterRefChecker LoopStmtChecker(SemaRef, Stack, LCDecl, IsInitializer,
+ DepDecl);
+ if (LoopStmtChecker.Visit(S)) {
+ DepDecl = LoopStmtChecker.getDepDecl();
+ return LoopStmtChecker.getBaseLoopId();
+ }
+ return llvm::None;
+}
+
bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
// Check init-expr for canonical loop form and save loop counter
// variable - #Var and its initialization value - #LB.
@@ -4188,13 +5060,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
- return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
- return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS());
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
+ return setLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS(), EmitDiags);
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
- return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
}
}
} else if (auto *DS = dyn_cast<DeclStmt>(S)) {
@@ -4211,7 +5085,7 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
buildDeclRefExpr(SemaRef, Var,
Var->getType().getNonReferenceType(),
DS->getBeginLoc()),
- Var->getInit());
+ Var->getInit(), EmitDiags);
}
}
}
@@ -4221,13 +5095,15 @@ bool OpenMPIterationSpaceChecker::checkAndSetInit(Stmt *S, bool EmitDiags) {
if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
- return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
- return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1));
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
+ return setLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1), EmitDiags);
}
if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
if (ME->isArrow() &&
isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
- return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ return setLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS(),
+ EmitDiags);
}
}
}
@@ -4581,7 +5457,7 @@ Expr *OpenMPIterationSpaceChecker::buildPreCond(
/*AllowExplicit=*/true);
}
SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
- // Otherwise use original loop conditon and evaluate it in runtime.
+ // Otherwise use original loop condition and evaluate it in runtime.
return CondExpr.isUsable() ? CondExpr.get() : Cond;
}
@@ -4602,8 +5478,7 @@ DeclRefExpr *OpenMPIterationSpaceChecker::buildCounterVar(
Captures.insert(std::make_pair(LCRef, Ref));
return Ref;
}
- return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(),
- DefaultLoc);
+ return cast<DeclRefExpr>(LCRef);
}
Expr *OpenMPIterationSpaceChecker::buildPrivateCounterVar() const {
@@ -4648,10 +5523,12 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
// Upper - Lower
- Expr *Upper =
- TestIsLessOp.getValue() ? Cnt : tryBuildCapture(SemaRef, UB, Captures).get();
- Expr *Lower =
- TestIsLessOp.getValue() ? tryBuildCapture(SemaRef, LB, Captures).get() : Cnt;
+ Expr *Upper = TestIsLessOp.getValue()
+ ? Cnt
+ : tryBuildCapture(SemaRef, UB, Captures).get();
+ Expr *Lower = TestIsLessOp.getValue()
+ ? tryBuildCapture(SemaRef, LB, Captures).get()
+ : Cnt;
if (!Upper || !Lower)
return nullptr;
@@ -4687,6 +5564,9 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
/// 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.
@@ -4720,7 +5600,7 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
if (AssociatedLoops > 0 &&
isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
DSAStack->loopStart();
- OpenMPIterationSpaceChecker ISC(*this, ForLoc);
+ OpenMPIterationSpaceChecker ISC(*this, *DSAStack, ForLoc);
if (!ISC.checkAndSetInit(Init, /*EmitDiags=*/false)) {
if (ValueDecl *D = ISC.getLoopDecl()) {
auto *VD = dyn_cast<VarDecl>(D);
@@ -4786,7 +5666,7 @@ static bool checkOpenMPIterationSpace(
}
assert(For->getBody());
- OpenMPIterationSpaceChecker ISC(SemaRef, For->getForLoc());
+ OpenMPIterationSpaceChecker ISC(SemaRef, DSA, For->getForLoc());
// Check init.
Stmt *Init = For->getInit();
@@ -4840,12 +5720,14 @@ static bool checkOpenMPIterationSpace(
? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
: OMPC_private;
if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != PredeterminedCKind) ||
+ 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 != nullptr)) {
+ (DVar.CKind != OMPC_private || DVar.RefExpr)) {
SemaRef.Diag(Init->getBeginLoc(), diag::err_omp_loop_var_dsa)
<< getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
<< getOpenMPClauseName(PredeterminedCKind);
@@ -4859,10 +5741,7 @@ static bool checkOpenMPIterationSpace(
// lastprivate (for simd directives with several collapsed or ordered
// loops).
if (DVar.CKind == OMPC_unknown)
- DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate,
- [](OpenMPDirectiveKind) -> bool { return true; },
- /*FromParent=*/false);
- DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
+ DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
}
assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
@@ -4893,6 +5772,7 @@ static bool checkOpenMPIterationSpace(
ResultIterSpace.CondSrcRange = ISC.getConditionSrcRange();
ResultIterSpace.IncSrcRange = ISC.getIncrementSrcRange();
ResultIterSpace.Subtract = ISC.shouldSubtractStep();
+ ResultIterSpace.IsStrictCompare = ISC.isStrictTestOp();
HasErrors |= (ResultIterSpace.PreCond == nullptr ||
ResultIterSpace.NumIterations == nullptr ||
@@ -5117,14 +5997,21 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (CollapseLoopCountExpr) {
// Found 'collapse' clause - calculate collapse number.
Expr::EvalResult Result;
- if (CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext()))
+ if (!CollapseLoopCountExpr->isValueDependent() &&
+ CollapseLoopCountExpr->EvaluateAsInt(Result, SemaRef.getASTContext())) {
NestedLoopCount = Result.Val.getInt().getLimitedValue();
+ } else {
+ Built.clear(/*Size=*/1);
+ return 1;
+ }
}
unsigned OrderedLoopCount = 1;
if (OrderedLoopCountExpr) {
// Found 'ordered' clause - calculate collapse number.
Expr::EvalResult EVResult;
- if (OrderedLoopCountExpr->EvaluateAsInt(EVResult, SemaRef.getASTContext())) {
+ if (!OrderedLoopCountExpr->isValueDependent() &&
+ OrderedLoopCountExpr->EvaluateAsInt(EVResult,
+ SemaRef.getASTContext())) {
llvm::APSInt Result = EVResult.Val.getInt();
if (Result.getLimitedValue() < NestedLoopCount) {
SemaRef.Diag(OrderedLoopCountExpr->getExprLoc(),
@@ -5135,13 +6022,16 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
<< CollapseLoopCountExpr->getSourceRange();
}
OrderedLoopCount = Result.getLimitedValue();
+ } else {
+ Built.clear(/*Size=*/1);
+ return 1;
}
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
llvm::MapVector<const Expr *, DeclRefExpr *> Captures;
- SmallVector<LoopIterationSpace, 4> IterSpaces;
- IterSpaces.resize(std::max(OrderedLoopCount, NestedLoopCount));
+ SmallVector<LoopIterationSpace, 4> IterSpaces(
+ std::max(OrderedLoopCount, NestedLoopCount));
Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
for (unsigned Cnt = 0; Cnt < NestedLoopCount; ++Cnt) {
if (checkOpenMPIterationSpace(
@@ -5447,25 +6337,55 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
}
}
- // Loop condition (IV < NumIterations) or (IV <= UB) for worksharing loops.
+ bool UseStrictCompare =
+ RealVType->hasUnsignedIntegerRepresentation() &&
+ llvm::all_of(IterSpaces, [](const LoopIterationSpace &LIS) {
+ return LIS.IsStrictCompare;
+ });
+ // Loop condition (IV < NumIterations) or (IV <= UB or IV < UB + 1 (for
+ // unsigned IV)) for worksharing loops.
SourceLocation CondLoc = AStmt->getBeginLoc();
+ Expr *BoundUB = UB.get();
+ if (UseStrictCompare) {
+ BoundUB =
+ SemaRef
+ .BuildBinOp(CurScope, CondLoc, BO_Add, BoundUB,
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get())
+ .get();
+ BoundUB =
+ SemaRef.ActOnFinishFullExpr(BoundUB, /*DiscardedValue*/ false).get();
+ }
ExprResult Cond =
(isOpenMPWorksharingDirective(DKind) ||
isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind))
- ? SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get())
+ ? SemaRef.BuildBinOp(CurScope, CondLoc,
+ UseStrictCompare ? BO_LT : BO_LE, IV.get(),
+ BoundUB)
: SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
NumIterations.get());
ExprResult CombDistCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
- CombDistCond =
- SemaRef.BuildBinOp(
- CurScope, CondLoc, BO_LT, IV.get(), NumIterations.get());
+ CombDistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LT, IV.get(),
+ NumIterations.get());
}
ExprResult CombCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ Expr *BoundCombUB = CombUB.get();
+ if (UseStrictCompare) {
+ BoundCombUB =
+ SemaRef
+ .BuildBinOp(
+ CurScope, CondLoc, BO_Add, BoundCombUB,
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get())
+ .get();
+ BoundCombUB =
+ SemaRef.ActOnFinishFullExpr(BoundCombUB, /*DiscardedValue*/ false)
+ .get();
+ }
CombCond =
- SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), CombUB.get());
+ SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE,
+ IV.get(), BoundCombUB);
}
// Loop increment (IV = IV + 1)
SourceLocation IncLoc = AStmt->getBeginLoc();
@@ -5542,7 +6462,8 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
SourceLocation DistIncLoc = AStmt->getBeginLoc();
ExprResult DistCond, DistInc, PrevEUB, ParForInDistCond;
if (isOpenMPLoopBoundSharingDirective(DKind)) {
- DistCond = SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), UB.get());
+ DistCond = SemaRef.BuildBinOp(
+ CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE, IV.get(), BoundUB);
assert(DistCond.isUsable() && "distribute cond expr was not built");
DistInc =
@@ -5566,10 +6487,24 @@ checkOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
PrevEUB =
SemaRef.ActOnFinishFullExpr(PrevEUB.get(), /*DiscardedValue*/ false);
- // Build IV <= PrevUB to be used in parallel for is in combination with
- // a distribute directive with schedule(static, 1)
+ // Build IV <= PrevUB or IV < PrevUB + 1 for unsigned IV to be used in
+ // parallel for is in combination with a distribute directive with
+ // schedule(static, 1)
+ Expr *BoundPrevUB = PrevUB.get();
+ if (UseStrictCompare) {
+ BoundPrevUB =
+ SemaRef
+ .BuildBinOp(
+ CurScope, CondLoc, BO_Add, BoundPrevUB,
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get())
+ .get();
+ BoundPrevUB =
+ SemaRef.ActOnFinishFullExpr(BoundPrevUB, /*DiscardedValue*/ false)
+ .get();
+ }
ParForInDistCond =
- SemaRef.BuildBinOp(CurScope, CondLoc, BO_LE, IV.get(), PrevUB.get());
+ SemaRef.BuildBinOp(CurScope, CondLoc, UseStrictCompare ? BO_LT : BO_LE,
+ IV.get(), BoundPrevUB);
}
// Build updates and final values of the loop counters.
@@ -7015,7 +7950,9 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
auto I = CS->body_begin();
while (I != CS->body_end()) {
const auto *OED = dyn_cast<OMPExecutableDirective>(*I);
- if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) {
+ if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind()) ||
+ OMPTeamsFound) {
+
OMPTeamsFound = false;
break;
}
@@ -8235,6 +9172,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_simdlen:
Res = ActOnOpenMPSimdlenClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_allocator:
+ Res = ActOnOpenMPAllocatorClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_collapse:
Res = ActOnOpenMPCollapseClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
@@ -8281,6 +9221,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -8365,12 +9306,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
// Do not capture if-clause expressions.
break;
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_target:
case OMPD_end_declare_target:
@@ -8431,12 +9374,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskloop:
case OMPD_taskloop_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_target:
case OMPD_end_declare_target:
@@ -8498,12 +9443,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel_for:
case OMPD_target_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_target:
case OMPD_end_declare_target:
@@ -8562,12 +9509,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_target_parallel_for:
case OMPD_target_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_target:
case OMPD_end_declare_target:
@@ -8627,12 +9576,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel:
case OMPD_parallel_sections:
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_target:
case OMPD_end_declare_target:
@@ -8691,12 +9642,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_parallel:
case OMPD_parallel_sections:
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_target:
case OMPD_end_declare_target:
@@ -8754,12 +9707,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
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_target:
case OMPD_end_declare_target:
@@ -8793,6 +9748,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_final:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_private:
case OMPC_shared:
@@ -8804,6 +9760,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -9042,6 +9999,71 @@ OMPClause *Sema::ActOnOpenMPSimdlenClause(Expr *Len, SourceLocation StartLoc,
OMPSimdlenClause(Simdlen.get(), StartLoc, LParenLoc, EndLoc);
}
+/// Tries to find omp_allocator_handle_t type.
+static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
+ DSAStackTy *Stack) {
+ QualType OMPAllocatorHandleT = Stack->getOMPAllocatorHandleT();
+ if (!OMPAllocatorHandleT.isNull())
+ return true;
+ // Build the predefined allocator expressions.
+ bool ErrorFound = false;
+ for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
+ StringRef Allocator =
+ OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind);
+ DeclarationName AllocatorName = &S.getASTContext().Idents.get(Allocator);
+ auto *VD = dyn_cast_or_null<ValueDecl>(
+ S.LookupSingleName(S.TUScope, AllocatorName, Loc, Sema::LookupAnyName));
+ if (!VD) {
+ ErrorFound = true;
+ break;
+ }
+ QualType AllocatorType =
+ VD->getType().getNonLValueExprType(S.getASTContext());
+ ExprResult Res = S.BuildDeclRefExpr(VD, AllocatorType, VK_LValue, Loc);
+ if (!Res.isUsable()) {
+ ErrorFound = true;
+ break;
+ }
+ if (OMPAllocatorHandleT.isNull())
+ OMPAllocatorHandleT = AllocatorType;
+ if (!S.getASTContext().hasSameType(OMPAllocatorHandleT, AllocatorType)) {
+ ErrorFound = true;
+ break;
+ }
+ Stack->setAllocator(AllocatorKind, Res.get());
+ }
+ if (ErrorFound) {
+ S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found);
+ return false;
+ }
+ OMPAllocatorHandleT.addConst();
+ Stack->setOMPAllocatorHandleT(OMPAllocatorHandleT);
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPAllocatorClause(Expr *A, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.11.3, allocate Directive, Description]
+ // allocator is an expression of omp_allocator_handle_t type.
+ if (!findOMPAllocatorHandleT(*this, A->getExprLoc(), DSAStack))
+ return nullptr;
+
+ ExprResult Allocator = DefaultLvalueConversion(A);
+ if (Allocator.isInvalid())
+ return nullptr;
+ Allocator = PerformImplicitConversion(Allocator.get(),
+ DSAStack->getOMPAllocatorHandleT(),
+ Sema::AA_Initializing,
+ /*AllowExplicit=*/true);
+ if (Allocator.isInvalid())
+ return nullptr;
+ return new (Context)
+ OMPAllocatorClause(Allocator.get(), StartLoc, LParenLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPCollapseClause(Expr *NumForLoops,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -9109,6 +10131,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_schedule:
case OMPC_private:
@@ -9127,6 +10150,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -9285,6 +10309,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
@@ -9304,6 +10329,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_untied:
case OMPC_mergeable:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_read:
case OMPC_write:
@@ -9505,6 +10531,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_schedule:
case OMPC_private:
@@ -9521,6 +10548,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_default:
case OMPC_proc_bind:
case OMPC_threadprivate:
+ case OMPC_allocate:
case OMPC_flush:
case OMPC_depend:
case OMPC_device:
@@ -9623,14 +10651,16 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc,
OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
- SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
- SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
- const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind,
+ const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
+ CXXScopeSpec &ReductionOrMapperIdScopeSpec,
+ DeclarationNameInfo &ReductionOrMapperId, OpenMPDependClauseKind DepKind,
OpenMPLinearClauseKind LinKind,
ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc,
- OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
- SourceLocation DepLinMapLoc) {
+ ArrayRef<SourceLocation> MapTypeModifiersLoc, OpenMPMapClauseKind MapType,
+ bool IsMapTypeImplicit, SourceLocation DepLinMapLoc) {
+ SourceLocation StartLoc = Locs.StartLoc;
+ SourceLocation LParenLoc = Locs.LParenLoc;
+ SourceLocation EndLoc = Locs.EndLoc;
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_private:
@@ -9647,17 +10677,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
break;
case OMPC_reduction:
Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionIdScopeSpec, ReductionId);
+ EndLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId);
break;
case OMPC_task_reduction:
Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionIdScopeSpec,
- ReductionId);
+ EndLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId);
break;
case OMPC_in_reduction:
- Res =
- ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionIdScopeSpec, ReductionId);
+ Res = ActOnOpenMPInReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId);
break;
case OMPC_linear:
Res = ActOnOpenMPLinearClause(VarList, TailExpr, StartLoc, LParenLoc,
@@ -9681,27 +10712,35 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
- Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc, MapType,
- IsMapTypeImplicit, DepLinMapLoc, ColonLoc,
- VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPMapClause(MapTypeModifiers, MapTypeModifiersLoc,
+ ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, MapType, IsMapTypeImplicit,
+ DepLinMapLoc, ColonLoc, VarList, Locs);
break;
case OMPC_to:
- Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, Locs);
break;
case OMPC_from:
- Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPFromClause(VarList, ReductionOrMapperIdScopeSpec,
+ ReductionOrMapperId, Locs);
break;
case OMPC_use_device_ptr:
- Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs);
break;
case OMPC_is_device_ptr:
- Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs);
+ break;
+ case OMPC_allocate:
+ Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc,
+ ColonLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
case OMPC_simdlen:
+ case OMPC_allocator:
case OMPC_collapse:
case OMPC_default:
case OMPC_proc_bind:
@@ -9759,66 +10798,6 @@ ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK,
return Res;
}
-static std::pair<ValueDecl *, bool>
-getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
- SourceRange &ERange, bool AllowArraySection = false) {
- if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
- RefExpr->containsUnexpandedParameterPack())
- return std::make_pair(nullptr, true);
-
- // OpenMP [3.1, C/C++]
- // A list item is a variable name.
- // OpenMP [2.9.3.3, Restrictions, p.1]
- // A variable that is part of another variable (as an array or
- // structure element) cannot appear in a private clause.
- RefExpr = RefExpr->IgnoreParens();
- enum {
- NoArrayExpr = -1,
- ArraySubscript = 0,
- OMPArraySection = 1
- } IsArrayExpr = NoArrayExpr;
- if (AllowArraySection) {
- if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) {
- Expr *Base = ASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- RefExpr = Base;
- IsArrayExpr = ArraySubscript;
- } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) {
- Expr *Base = OASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
- Base = TempOASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- RefExpr = Base;
- IsArrayExpr = OMPArraySection;
- }
- }
- ELoc = RefExpr->getExprLoc();
- ERange = RefExpr->getSourceRange();
- RefExpr = RefExpr->IgnoreParenImpCasts();
- auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
- auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr);
- if ((!DE || !isa<VarDecl>(DE->getDecl())) &&
- (S.getCurrentThisType().isNull() || !ME ||
- !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) ||
- !isa<FieldDecl>(ME->getMemberDecl()))) {
- if (IsArrayExpr != NoArrayExpr) {
- S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr
- << ERange;
- } else {
- S.Diag(ELoc,
- AllowArraySection
- ? diag::err_omp_expected_var_name_member_expr_or_array_item
- : diag::err_omp_expected_var_name_member_expr)
- << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange;
- }
- return std::make_pair(nullptr, false);
- }
- return std::make_pair(
- getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
-}
-
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -10511,8 +11490,8 @@ public:
} // namespace
template <typename T, typename U>
-static T filterLookupForUDR(SmallVectorImpl<U> &Lookups,
- const llvm::function_ref<T(ValueDecl *)> Gen) {
+static T filterLookupForUDReductionAndMapper(
+ SmallVectorImpl<U> &Lookups, const llvm::function_ref<T(ValueDecl *)> Gen) {
for (U &Set : Lookups) {
for (auto *D : Set) {
if (T Res = Gen(cast<ValueDecl>(D)))
@@ -10539,7 +11518,7 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
}
static void
-argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId,
+argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &Id,
SourceLocation Loc, QualType Ty,
SmallVectorImpl<UnresolvedSet<8>> &Lookups) {
// Find all of the associated namespaces and classes based on the
@@ -10573,13 +11552,14 @@ argumentDependentLookup(Sema &SemaRef, const DeclarationNameInfo &ReductionId,
// associated classes are visible within their respective
// namespaces even if they are not visible during an ordinary
// lookup (11.4).
- DeclContext::lookup_result R = NS->lookup(ReductionId.getName());
+ DeclContext::lookup_result R = NS->lookup(Id.getName());
for (auto *D : R) {
auto *Underlying = D;
if (auto *USD = dyn_cast<UsingShadowDecl>(D))
Underlying = USD->getTargetDecl();
- if (!isa<OMPDeclareReductionDecl>(Underlying))
+ if (!isa<OMPDeclareReductionDecl>(Underlying) &&
+ !isa<OMPDeclareMapperDecl>(Underlying))
continue;
if (!SemaRef.isVisible(D)) {
@@ -10624,7 +11604,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
for (NamedDecl *D : ULE->decls()) {
if (D == PrevD)
Lookups.push_back(UnresolvedSet<8>());
- else if (auto *DRD = cast<OMPDeclareReductionDecl>(D))
+ else if (auto *DRD = dyn_cast<OMPDeclareReductionDecl>(D))
Lookups.back().addDecl(DRD);
PrevD = D;
}
@@ -10632,7 +11612,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
if (SemaRef.CurContext->isDependentContext() || Ty->isDependentType() ||
Ty->isInstantiationDependentType() ||
Ty->containsUnexpandedParameterPack() ||
- filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) {
+ filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) {
return !D->isInvalidDecl() &&
(D->getType()->isDependentType() ||
D->getType()->isInstantiationDependentType() ||
@@ -10680,33 +11660,38 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
}
}
// Perform ADL.
- argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups);
- if (auto *VD = filterLookupForUDR<ValueDecl *>(
+ if (SemaRef.getLangOpts().CPlusPlus)
+ argumentDependentLookup(SemaRef, ReductionId, Loc, Ty, Lookups);
+ if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * {
if (!D->isInvalidDecl() &&
SemaRef.Context.hasSameType(D->getType(), Ty))
return D;
return nullptr;
}))
- return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
- if (auto *VD = filterLookupForUDR<ValueDecl *>(
- Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
- if (!D->isInvalidDecl() &&
- SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) &&
- !Ty.isMoreQualifiedThan(D->getType()))
- return D;
- return nullptr;
- })) {
- CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
- /*DetectVirtual=*/false);
- if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) {
- if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType(
- VD->getType().getUnqualifiedType()))) {
- if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(),
- /*DiagID=*/0) !=
- Sema::AR_inaccessible) {
- SemaRef.BuildBasePathArray(Paths, BasePath);
- return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
+ return SemaRef.BuildDeclRefExpr(VD, VD->getType().getNonReferenceType(),
+ VK_LValue, Loc);
+ if (SemaRef.getLangOpts().CPlusPlus) {
+ if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
+ Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) &&
+ !Ty.isMoreQualifiedThan(D->getType()))
+ return D;
+ return nullptr;
+ })) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) {
+ if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType(
+ VD->getType().getUnqualifiedType()))) {
+ if (SemaRef.CheckBaseClassAccess(
+ Loc, VD->getType(), Ty, Paths.front(),
+ /*DiagID=*/0) != Sema::AR_inaccessible) {
+ SemaRef.BuildBasePathArray(Paths, BasePath);
+ return SemaRef.BuildDeclRefExpr(
+ VD, VD->getType().getNonReferenceType(), VK_LValue, Loc);
+ }
}
}
}
@@ -11156,10 +12141,14 @@ static bool actOnOMPReductionKindClause(
if ((OASE && !ConstantLengthOASE) ||
(!OASE && !ASE &&
D->getType().getNonReferenceType()->isVariablyModifiedType())) {
- if (!Context.getTargetInfo().isVLASupported() &&
- S.shouldDiagnoseTargetSupportFromOpenMP()) {
- S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
- S.Diag(ELoc, diag::note_vla_unsupported);
+ if (!Context.getTargetInfo().isVLASupported()) {
+ if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective())) {
+ S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
+ S.Diag(ELoc, diag::note_vla_unsupported);
+ } else {
+ S.targetDiag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
+ S.targetDiag(ELoc, diag::note_vla_unsupported);
+ }
continue;
}
// For arrays/array sections only:
@@ -11300,7 +12289,8 @@ static bool actOnOMPReductionKindClause(
S.ActOnUninitializedDecl(RHSVD);
if (RHSVD->isInvalidDecl())
continue;
- if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
+ if (!RHSVD->hasInit() &&
+ (DeclareReductionRef.isUnset() || !S.LangOpts.CPlusPlus)) {
S.Diag(ELoc, diag::err_omp_reduction_id_not_compatible)
<< Type << ReductionIdRange;
bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) ==
@@ -12885,6 +13875,110 @@ static bool checkMapConflicts(
return FoundError;
}
+// Look up the user-defined mapper given the mapper name and mapped type, and
+// build a reference to it.
+static ExprResult buildUserDefinedMapperRef(Sema &SemaRef, Scope *S,
+ CXXScopeSpec &MapperIdScopeSpec,
+ const DeclarationNameInfo &MapperId,
+ QualType Type,
+ Expr *UnresolvedMapper) {
+ if (MapperIdScopeSpec.isInvalid())
+ return ExprError();
+ // Find all user-defined mappers with the given MapperId.
+ SmallVector<UnresolvedSet<8>, 4> Lookups;
+ LookupResult Lookup(SemaRef, MapperId, Sema::LookupOMPMapperName);
+ Lookup.suppressDiagnostics();
+ if (S) {
+ while (S && SemaRef.LookupParsedName(Lookup, S, &MapperIdScopeSpec)) {
+ NamedDecl *D = Lookup.getRepresentativeDecl();
+ while (S && !S->isDeclScope(D))
+ S = S->getParent();
+ if (S)
+ S = S->getParent();
+ Lookups.emplace_back();
+ Lookups.back().append(Lookup.begin(), Lookup.end());
+ Lookup.clear();
+ }
+ } else if (auto *ULE = cast_or_null<UnresolvedLookupExpr>(UnresolvedMapper)) {
+ // Extract the user-defined mappers with the given MapperId.
+ Lookups.push_back(UnresolvedSet<8>());
+ for (NamedDecl *D : ULE->decls()) {
+ auto *DMD = cast<OMPDeclareMapperDecl>(D);
+ assert(DMD && "Expect valid OMPDeclareMapperDecl during instantiation.");
+ Lookups.back().addDecl(DMD);
+ }
+ }
+ // Defer the lookup for dependent types. The results will be passed through
+ // UnresolvedMapper on instantiation.
+ if (SemaRef.CurContext->isDependentContext() || Type->isDependentType() ||
+ Type->isInstantiationDependentType() ||
+ Type->containsUnexpandedParameterPack() ||
+ filterLookupForUDReductionAndMapper<bool>(Lookups, [](ValueDecl *D) {
+ return !D->isInvalidDecl() &&
+ (D->getType()->isDependentType() ||
+ D->getType()->isInstantiationDependentType() ||
+ D->getType()->containsUnexpandedParameterPack());
+ })) {
+ UnresolvedSet<8> URS;
+ for (const UnresolvedSet<8> &Set : Lookups) {
+ if (Set.empty())
+ continue;
+ URS.append(Set.begin(), Set.end());
+ }
+ return UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ MapperIdScopeSpec.getWithLocInContext(SemaRef.Context), MapperId,
+ /*ADL=*/false, /*Overloaded=*/true, URS.begin(), URS.end());
+ }
+ // [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();
+ // Perform argument dependent lookup.
+ if (SemaRef.getLangOpts().CPlusPlus && !MapperIdScopeSpec.isSet())
+ argumentDependentLookup(SemaRef, MapperId, Loc, Type, Lookups);
+ // Return the first user-defined mapper with the desired type.
+ if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
+ Lookups, [&SemaRef, Type](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.Context.hasSameType(D->getType(), Type))
+ return D;
+ return nullptr;
+ }))
+ return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc);
+ // Find the first user-defined mapper with a type derived from the desired
+ // type.
+ if (auto *VD = filterLookupForUDReductionAndMapper<ValueDecl *>(
+ Lookups, [&SemaRef, Type, Loc](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.IsDerivedFrom(Loc, Type, D->getType()) &&
+ !Type.isMoreQualifiedThan(D->getType()))
+ return D;
+ return nullptr;
+ })) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (SemaRef.IsDerivedFrom(Loc, Type, VD->getType(), Paths)) {
+ if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType(
+ VD->getType().getUnqualifiedType()))) {
+ if (SemaRef.CheckBaseClassAccess(
+ Loc, VD->getType(), Type, Paths.front(),
+ /*DiagID=*/0) != Sema::AR_inaccessible) {
+ return SemaRef.BuildDeclRefExpr(VD, Type, VK_LValue, Loc);
+ }
+ }
+ }
+ }
+ // Report error if a mapper is specified, but cannot be found.
+ if (MapperIdScopeSpec.isSet() || MapperId.getAsString() != "default") {
+ SemaRef.Diag(Loc, diag::err_omp_invalid_mapper)
+ << Type << MapperId.getName();
+ return ExprError();
+ }
+ return ExprEmpty();
+}
+
namespace {
// Utility struct that gathers all the related lists associated with a mappable
// expression.
@@ -12897,6 +13991,8 @@ struct MappableVarListInfo {
OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents;
// The base declaration of the variable.
SmallVector<ValueDecl *, 16> VarBaseDeclarations;
+ // The reference to the user-defined mapper associated with every expression.
+ SmallVector<Expr *, 16> UDMapperList;
MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) {
// We have a list of components and base declarations for each entry in the
@@ -12908,20 +14004,37 @@ struct MappableVarListInfo {
}
// Check the validity of the provided variable list for the provided clause kind
-// \a CKind. In the check process the valid expressions, and mappable expression
-// components and variables are extracted and used to fill \a Vars,
-// \a ClauseComponents, and \a ClauseBaseDeclarations. \a MapType and
-// \a IsMapTypeImplicit are expected to be valid if the clause kind is 'map'.
-static void
-checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
- OpenMPClauseKind CKind, MappableVarListInfo &MVLI,
- SourceLocation StartLoc,
- OpenMPMapClauseKind MapType = OMPC_MAP_unknown,
- bool IsMapTypeImplicit = false) {
+// \a CKind. In the check process the valid expressions, mappable expression
+// components, variables, and user-defined mappers are extracted and used to
+// fill \a ProcessedVarList, \a VarComponents, \a VarBaseDeclarations, and \a
+// UDMapperList in MVLI. \a MapType, \a IsMapTypeImplicit, \a MapperIdScopeSpec,
+// and \a MapperId are expected to be valid if the clause kind is 'map'.
+static void checkMappableExpressionList(
+ Sema &SemaRef, DSAStackTy *DSAS, OpenMPClauseKind CKind,
+ MappableVarListInfo &MVLI, SourceLocation StartLoc,
+ CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo MapperId,
+ ArrayRef<Expr *> UnresolvedMappers,
+ OpenMPMapClauseKind MapType = OMPC_MAP_unknown,
+ bool IsMapTypeImplicit = false) {
// We only expect mappable expressions in 'to', 'from', and 'map' clauses.
assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) &&
"Unexpected clause kind with mappable expressions!");
+ // If the identifier of user-defined mapper is not specified, it is "default".
+ // We do not change the actual name in this clause to distinguish whether a
+ // mapper is specified explicitly, i.e., it is not explicitly specified when
+ // MapperId.getName() is empty.
+ if (!MapperId.getName() || MapperId.getName().isEmpty()) {
+ auto &DeclNames = SemaRef.getASTContext().DeclarationNames;
+ MapperId.setName(DeclNames.getIdentifier(
+ &SemaRef.getASTContext().Idents.get("default")));
+ }
+
+ // Iterators to find the current unresolved mapper expression.
+ auto UMIt = UnresolvedMappers.begin(), UMEnd = UnresolvedMappers.end();
+ bool UpdateUMIt = false;
+ Expr *UnresolvedMapper = nullptr;
+
// Keep track of the mappable components and base declarations in this clause.
// Each entry in the list is going to have a list of components associated. We
// record each set of the components so that we can build the clause later on.
@@ -12932,11 +14045,29 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
assert(RE && "Null expr in omp to/from/map clause");
SourceLocation ELoc = RE->getExprLoc();
+ // Find the current unresolved mapper expression.
+ if (UpdateUMIt && UMIt != UMEnd) {
+ UMIt++;
+ assert(
+ UMIt != UMEnd &&
+ "Expect the size of UnresolvedMappers to match with that of VarList");
+ }
+ UpdateUMIt = true;
+ if (UMIt != UMEnd)
+ UnresolvedMapper = *UMIt;
+
const Expr *VE = RE->IgnoreParenLValueCasts();
if (VE->isValueDependent() || VE->isTypeDependent() ||
VE->isInstantiationDependent() ||
VE->containsUnexpandedParameterPack()) {
+ // Try to find the associated user-defined mapper.
+ ExprResult ER = buildUserDefinedMapperRef(
+ SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
+ VE->getType().getCanonicalType(), UnresolvedMapper);
+ if (ER.isInvalid())
+ continue;
+ MVLI.UDMapperList.push_back(ER.get());
// We can only analyze this information once the missing information is
// resolved.
MVLI.ProcessedVarList.push_back(RE);
@@ -12968,6 +14099,13 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
if (const auto *TE = dyn_cast<CXXThisExpr>(BE)) {
// Add store "this" pointer to class in DSAStackTy for future checking
DSAS->addMappedClassesQualTypes(TE->getType());
+ // Try to find the associated user-defined mapper.
+ ExprResult ER = buildUserDefinedMapperRef(
+ SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
+ VE->getType().getCanonicalType(), UnresolvedMapper);
+ if (ER.isInvalid())
+ continue;
+ MVLI.UDMapperList.push_back(ER.get());
// Skip restriction checking for variable or field declarations
MVLI.ProcessedVarList.push_back(RE);
MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
@@ -13086,6 +14224,14 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
}
}
+ // Try to find the associated user-defined mapper.
+ ExprResult ER = buildUserDefinedMapperRef(
+ SemaRef, DSAS->getCurScope(), MapperIdScopeSpec, MapperId,
+ Type.getCanonicalType(), UnresolvedMapper);
+ if (ER.isInvalid())
+ continue;
+ MVLI.UDMapperList.push_back(ER.get());
+
// Save the current expression.
MVLI.ProcessedVarList.push_back(RE);
@@ -13105,19 +14251,16 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
}
}
-OMPClause *
-Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
- ArrayRef<SourceLocation> MapTypeModifiersLoc,
- OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
- SourceLocation MapLoc, SourceLocation ColonLoc,
- ArrayRef<Expr *> VarList, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc) {
- MappableVarListInfo MVLI(VarList);
- checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, StartLoc,
- MapType, IsMapTypeImplicit);
-
- OpenMPMapModifierKind Modifiers[] = { OMPC_MAP_MODIFIER_unknown,
- OMPC_MAP_MODIFIER_unknown };
+OMPClause *Sema::ActOnOpenMPMapClause(
+ ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
+ ArrayRef<SourceLocation> MapTypeModifiersLoc,
+ CXXScopeSpec &MapperIdScopeSpec, DeclarationNameInfo &MapperId,
+ OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, SourceLocation MapLoc,
+ SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs, ArrayRef<Expr *> UnresolvedMappers) {
+ OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown,
+ OMPC_MAP_MODIFIER_unknown,
+ OMPC_MAP_MODIFIER_unknown};
SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers];
// Process map-type-modifiers, flag errors for duplicate modifiers.
@@ -13135,12 +14278,18 @@ Sema::ActOnOpenMPMapClause(ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
++Count;
}
+ MappableVarListInfo MVLI(VarList);
+ checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, Locs.StartLoc,
+ MapperIdScopeSpec, MapperId, UnresolvedMappers,
+ MapType, IsMapTypeImplicit);
+
// We need to produce a map clause even if we don't have variables so that
// other diagnostics related with non-existing map clauses are accurate.
- return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
- MVLI.VarComponents, Modifiers, ModifiersLoc,
- MapType, IsMapTypeImplicit, MapLoc);
+ return OMPMapClause::Create(Context, Locs, MVLI.ProcessedVarList,
+ MVLI.VarBaseDeclarations, MVLI.VarComponents,
+ MVLI.UDMapperList, Modifiers, ModifiersLoc,
+ MapperIdScopeSpec.getWithLocInContext(Context),
+ MapperId, MapType, IsMapTypeImplicit, MapLoc);
}
QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
@@ -13400,6 +14549,143 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd(
return DeclReductions;
}
+TypeResult Sema::ActOnOpenMPDeclareMapperVarDecl(Scope *S, Declarator &D) {
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
+ QualType T = TInfo->getType();
+ if (D.isInvalidType())
+ return true;
+
+ if (getLangOpts().CPlusPlus) {
+ // Check that there are no default arguments (C++ only).
+ CheckExtraCXXDefaultArguments(D);
+ }
+
+ return CreateParsedType(T, TInfo);
+}
+
+QualType Sema::ActOnOpenMPDeclareMapperType(SourceLocation TyLoc,
+ TypeResult ParsedType) {
+ assert(ParsedType.isUsable() && "Expect usable parsed mapper type");
+
+ QualType MapperType = GetTypeFromParser(ParsedType.get());
+ assert(!MapperType.isNull() && "Expect valid mapper type");
+
+ // [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 (!MapperType->isStructureOrClassType() && !MapperType->isUnionType()) {
+ Diag(TyLoc, diag::err_omp_mapper_wrong_type);
+ return QualType();
+ }
+ return MapperType;
+}
+
+OMPDeclareMapperDecl *Sema::ActOnOpenMPDeclareMapperDirectiveStart(
+ Scope *S, DeclContext *DC, DeclarationName Name, QualType MapperType,
+ SourceLocation StartLoc, DeclarationName VN, AccessSpecifier AS,
+ Decl *PrevDeclInScope) {
+ LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPMapperName,
+ forRedeclarationInCurContext());
+ // [OpenMP 5.0], 2.19.7.3 declare mapper Directive, Restrictions
+ // A mapper-identifier may not be redeclared in the current scope for the
+ // same type or for a type that is compatible according to the base language
+ // rules.
+ llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes;
+ OMPDeclareMapperDecl *PrevDMD = nullptr;
+ bool InCompoundScope = true;
+ if (S != nullptr) {
+ // Find previous declaration with the same name not referenced in other
+ // declarations.
+ FunctionScopeInfo *ParentFn = getEnclosingFunction();
+ InCompoundScope =
+ (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty();
+ LookupName(Lookup, S);
+ FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false,
+ /*AllowInlineNamespace=*/false);
+ llvm::DenseMap<OMPDeclareMapperDecl *, bool> UsedAsPrevious;
+ LookupResult::Filter Filter = Lookup.makeFilter();
+ while (Filter.hasNext()) {
+ auto *PrevDecl = cast<OMPDeclareMapperDecl>(Filter.next());
+ if (InCompoundScope) {
+ auto I = UsedAsPrevious.find(PrevDecl);
+ if (I == UsedAsPrevious.end())
+ UsedAsPrevious[PrevDecl] = false;
+ if (OMPDeclareMapperDecl *D = PrevDecl->getPrevDeclInScope())
+ UsedAsPrevious[D] = true;
+ }
+ PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
+ PrevDecl->getLocation();
+ }
+ Filter.done();
+ if (InCompoundScope) {
+ for (const auto &PrevData : UsedAsPrevious) {
+ if (!PrevData.second) {
+ PrevDMD = PrevData.first;
+ break;
+ }
+ }
+ }
+ } else if (PrevDeclInScope) {
+ auto *PrevDMDInScope = PrevDMD =
+ cast<OMPDeclareMapperDecl>(PrevDeclInScope);
+ do {
+ PreviousRedeclTypes[PrevDMDInScope->getType().getCanonicalType()] =
+ PrevDMDInScope->getLocation();
+ PrevDMDInScope = PrevDMDInScope->getPrevDeclInScope();
+ } while (PrevDMDInScope != nullptr);
+ }
+ const auto I = PreviousRedeclTypes.find(MapperType.getCanonicalType());
+ bool Invalid = false;
+ if (I != PreviousRedeclTypes.end()) {
+ Diag(StartLoc, diag::err_omp_declare_mapper_redefinition)
+ << MapperType << Name;
+ Diag(I->second, diag::note_previous_definition);
+ Invalid = true;
+ }
+ auto *DMD = OMPDeclareMapperDecl::Create(Context, DC, StartLoc, Name,
+ MapperType, VN, PrevDMD);
+ DC->addDecl(DMD);
+ DMD->setAccess(AS);
+ if (Invalid)
+ DMD->setInvalidDecl();
+
+ // Enter new function scope.
+ PushFunctionScope();
+ setFunctionHasBranchProtectedScope();
+
+ CurContext = DMD;
+
+ return DMD;
+}
+
+void Sema::ActOnOpenMPDeclareMapperDirectiveVarDecl(OMPDeclareMapperDecl *DMD,
+ Scope *S,
+ QualType MapperType,
+ SourceLocation StartLoc,
+ DeclarationName VN) {
+ VarDecl *VD = buildVarDecl(*this, StartLoc, MapperType, VN.getAsString());
+ if (S)
+ PushOnScopeChains(VD, S);
+ else
+ DMD->addDecl(VD);
+ Expr *MapperVarRefExpr = buildDeclRefExpr(*this, VD, MapperType, StartLoc);
+ DMD->setMapperVarRef(MapperVarRefExpr);
+}
+
+Sema::DeclGroupPtrTy
+Sema::ActOnOpenMPDeclareMapperDirectiveEnd(OMPDeclareMapperDecl *D, Scope *S,
+ ArrayRef<OMPClause *> ClauseList) {
+ PopDeclContext();
+ PopFunctionScopeInfo();
+
+ if (D) {
+ if (S)
+ PushOnScopeChains(D, S, /*AddToContext=*/false);
+ D->CreateClauses(Context, ClauseList);
+ }
+
+ return DeclGroupPtrTy::make(DeclGroupRef(D));
+}
+
OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -13632,9 +14918,9 @@ void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope,
Lookup.suppressDiagnostics();
if (!Lookup.isSingleResult()) {
+ VarOrFuncDeclFilterCCC CCC(*this);
if (TypoCorrection Corrected =
- CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr,
- llvm::make_unique<VarOrFuncDeclFilterCCC>(*this),
+ CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, CCC,
CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Id.getName());
@@ -13744,37 +15030,41 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
}
OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ CXXScopeSpec &MapperIdScopeSpec,
+ DeclarationNameInfo &MapperId,
+ const OMPVarListLocTy &Locs,
+ ArrayRef<Expr *> UnresolvedMappers) {
MappableVarListInfo MVLI(VarList);
- checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc);
+ checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, Locs.StartLoc,
+ MapperIdScopeSpec, MapperId, UnresolvedMappers);
if (MVLI.ProcessedVarList.empty())
return nullptr;
- return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
- MVLI.VarComponents);
+ return OMPToClause::Create(
+ Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents, MVLI.UDMapperList,
+ MapperIdScopeSpec.getWithLocInContext(Context), MapperId);
}
OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ CXXScopeSpec &MapperIdScopeSpec,
+ DeclarationNameInfo &MapperId,
+ const OMPVarListLocTy &Locs,
+ ArrayRef<Expr *> UnresolvedMappers) {
MappableVarListInfo MVLI(VarList);
- checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc);
+ checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, Locs.StartLoc,
+ MapperIdScopeSpec, MapperId, UnresolvedMappers);
if (MVLI.ProcessedVarList.empty())
return nullptr;
- return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
- MVLI.VarComponents);
+ return OMPFromClause::Create(
+ Context, Locs, MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents, MVLI.UDMapperList,
+ MapperIdScopeSpec.getWithLocInContext(Context), MapperId);
}
OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ const OMPVarListLocTy &Locs) {
MappableVarListInfo MVLI(VarList);
SmallVector<Expr *, 8> PrivateCopies;
SmallVector<Expr *, 8> Inits;
@@ -13854,14 +15144,12 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
return nullptr;
return OMPUseDevicePtrClause::Create(
- Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList,
- PrivateCopies, Inits, MVLI.VarBaseDeclarations, MVLI.VarComponents);
+ Context, Locs, MVLI.ProcessedVarList, PrivateCopies, Inits,
+ MVLI.VarBaseDeclarations, MVLI.VarComponents);
}
OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+ const OMPVarListLocTy &Locs) {
MappableVarListInfo MVLI(VarList);
for (Expr *RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause.");
@@ -13937,7 +15225,68 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
if (MVLI.ProcessedVarList.empty())
return nullptr;
- return OMPIsDevicePtrClause::Create(
- Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList,
- MVLI.VarBaseDeclarations, MVLI.VarComponents);
+ return OMPIsDevicePtrClause::Create(Context, Locs, MVLI.ProcessedVarList,
+ MVLI.VarBaseDeclarations,
+ MVLI.VarComponents);
+}
+
+OMPClause *Sema::ActOnOpenMPAllocateClause(
+ Expr *Allocator, ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation ColonLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
+ if (Allocator) {
+ // OpenMP [2.11.4 allocate Clause, Description]
+ // allocator is an expression of omp_allocator_handle_t type.
+ if (!findOMPAllocatorHandleT(*this, Allocator->getExprLoc(), DSAStack))
+ return nullptr;
+
+ ExprResult AllocatorRes = DefaultLvalueConversion(Allocator);
+ if (AllocatorRes.isInvalid())
+ return nullptr;
+ AllocatorRes = PerformImplicitConversion(AllocatorRes.get(),
+ DSAStack->getOMPAllocatorHandleT(),
+ Sema::AA_Initializing,
+ /*AllowExplicit=*/true);
+ if (AllocatorRes.isInvalid())
+ return nullptr;
+ Allocator = AllocatorRes.get();
+ } else {
+ // OpenMP 5.0, 2.11.4 allocate Clause, Restrictions.
+ // allocate clauses that appear on a target construct or on constructs in a
+ // target region must specify an allocator expression unless a requires
+ // directive with the dynamic_allocators clause is present in the same
+ // compilation unit.
+ if (LangOpts.OpenMPIsDevice &&
+ !DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())
+ targetDiag(StartLoc, diag::err_expected_allocator_expression);
+ }
+ // Analyze and build list of variables.
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP private clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ }
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ auto *VD = dyn_cast<VarDecl>(D);
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && !CurContext->isDependentContext())
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ Vars.push_back((VD || CurContext->isDependentContext())
+ ? RefExpr->IgnoreParens()
+ : Ref);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator,
+ ColonLoc, EndLoc, Vars);
}