aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2020-07-31 21:22:58 +0000
committerDimitry Andric <dim@FreeBSD.org>2020-07-31 21:22:58 +0000
commit5ffd83dbcc34f10e07f6d3e968ae6365869615f4 (patch)
tree0e9f5cf729dde39f949698fddef45a34e2bc7f44 /contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp
parent1799696096df87b52968b8996d00c91e0a5de8d9 (diff)
parentcfca06d7963fa0909f90483b42a6d7d194d01e08 (diff)
Notes
Diffstat (limited to 'contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp')
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp3883
1 files changed, 2882 insertions, 1001 deletions
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp
index 3fce0e27e9b3..920463da4027 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaOpenMP.cpp
@@ -18,12 +18,15 @@
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
+#include "clang/AST/OpenMPClause.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
#include "clang/AST/TypeOrdering.h"
+#include "clang/Basic/DiagnosticSema.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/PartialDiagnostic.h"
+#include "clang/Basic/TargetInfo.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
@@ -31,7 +34,10 @@
#include "clang/Sema/SemaInternal.h"
#include "llvm/ADT/IndexedMap.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
+#include "llvm/ADT/STLExtras.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <set>
+
using namespace clang;
using namespace llvm::omp;
@@ -47,9 +53,10 @@ static const Expr *checkMapClauseExpressionBase(
namespace {
/// Default data sharing attributes, which can be applied to directive.
enum DefaultDataSharingAttributes {
- DSA_unspecified = 0, /// Data sharing attribute not specified.
- DSA_none = 1 << 0, /// Default data sharing attribute 'none'.
- DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
+ DSA_unspecified = 0, /// Data sharing attribute not specified.
+ DSA_none = 1 << 0, /// Default data sharing attribute 'none'.
+ DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'.
+ DSA_firstprivate = 1 << 2, /// Default data sharing attribute 'firstprivate'.
};
/// Stack for tracking declarations used in OpenMP directives and
@@ -59,24 +66,35 @@ public:
struct DSAVarData {
OpenMPDirectiveKind DKind = OMPD_unknown;
OpenMPClauseKind CKind = OMPC_unknown;
+ unsigned Modifier = 0;
const Expr *RefExpr = nullptr;
DeclRefExpr *PrivateCopy = nullptr;
SourceLocation ImplicitDSALoc;
DSAVarData() = default;
DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind,
const Expr *RefExpr, DeclRefExpr *PrivateCopy,
- SourceLocation ImplicitDSALoc)
- : DKind(DKind), CKind(CKind), RefExpr(RefExpr),
+ SourceLocation ImplicitDSALoc, unsigned Modifier)
+ : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr),
PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {}
};
using OperatorOffsetTy =
llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>;
using DoacrossDependMapTy =
llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>;
+ /// Kind of the declaration used in the uses_allocators clauses.
+ enum class UsesAllocatorsDeclKind {
+ /// Predefined allocator
+ PredefinedAllocator,
+ /// User-defined allocator
+ UserDefinedAllocator,
+ /// The declaration that represent allocator trait
+ AllocatorTrait,
+ };
private:
struct DSAInfo {
OpenMPClauseKind Attributes = OMPC_unknown;
+ unsigned Modifier = 0;
/// Pointer to a reference expression and a flag which shows that the
/// variable is marked as lastprivate(true) or not (false).
llvm::PointerIntPair<const Expr *, 1, bool> RefExpr;
@@ -151,13 +169,21 @@ private:
bool CancelRegion = false;
bool LoopStart = false;
bool BodyComplete = false;
+ SourceLocation PrevScanLocation;
+ SourceLocation PrevOrderedLocation;
SourceLocation InnerTeamsRegionLoc;
/// Reference to the taskgroup task_reduction reference expression.
Expr *TaskgroupReductionRef = nullptr;
llvm::DenseSet<QualType> MappedClassesQualTypes;
+ SmallVector<Expr *, 4> InnerUsedAllocators;
+ llvm::DenseSet<CanonicalDeclPtr<Decl>> ImplicitTaskFirstprivates;
/// List of globals marked as declare target link in this target region
/// (isOpenMPTargetExecutionDirective(Directive) == true).
llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls;
+ /// List of decls used in inclusive/exclusive clauses of the scan directive.
+ llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective;
+ llvm::DenseMap<CanonicalDeclPtr<const Decl>, UsesAllocatorsDeclKind>
+ UsesAllocatorsDecls;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -263,11 +289,18 @@ private:
SmallVector<const OMPRequiresDecl *, 2> RequiresDecls;
/// omp_allocator_handle_t type.
QualType OMPAllocatorHandleT;
+ /// omp_depend_t type.
+ QualType OMPDependT;
+ /// omp_event_handle_t type.
+ QualType OMPEventHandleT;
+ /// omp_alloctrait_t type.
+ QualType OMPAlloctraitT;
/// Expression for the predefined allocators.
Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = {
nullptr};
/// Vector of previously encountered target directives
SmallVector<SourceLocation, 2> TargetLocations;
+ SourceLocation AtomicLocation;
public:
explicit DSAStackTy(Sema &S) : SemaRef(S) {}
@@ -276,6 +309,10 @@ public:
void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; }
/// Gets omp_allocator_handle_t type.
QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; }
+ /// Sets omp_alloctrait_t type.
+ void setOMPAlloctraitT(QualType Ty) { OMPAlloctraitT = Ty; }
+ /// Gets omp_alloctrait_t type.
+ QualType getOMPAlloctraitT() const { return OMPAlloctraitT; }
/// Sets the given default allocator.
void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
Expr *Allocator) {
@@ -285,6 +322,15 @@ public:
Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const {
return OMPPredefinedAllocators[AllocatorKind];
}
+ /// Sets omp_depend_t type.
+ void setOMPDependT(QualType Ty) { OMPDependT = Ty; }
+ /// Gets omp_depend_t type.
+ QualType getOMPDependT() const { return OMPDependT; }
+
+ /// Sets omp_event_handle_t type.
+ void setOMPEventHandleT(QualType Ty) { OMPEventHandleT = Ty; }
+ /// Gets omp_event_handle_t type.
+ QualType getOMPEventHandleT() const { return OMPEventHandleT; }
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
OpenMPClauseKind getClauseParsingMode() const {
@@ -439,13 +485,32 @@ public:
/// \return The index of the loop control variable in the list of associated
/// for-loops (from outer to inner).
const LCDeclInfo isParentLoopControlVariable(const ValueDecl *D) const;
+ /// Check if the specified variable is a loop control variable for
+ /// current region.
+ /// \return The index of the loop control variable in the list of associated
+ /// for-loops (from outer to inner).
+ const LCDeclInfo isLoopControlVariable(const ValueDecl *D,
+ unsigned Level) const;
/// Get the loop control variable for the I-th loop (or nullptr) in
/// parent directive.
const ValueDecl *getParentLoopControlVariable(unsigned I) const;
+ /// Marks the specified decl \p D as used in scan directive.
+ void markDeclAsUsedInScanDirective(ValueDecl *D) {
+ if (SharingMapTy *Stack = getSecondOnStackOrNull())
+ Stack->UsedInScanDirective.insert(D);
+ }
+
+ /// Checks if the specified declaration was used in the inner scan directive.
+ bool isUsedInScanDirective(ValueDecl *D) const {
+ if (const SharingMapTy *Stack = getTopOfStackOrNull())
+ return Stack->UsedInScanDirective.count(D) > 0;
+ return false;
+ }
+
/// Adds explicit data sharing attribute to the specified declaration.
void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
- DeclRefExpr *PrivateCopy = nullptr);
+ DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0);
/// Adds additional information for the reduction items with the reduction id
/// represented as an operator.
@@ -467,11 +532,15 @@ public:
getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR,
const Expr *&ReductionRef,
Expr *&TaskgroupDescriptor) const;
- /// Return reduction reference expression for the current taskgroup.
+ /// Return reduction reference expression for the current taskgroup or
+ /// parallel/worksharing directives with task reductions.
Expr *getTaskgroupReductionRef() const {
- assert(getTopOfStack().Directive == OMPD_taskgroup &&
- "taskgroup reference expression requested for non taskgroup "
- "directive.");
+ assert((getTopOfStack().Directive == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
+ isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
+ !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
+ "taskgroup reference expression requested for non taskgroup or "
+ "parallel/worksharing directive.");
return getTopOfStack().TaskgroupReductionRef;
}
/// Checks if the given \p VD declaration is actually a taskgroup reduction
@@ -487,6 +556,8 @@ public:
const DSAVarData getTopDSA(ValueDecl *D, bool FromParent);
/// Returns data-sharing attributes for the specified declaration.
const DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent) const;
+ /// Returns data-sharing attributes for the specified declaration.
+ const DSAVarData getImplicitDSA(ValueDecl *D, unsigned Level) const;
/// Checks if the specified variables has data-sharing attributes which
/// match specified \a CPred predicate in any directive which matches \a DPred
/// predicate.
@@ -552,7 +623,7 @@ public:
/// Checks if the defined 'requires' directive has specified type of clause.
template <typename ClauseType>
- bool hasRequiresDeclWithClause() {
+ bool hasRequiresDeclWithClause() const {
return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) {
return llvm::any_of(D->clauselists(), [](const OMPClause *C) {
return isa<ClauseType>(C);
@@ -587,6 +658,18 @@ public:
TargetLocations.push_back(LocStart);
}
+ /// Add location for the first encountered atomicc directive.
+ void addAtomicDirectiveLoc(SourceLocation Loc) {
+ if (AtomicLocation.isInvalid())
+ AtomicLocation = Loc;
+ }
+
+ /// Returns the location of the first encountered atomic directive in the
+ /// module.
+ SourceLocation getAtomicDirectiveLoc() const {
+ return AtomicLocation;
+ }
+
// Return previously encountered target region locations.
ArrayRef<SourceLocation> getEncounteredTargetLocs() const {
return TargetLocations;
@@ -602,6 +685,11 @@ public:
getTopOfStack().DefaultAttr = DSA_shared;
getTopOfStack().DefaultAttrLoc = Loc;
}
+ /// Set default data sharing attribute to firstprivate.
+ void setDefaultDSAFirstPrivate(SourceLocation Loc) {
+ getTopOfStack().DefaultAttr = DSA_firstprivate;
+ getTopOfStack().DefaultAttrLoc = Loc;
+ }
/// Set default data mapping attribute to Modifier:Kind
void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M,
OpenMPDefaultmapClauseKind Kind,
@@ -612,10 +700,24 @@ public:
}
/// Check whether the implicit-behavior has been set in defaultmap
bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) {
+ if (VariableCategory == OMPC_DEFAULTMAP_unknown)
+ return getTopOfStack()
+ .DefaultmapMap[OMPC_DEFAULTMAP_aggregate]
+ .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown ||
+ getTopOfStack()
+ .DefaultmapMap[OMPC_DEFAULTMAP_scalar]
+ .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown ||
+ getTopOfStack()
+ .DefaultmapMap[OMPC_DEFAULTMAP_pointer]
+ .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown;
return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior !=
OMPC_DEFAULTMAP_MODIFIER_unknown;
}
+ DefaultDataSharingAttributes getDefaultDSA(unsigned Level) const {
+ return getStackSize() <= Level ? DSA_unspecified
+ : getStackElemAtLevel(Level).DefaultAttr;
+ }
DefaultDataSharingAttributes getDefaultDSA() const {
return isStackEmpty() ? DSA_unspecified
: getTopOfStack().DefaultAttr;
@@ -738,6 +840,37 @@ public:
return Top ? Top->CancelRegion : false;
}
+ /// Mark that parent region already has scan directive.
+ void setParentHasScanDirective(SourceLocation Loc) {
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->PrevScanLocation = Loc;
+ }
+ /// Return true if current region has inner cancel construct.
+ bool doesParentHasScanDirective() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevScanLocation.isValid() : false;
+ }
+ /// Return true if current region has inner cancel construct.
+ SourceLocation getParentScanDirectiveLoc() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevScanLocation : SourceLocation();
+ }
+ /// Mark that parent region already has ordered directive.
+ void setParentHasOrderedDirective(SourceLocation Loc) {
+ if (SharingMapTy *Parent = getSecondOnStackOrNull())
+ Parent->PrevOrderedLocation = Loc;
+ }
+ /// Return true if current region has inner ordered construct.
+ bool doesParentHasOrderedDirective() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevOrderedLocation.isValid() : false;
+ }
+ /// Returns the location of the previously specified ordered directive.
+ SourceLocation getParentOrderedDirectiveLoc() const {
+ const SharingMapTy *Top = getSecondOnStackOrNull();
+ return Top ? Top->PrevOrderedLocation : SourceLocation();
+ }
+
/// Set collapse value for the region.
void setAssociatedLoops(unsigned Val) {
getTopOfStack().AssociatedLoops = Val;
@@ -899,6 +1032,46 @@ public:
"Expected target executable directive.");
return getTopOfStack().DeclareTargetLinkVarDecls;
}
+
+ /// Adds list of allocators expressions.
+ void addInnerAllocatorExpr(Expr *E) {
+ getTopOfStack().InnerUsedAllocators.push_back(E);
+ }
+ /// Return list of used allocators.
+ ArrayRef<Expr *> getInnerAllocators() const {
+ return getTopOfStack().InnerUsedAllocators;
+ }
+ /// Marks the declaration as implicitly firstprivate nin the task-based
+ /// regions.
+ void addImplicitTaskFirstprivate(unsigned Level, Decl *D) {
+ getStackElemAtLevel(Level).ImplicitTaskFirstprivates.insert(D);
+ }
+ /// Checks if the decl is implicitly firstprivate in the task-based region.
+ bool isImplicitTaskFirstprivate(Decl *D) const {
+ return getTopOfStack().ImplicitTaskFirstprivates.count(D) > 0;
+ }
+
+ /// Marks decl as used in uses_allocators clause as the allocator.
+ void addUsesAllocatorsDecl(const Decl *D, UsesAllocatorsDeclKind Kind) {
+ getTopOfStack().UsesAllocatorsDecls.try_emplace(D, Kind);
+ }
+ /// Checks if specified decl is used in uses allocator clause as the
+ /// allocator.
+ Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(unsigned Level,
+ const Decl *D) const {
+ const SharingMapTy &StackElem = getTopOfStack();
+ auto I = StackElem.UsesAllocatorsDecls.find(D);
+ if (I == StackElem.UsesAllocatorsDecls.end())
+ return None;
+ return I->getSecond();
+ }
+ Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(const Decl *D) const {
+ const SharingMapTy &StackElem = getTopOfStack();
+ auto I = StackElem.UsesAllocatorsDecls.find(D);
+ if (I == StackElem.UsesAllocatorsDecls.end())
+ return None;
+ return I->getSecond();
+ }
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
@@ -1001,6 +1174,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
DVar.PrivateCopy = Data.PrivateCopy;
DVar.CKind = Data.Attributes;
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
+ DVar.Modifier = Data.Modifier;
return DVar;
}
@@ -1015,6 +1189,15 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter,
return DVar;
case DSA_none:
return DVar;
+ case DSA_firstprivate:
+ if (VD->getStorageDuration() == SD_Static &&
+ VD->getDeclContext()->isFileContext()) {
+ DVar.CKind = OMPC_unknown;
+ } else {
+ DVar.CKind = OMPC_firstprivate;
+ }
+ DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
+ return DVar;
case DSA_unspecified:
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, implicitly determined, p.2]
@@ -1113,6 +1296,19 @@ DSAStackTy::isLoopControlVariable(const ValueDecl *D) const {
}
const DSAStackTy::LCDeclInfo
+DSAStackTy::isLoopControlVariable(const ValueDecl *D, unsigned Level) const {
+ assert(!isStackEmpty() && "Data-sharing attributes stack is empty");
+ D = getCanonicalDecl(D);
+ for (unsigned I = Level + 1; I > 0; --I) {
+ const SharingMapTy &StackElem = getStackElemAtLevel(I - 1);
+ auto It = StackElem.LCVMap.find(D);
+ if (It != StackElem.LCVMap.end())
+ return It->second;
+ }
+ return {0, nullptr};
+}
+
+const DSAStackTy::LCDeclInfo
DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const {
const SharingMapTy *Parent = getSecondOnStackOrNull();
assert(Parent && "Data-sharing attributes stack is empty");
@@ -1135,19 +1331,21 @@ const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const {
}
void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
- DeclRefExpr *PrivateCopy) {
+ DeclRefExpr *PrivateCopy, unsigned Modifier) {
D = getCanonicalDecl(D);
if (A == OMPC_threadprivate) {
DSAInfo &Data = Threadprivates[D];
Data.Attributes = A;
Data.RefExpr.setPointer(E);
Data.PrivateCopy = nullptr;
+ Data.Modifier = Modifier;
} else {
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) ||
(isLoopControlVariable(D).first && A == OMPC_private));
+ Data.Modifier = Modifier;
if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) {
Data.RefExpr.setInt(/*IntVal=*/true);
return;
@@ -1159,6 +1357,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A,
Data.PrivateCopy = PrivateCopy;
if (PrivateCopy) {
DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()];
+ Data.Modifier = Modifier;
Data.Attributes = A;
Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
Data.PrivateCopy = nullptr;
@@ -1207,7 +1406,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
"Additional reduction info may be specified only for reduction items.");
ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- getTopOfStack().Directive == OMPD_taskgroup &&
+ (getTopOfStack().Directive == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
+ isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
+ !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(BOK, SR);
@@ -1230,7 +1432,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR,
"Additional reduction info may be specified only for reduction items.");
ReductionData &ReductionData = getTopOfStack().ReductionMap[D];
assert(ReductionData.ReductionRange.isInvalid() &&
- getTopOfStack().Directive == OMPD_taskgroup &&
+ (getTopOfStack().Directive == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(getTopOfStack().Directive) ||
+ isOpenMPWorksharingDirective(getTopOfStack().Directive)) &&
+ !isOpenMPSimdDirective(getTopOfStack().Directive))) &&
"Additional reduction info may be specified only once for reduction "
"items.");
ReductionData.set(ReductionRef, SR);
@@ -1251,7 +1456,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
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)
+ if (Data.Attributes != OMPC_reduction ||
+ Data.Modifier != OMPC_REDUCTION_task)
continue;
const ReductionData &ReductionData = I->ReductionMap.lookup(D);
if (!ReductionData.ReductionOp ||
@@ -1263,8 +1469,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
"expression for the descriptor is not "
"set.");
TaskgroupDescriptor = I->TaskgroupReductionRef;
- return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
- Data.PrivateCopy, I->DefaultAttrLoc);
+ return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task);
}
return DSAVarData();
}
@@ -1276,7 +1482,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
assert(!isStackEmpty() && "Data-sharing attributes stack is empty.");
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)
+ if (Data.Attributes != OMPC_reduction ||
+ Data.Modifier != OMPC_REDUCTION_task)
continue;
const ReductionData &ReductionData = I->ReductionMap.lookup(D);
if (!ReductionData.ReductionOp ||
@@ -1288,8 +1495,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData(
"expression for the descriptor is not "
"set.");
TaskgroupDescriptor = I->TaskgroupReductionRef;
- return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(),
- Data.PrivateCopy, I->DefaultAttrLoc);
+ return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(),
+ Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task);
}
return DSAVarData();
}
@@ -1364,6 +1571,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
if (TI != Threadprivates.end()) {
DVar.RefExpr = TI->getSecond().RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
+ DVar.Modifier = TI->getSecond().Modifier;
return DVar;
}
if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) {
@@ -1447,15 +1655,18 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
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;
+ if (I != EndI) {
+ 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;
+ DVar.Modifier = Data.Modifier;
+ return DVar;
+ }
}
DVar.CKind = OMPC_shared;
@@ -1493,6 +1704,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
const_iterator EndI = end();
if (FromParent && I != EndI)
++I;
+ if (I == EndI)
+ return DVar;
auto It = I->SharingMap.find(D);
if (It != I->SharingMap.end()) {
const DSAInfo &Data = It->getSecond();
@@ -1501,6 +1714,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D,
DVar.CKind = Data.Attributes;
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
DVar.DKind = I->Directive;
+ DVar.Modifier = Data.Modifier;
}
return DVar;
@@ -1520,6 +1734,15 @@ const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
return getDSA(StartI, D);
}
+const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
+ unsigned Level) const {
+ if (getStackSize() <= Level)
+ return DSAVarData();
+ D = getCanonicalDecl(D);
+ const_iterator StartI = std::next(begin(), getStackSize() - 1 - Level);
+ return getDSA(StartI, D);
+}
+
const DSAStackTy::DSAVarData
DSAStackTy::hasDSA(ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> CPred,
@@ -1640,23 +1863,28 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
"Expected OpenMP device compilation.");
- FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl());
+
+ FunctionDecl *FD = getCurFunctionDecl();
DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop;
- switch (FES) {
- case FunctionEmissionStatus::Emitted:
- Kind = DeviceDiagBuilder::K_Immediate;
- break;
- case FunctionEmissionStatus::Unknown:
- Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred
- : DeviceDiagBuilder::K_Immediate;
- break;
- case FunctionEmissionStatus::TemplateDiscarded:
- case FunctionEmissionStatus::OMPDiscarded:
- Kind = DeviceDiagBuilder::K_Nop;
- break;
- case FunctionEmissionStatus::CUDADiscarded:
- llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
- break;
+ if (FD) {
+ FunctionEmissionStatus FES = getEmissionStatus(FD);
+ switch (FES) {
+ case FunctionEmissionStatus::Emitted:
+ Kind = DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::Unknown:
+ Kind = isOpenMPDeviceDelayedContext(*this)
+ ? DeviceDiagBuilder::K_Deferred
+ : DeviceDiagBuilder::K_Immediate;
+ break;
+ case FunctionEmissionStatus::TemplateDiscarded:
+ case FunctionEmissionStatus::OMPDiscarded:
+ Kind = DeviceDiagBuilder::K_Nop;
+ break;
+ case FunctionEmissionStatus::CUDADiscarded:
+ llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation");
+ break;
+ }
}
return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
@@ -1685,107 +1913,6 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc,
return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this);
}
-void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee,
- bool CheckForDelayedContext) {
- assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice &&
- "Expected OpenMP device compilation.");
- assert(Callee && "Callee may not be null.");
- Callee = Callee->getMostRecentDecl();
- FunctionDecl *Caller = getCurFunctionDecl();
-
- // host only function are not available on the device.
- if (Caller) {
- FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
- FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
- assert(CallerS != FunctionEmissionStatus::CUDADiscarded &&
- CalleeS != FunctionEmissionStatus::CUDADiscarded &&
- "CUDADiscarded unexpected in OpenMP device function check");
- if ((CallerS == FunctionEmissionStatus::Emitted ||
- (!isOpenMPDeviceDelayedContext(*this) &&
- CallerS == FunctionEmissionStatus::Unknown)) &&
- CalleeS == FunctionEmissionStatus::OMPDiscarded) {
- StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
- OMPC_device_type, OMPC_DEVICE_TYPE_host);
- Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
- Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
- diag::note_omp_marked_device_type_here)
- << HostDevTy;
- return;
- }
- }
- // If the caller is known-emitted, mark the callee as known-emitted.
- // Otherwise, mark the call in our call graph so we can traverse it later.
- if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) ||
- (!Caller && !CheckForDelayedContext) ||
- (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
- markKnownEmitted(*this, Caller, Callee, Loc,
- [CheckForDelayedContext](Sema &S, FunctionDecl *FD) {
- return CheckForDelayedContext &&
- S.getEmissionStatus(FD) ==
- FunctionEmissionStatus::Emitted;
- });
- else if (Caller)
- DeviceCallGraph[Caller].insert({Callee, Loc});
-}
-
-void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee,
- bool CheckCaller) {
- assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice &&
- "Expected OpenMP host compilation.");
- assert(Callee && "Callee may not be null.");
- Callee = Callee->getMostRecentDecl();
- FunctionDecl *Caller = getCurFunctionDecl();
-
- // device only function are not available on the host.
- if (Caller) {
- FunctionEmissionStatus CallerS = getEmissionStatus(Caller);
- FunctionEmissionStatus CalleeS = getEmissionStatus(Callee);
- assert(
- (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded &&
- CalleeS != FunctionEmissionStatus::CUDADiscarded)) &&
- "CUDADiscarded unexpected in OpenMP host function check");
- if (CallerS == FunctionEmissionStatus::Emitted &&
- CalleeS == FunctionEmissionStatus::OMPDiscarded) {
- StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
- OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
- Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
- Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
- diag::note_omp_marked_device_type_here)
- << NoHostDevTy;
- return;
- }
- }
- // If the caller is known-emitted, mark the callee as known-emitted.
- // Otherwise, mark the call in our call graph so we can traverse it later.
- if (!shouldIgnoreInHostDeviceCheck(Callee)) {
- if ((!CheckCaller && !Caller) ||
- (Caller &&
- getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted))
- markKnownEmitted(
- *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) {
- return CheckCaller &&
- S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted;
- });
- else if (Caller)
- DeviceCallGraph[Caller].insert({Callee, Loc});
- }
-}
-
-void Sema::checkOpenMPDeviceExpr(const Expr *E) {
- assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice &&
- "OpenMP device compilation mode is expected.");
- 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();
-}
-
static OpenMPDefaultmapClauseKind
getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) {
if (LO.OpenMP <= 45) {
@@ -1901,7 +2028,8 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) ||
isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) ||
- isa<MemberExpr>(EI->getAssociatedExpression())) {
+ isa<MemberExpr>(EI->getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(EI->getAssociatedExpression())) {
IsVariableAssociatedWithSection = true;
// There is nothing more we need to know about this variable.
return true;
@@ -1935,14 +2063,23 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level,
((IsVariableUsedInMapClause &&
DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) ==
OMPD_target) ||
- !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) ||
+ DSAStack->isUsesAllocatorsDecl(Level, D))) &&
// If the variable is artificial and must be captured by value - try to
// capture by value.
!(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() &&
- !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue());
+ !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue()) &&
+ // If the variable is implicitly firstprivate and scalar - capture by
+ // copy
+ !(DSAStack->getDefaultDSA() == DSA_firstprivate &&
+ !DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K != OMPC_unknown; }, Level) &&
+ !DSAStack->isLoopControlVariable(D, Level).first);
}
// When passing data by copy, we need to make sure it fits the uintptr size
@@ -2010,7 +2147,23 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
//
if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD))
return nullptr;
- return VD;
+ CapturedRegionScopeInfo *CSI = nullptr;
+ for (FunctionScopeInfo *FSI : llvm::drop_begin(
+ llvm::reverse(FunctionScopes),
+ CheckScopeInfo ? (FunctionScopes.size() - (StopAt + 1)) : 0)) {
+ if (!isa<CapturingScopeInfo>(FSI))
+ return nullptr;
+ if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(FSI))
+ if (RSI->CapRegionKind == CR_OpenMP) {
+ CSI = RSI;
+ break;
+ }
+ }
+ SmallVector<OpenMPDirectiveKind, 4> Regions;
+ getOpenMPCaptureRegions(Regions,
+ DSAStack->getDirective(CSI->OpenMPLevel));
+ if (Regions[CSI->OpenMPCaptureLevel] != OMPD_task)
+ return VD;
}
}
@@ -2039,20 +2192,27 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
isImplicitOrExplicitTaskingRegion(DSAStack->getCurrentDirective())) ||
(VD && DSAStack->isForceVarCapturing()))
return VD ? VD : Info.second;
- DSAStackTy::DSAVarData DVarPrivate =
+ DSAStackTy::DSAVarData DVarTop =
DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
- if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
- return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
+ if (DVarTop.CKind != OMPC_unknown && isOpenMPPrivate(DVarTop.CKind))
+ return VD ? VD : cast<VarDecl>(DVarTop.PrivateCopy->getDecl());
// Threadprivate variables must not be captured.
- if (isOpenMPThreadPrivate(DVarPrivate.CKind))
+ if (isOpenMPThreadPrivate(DVarTop.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());
+ DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA(
+ D, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; },
+ DSAStack->isClauseParsingMode());
+ // Global shared must not be captured.
+ if (VD && !VD->hasLocalStorage() && DVarPrivate.CKind == OMPC_unknown &&
+ ((DSAStack->getDefaultDSA() != DSA_none &&
+ DSAStack->getDefaultDSA() != DSA_firstprivate) ||
+ DVarTop.CKind == OMPC_shared))
+ return nullptr;
if (DVarPrivate.CKind != OMPC_unknown ||
- (VD && DSAStack->getDefaultDSA() == DSA_none))
+ (VD && (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_firstprivate)))
return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
}
return nullptr;
@@ -2060,9 +2220,7 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo,
void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex,
unsigned Level) const {
- SmallVector<OpenMPDirectiveKind, 4> Regions;
- getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level));
- FunctionScopesIndex -= Regions.size();
+ FunctionScopesIndex -= getOpenMPCaptureLevels(DSAStack->getDirective(Level));
}
void Sema::startOpenMPLoop() {
@@ -2079,39 +2237,77 @@ void Sema::startOpenMPCXXRangeFor() {
}
}
-bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const {
+OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level,
+ unsigned CapLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ if (DSAStack->hasExplicitDirective(
+ [](OpenMPDirectiveKind K) { return isOpenMPTaskingDirective(K); },
+ Level)) {
+ bool IsTriviallyCopyable =
+ D->getType().getNonReferenceType().isTriviallyCopyableType(Context);
+ OpenMPDirectiveKind DKind = DSAStack->getDirective(Level);
+ SmallVector<OpenMPDirectiveKind, 4> CaptureRegions;
+ getOpenMPCaptureRegions(CaptureRegions, DKind);
+ if (isOpenMPTaskingDirective(CaptureRegions[CapLevel]) &&
+ (IsTriviallyCopyable ||
+ !isOpenMPTaskLoopDirective(CaptureRegions[CapLevel]))) {
+ if (DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_firstprivate; },
+ Level, /*NotLastprivate=*/true))
+ return OMPC_firstprivate;
+ DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level);
+ if (DVar.CKind != OMPC_shared &&
+ !DSAStack->isLoopControlVariable(D, Level).first && !DVar.RefExpr) {
+ DSAStack->addImplicitTaskFirstprivate(Level, D);
+ return OMPC_firstprivate;
+ }
+ }
+ }
if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
if (DSAStack->getAssociatedLoops() > 0 &&
!DSAStack->isLoopStarted()) {
DSAStack->resetPossibleLoopCounter(D);
DSAStack->loopStart();
- return true;
+ return OMPC_private;
}
if ((DSAStack->getPossiblyLoopCunter() == D->getCanonicalDecl() ||
DSAStack->isLoopControlVariable(D).first) &&
!DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K != OMPC_private; }, Level) &&
!isOpenMPSimdDirective(DSAStack->getCurrentDirective()))
- return true;
+ return OMPC_private;
}
if (const auto *VD = dyn_cast<VarDecl>(D)) {
if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) &&
DSAStack->isForceVarCapturing() &&
!DSAStack->hasExplicitDSA(
D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level))
- return true;
- }
- return DSAStack->hasExplicitDSA(
- D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
- (DSAStack->isClauseParsingMode() &&
- DSAStack->getClauseParsingMode() == OMPC_private) ||
- // Consider taskgroup reduction descriptor variable a private to avoid
- // possible capture in the region.
- (DSAStack->hasExplicitDirective(
- [](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; },
- Level) &&
- DSAStack->isTaskgroupReductionRef(D, Level));
+ return OMPC_private;
+ }
+ // User-defined allocators are private since they must be defined in the
+ // context of target region.
+ if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level) &&
+ DSAStack->isUsesAllocatorsDecl(Level, D).getValueOr(
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
+ DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator)
+ return OMPC_private;
+ return (DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) ||
+ (DSAStack->isClauseParsingMode() &&
+ DSAStack->getClauseParsingMode() == OMPC_private) ||
+ // Consider taskgroup reduction descriptor variable a private
+ // to avoid possible capture in the region.
+ (DSAStack->hasExplicitDirective(
+ [](OpenMPDirectiveKind K) {
+ return K == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K)) &&
+ !isOpenMPSimdDirective(K));
+ },
+ Level) &&
+ DSAStack->isTaskgroupReductionRef(D, Level)))
+ ? OMPC_private
+ : OMPC_unknown;
}
void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
@@ -2148,68 +2344,101 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D,
}
}
if (OMPC != OMPC_unknown)
- FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC));
+ FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, unsigned(OMPC)));
}
-bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D,
- unsigned Level) const {
+bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level,
+ unsigned CaptureLevel) const {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
// Return true if the current level is no longer enclosed in a target region.
+ SmallVector<OpenMPDirectiveKind, 4> Regions;
+ getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level));
const auto *VD = dyn_cast<VarDecl>(D);
return VD && !VD->hasLocalStorage() &&
DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
- Level);
+ Level) &&
+ Regions[CaptureLevel] != OMPD_task;
+}
+
+bool Sema::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level,
+ unsigned CaptureLevel) const {
+ assert(LangOpts.OpenMP && "OpenMP is not allowed");
+ // Return true if the current level is no longer enclosed in a target region.
+
+ if (const auto *VD = dyn_cast<VarDecl>(D)) {
+ if (!VD->hasLocalStorage()) {
+ DSAStackTy::DSAVarData TopDVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/false);
+ unsigned NumLevels =
+ getOpenMPCaptureLevels(DSAStack->getDirective(Level));
+ if (Level == 0)
+ return (NumLevels == CaptureLevel + 1) && TopDVar.CKind != OMPC_shared;
+ DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level - 1);
+ return DVar.CKind != OMPC_shared ||
+ isOpenMPGlobalCapturedDecl(
+ D, Level - 1,
+ getOpenMPCaptureLevels(DSAStack->getDirective(Level - 1)) - 1);
+ }
+ }
+ return true;
}
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
-void Sema::finalizeOpenMPDelayedAnalysis() {
+void Sema::ActOnOpenMPBeginDeclareVariant(SourceLocation Loc,
+ OMPTraitInfo &TI) {
+ if (!OMPDeclareVariantScopes.empty()) {
+ Diag(Loc, diag::warn_nested_declare_variant);
+ return;
+ }
+ OMPDeclareVariantScopes.push_back(OMPDeclareVariantScope(TI));
+}
+
+void Sema::ActOnOpenMPEndDeclareVariant() {
+ assert(isInOpenMPDeclareVariantScope() &&
+ "Not in OpenMP declare variant scope!");
+
+ OMPDeclareVariantScopes.pop_back();
+}
+
+void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller,
+ const FunctionDecl *Callee,
+ SourceLocation Loc) {
assert(LangOpts.OpenMP && "Expected OpenMP compilation mode.");
- // Diagnose implicit declare target functions and their callees.
- for (const auto &CallerCallees : DeviceCallGraph) {
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(
- CallerCallees.getFirst()->getMostRecentDecl());
- // Ignore host functions during device analyzis.
- if (LangOpts.OpenMPIsDevice && DevTy &&
- *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
- continue;
- // Ignore nohost functions during host analyzis.
- if (!LangOpts.OpenMPIsDevice && DevTy &&
- *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
- continue;
- for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation>
- &Callee : CallerCallees.getSecond()) {
- const FunctionDecl *FD = Callee.first->getMostRecentDecl();
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(FD);
- if (LangOpts.OpenMPIsDevice && DevTy &&
- *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
- // Diagnose host function called during device codegen.
- StringRef HostDevTy = getOpenMPSimpleClauseTypeName(
- OMPC_device_type, OMPC_DEVICE_TYPE_host);
- Diag(Callee.second, diag::err_omp_wrong_device_function_call)
- << HostDevTy << 0;
- Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
- diag::note_omp_marked_device_type_here)
- << HostDevTy;
- continue;
- }
+ Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
+ OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl());
+ // Ignore host functions during device analyzis.
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host)
+ return;
+ // Ignore nohost functions during host analyzis.
+ if (!LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost)
+ return;
+ const FunctionDecl *FD = Callee->getMostRecentDecl();
+ DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD);
+ if (LangOpts.OpenMPIsDevice && DevTy &&
+ *DevTy == OMPDeclareTargetDeclAttr::DT_Host) {
+ // Diagnose host function called during device codegen.
+ StringRef HostDevTy =
+ getOpenMPSimpleClauseTypeName(OMPC_device_type, OMPC_DEVICE_TYPE_host);
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0;
+ Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
+ diag::note_omp_marked_device_type_here)
+ << HostDevTy;
+ return;
+ }
if (!LangOpts.OpenMPIsDevice && DevTy &&
*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) {
// Diagnose nohost function called during host codegen.
StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName(
OMPC_device_type, OMPC_DEVICE_TYPE_nohost);
- Diag(Callee.second, diag::err_omp_wrong_device_function_call)
- << NoHostDevTy << 1;
+ Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1;
Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(),
diag::note_omp_marked_device_type_here)
<< NoHostDevTy;
- continue;
}
- }
- }
}
void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind,
@@ -2228,14 +2457,86 @@ void Sema::EndOpenMPClause() {
DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown);
}
-static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
- ArrayRef<OMPClause *> Clauses);
static std::pair<ValueDecl *, bool>
getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
SourceRange &ERange, bool AllowArraySection = false);
+
+/// Check consistency of the reduction clauses.
+static void checkReductionClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses) {
+ bool InscanFound = false;
+ SourceLocation InscanLoc;
+ // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions.
+ // A reduction clause without the inscan reduction-modifier may not appear on
+ // a construct on which a reduction clause with the inscan reduction-modifier
+ // appears.
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() != OMPC_reduction)
+ continue;
+ auto *RC = cast<OMPReductionClause>(C);
+ if (RC->getModifier() == OMPC_REDUCTION_inscan) {
+ InscanFound = true;
+ InscanLoc = RC->getModifierLoc();
+ continue;
+ }
+ if (RC->getModifier() == OMPC_REDUCTION_task) {
+ // OpenMP 5.0, 2.19.5.4 reduction Clause.
+ // A reduction clause with the task reduction-modifier may only appear on
+ // a parallel construct, a worksharing construct or a combined or
+ // composite construct for which any of the aforementioned constructs is a
+ // constituent construct and simd or loop are not constituent constructs.
+ OpenMPDirectiveKind CurDir = Stack->getCurrentDirective();
+ if (!(isOpenMPParallelDirective(CurDir) ||
+ isOpenMPWorksharingDirective(CurDir)) ||
+ isOpenMPSimdDirective(CurDir))
+ S.Diag(RC->getModifierLoc(),
+ diag::err_omp_reduction_task_not_parallel_or_worksharing);
+ continue;
+ }
+ }
+ if (InscanFound) {
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() != OMPC_reduction)
+ continue;
+ auto *RC = cast<OMPReductionClause>(C);
+ if (RC->getModifier() != OMPC_REDUCTION_inscan) {
+ S.Diag(RC->getModifier() == OMPC_REDUCTION_unknown
+ ? RC->getBeginLoc()
+ : RC->getModifierLoc(),
+ diag::err_omp_inscan_reduction_expected);
+ S.Diag(InscanLoc, diag::note_omp_previous_inscan_reduction);
+ continue;
+ }
+ for (Expr *Ref : RC->varlists()) {
+ assert(Ref && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = Ref;
+ auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+ if (!Stack->isUsedInScanDirective(getCanonicalDecl(D))) {
+ S.Diag(Ref->getExprLoc(),
+ diag::err_omp_reduction_not_inclusive_exclusive)
+ << Ref->getSourceRange();
+ }
+ }
+ }
+ }
+}
+
+static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
+ ArrayRef<OMPClause *> Clauses);
static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
bool WithInit);
+static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
+ const ValueDecl *D,
+ const DSAStackTy::DSAVarData &DVar,
+ bool IsLoopIterVar = false);
+
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
@@ -2305,10 +2606,56 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
Clause->setPrivateRefs(PrivateRefs);
continue;
}
+ if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) {
+ for (unsigned I = 0, E = Clause->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data D = Clause->getAllocatorData(I);
+ auto *DRE = dyn_cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts());
+ if (!DRE)
+ continue;
+ ValueDecl *VD = DRE->getDecl();
+ if (!VD || !isa<VarDecl>(VD))
+ continue;
+ DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(VD, /*FromParent=*/false);
+ // OpenMP [2.12.5, target Construct]
+ // Memory allocators that appear in a uses_allocators clause cannot
+ // appear in other data-sharing attribute clauses or data-mapping
+ // attribute clauses in the same construct.
+ Expr *MapExpr = nullptr;
+ if (DVar.RefExpr ||
+ DSAStack->checkMappableExprComponentListsForDecl(
+ VD, /*CurrentRegionOnly=*/true,
+ [VD, &MapExpr](
+ OMPClauseMappableExprCommon::MappableExprComponentListRef
+ MapExprComponents,
+ OpenMPClauseKind C) {
+ auto MI = MapExprComponents.rbegin();
+ auto ME = MapExprComponents.rend();
+ if (MI != ME &&
+ MI->getAssociatedDeclaration()->getCanonicalDecl() ==
+ VD->getCanonicalDecl()) {
+ MapExpr = MI->getAssociatedExpression();
+ return true;
+ }
+ return false;
+ })) {
+ Diag(D.Allocator->getExprLoc(),
+ diag::err_omp_allocator_used_in_clauses)
+ << D.Allocator->getSourceRange();
+ if (DVar.RefExpr)
+ reportOriginalDsa(*this, DSAStack, VD, DVar);
+ else
+ Diag(MapExpr->getExprLoc(), diag::note_used_here)
+ << MapExpr->getSourceRange();
+ }
+ }
+ continue;
+ }
}
// Check allocate clauses.
if (!CurContext->isDependentContext())
checkAllocateClauses(*this, DSAStack, D->clauses());
+ checkReductionClauses(*this, DSAStack, D->clauses());
}
DSAStack->pop();
@@ -2618,15 +2965,14 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
static OMPAllocateDeclAttr::AllocatorTypeTy
getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) {
if (!Allocator)
- return OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ return OMPAllocateDeclAttr::OMPNullMemAlloc;
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) {
+ for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
const Expr *DefAllocator = Stack->getAllocator(AllocatorKind);
llvm::FoldingSetNodeID AEId, DAEId;
@@ -2799,18 +3145,26 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc,
/// current compilation unit.
ArrayRef<SourceLocation> TargetLocations =
DSAStack->getEncounteredTargetLocs();
- if (!TargetLocations.empty()) {
+ SourceLocation AtomicLoc = DSAStack->getAtomicDirectiveLoc();
+ if (!TargetLocations.empty() || !AtomicLoc.isInvalid()) {
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());
+ Diag(Loc, diag::err_omp_directive_before_requires)
+ << "target" << getOpenMPClauseName(CNew->getClauseKind());
for (SourceLocation TargetLoc : TargetLocations) {
- Diag(TargetLoc, diag::note_omp_requires_encountered_target);
+ Diag(TargetLoc, diag::note_omp_requires_encountered_directive)
+ << "target";
}
+ } else if (!AtomicLoc.isInvalid() &&
+ isa<OMPAtomicDefaultMemOrderClause>(CNew)) {
+ Diag(Loc, diag::err_omp_directive_before_requires)
+ << "atomic" << getOpenMPClauseName(CNew->getClauseKind());
+ Diag(AtomicLoc, diag::note_omp_requires_encountered_directive)
+ << "atomic";
}
}
}
@@ -2824,7 +3178,7 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc,
static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack,
const ValueDecl *D,
const DSAStackTy::DSAVarData &DVar,
- bool IsLoopIterVar = false) {
+ bool IsLoopIterVar) {
if (DVar.RefExpr) {
SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(DVar.CKind);
@@ -2944,6 +3298,16 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
Visit(S->getInnermostCapturedStmt()->getCapturedStmt());
TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers;
}
+ // In tasks firstprivates are not captured anymore, need to analyze them
+ // explicitly.
+ if (isOpenMPTaskingDirective(S->getDirectiveKind()) &&
+ !isOpenMPTaskLoopDirective(S->getDirectiveKind())) {
+ for (OMPClause *C : S->clauses())
+ if (auto *FC = dyn_cast<OMPFirstprivateClause>(C)) {
+ for (Expr *Ref : FC->varlists())
+ Visit(Ref);
+ }
+ }
}
public:
@@ -2966,7 +3330,11 @@ public:
return;
VD = VD->getCanonicalDecl();
// Skip internally declared variables.
- if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD))
+ if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) &&
+ !Stack->isImplicitTaskFirstprivate(VD))
+ return;
+ // Skip allocators in uses_allocators clauses.
+ if (Stack->isUsesAllocatorsDecl(VD).hasValue())
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
@@ -2979,7 +3347,8 @@ public:
OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD);
if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) &&
(Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() ||
- !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link))
+ !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) &&
+ !Stack->isImplicitTaskFirstprivate(VD))
return;
SourceLocation ELoc = E->getExprLoc();
@@ -2988,10 +3357,19 @@ public:
// in the construct, and does not have a predetermined data-sharing
// attribute, must have its data-sharing attribute explicitly determined
// by being listed in a data-sharing attribute clause.
- if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none &&
+ if (DVar.CKind == OMPC_unknown &&
+ (Stack->getDefaultDSA() == DSA_none ||
+ Stack->getDefaultDSA() == DSA_firstprivate) &&
isImplicitOrExplicitTaskingRegion(DKind) &&
VarsWithInheritedDSA.count(VD) == 0) {
- VarsWithInheritedDSA[VD] = E;
+ bool InheritedDSA = Stack->getDefaultDSA() == DSA_none;
+ if (!InheritedDSA && Stack->getDefaultDSA() == DSA_firstprivate) {
+ DSAStackTy::DSAVarData DVar =
+ Stack->getImplicitDSA(VD, /*FromParent=*/false);
+ InheritedDSA = DVar.CKind == OMPC_unknown;
+ }
+ if (InheritedDSA)
+ VarsWithInheritedDSA[VD] = E;
return;
}
@@ -3036,7 +3414,7 @@ public:
StackComponents,
OpenMPClauseKind) {
// Variable is used if it has been marked as an array, array
- // section or the variable iself.
+ // section, array shaping or the variable iself.
return StackComponents.size() == 1 ||
std::all_of(
std::next(StackComponents.rbegin()),
@@ -3047,6 +3425,8 @@ public:
nullptr &&
(isa<OMPArraySectionExpr>(
MC.getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(
+ MC.getAssociatedExpression()) ||
isa<ArraySubscriptExpr>(
MC.getAssociatedExpression()));
});
@@ -3091,7 +3471,9 @@ public:
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false);
- if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
+ if (((isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared) ||
+ (Stack->getDefaultDSA() == DSA_firstprivate &&
+ DVar.CKind == OMPC_firstprivate && !DVar.RefExpr)) &&
!Stack->isLoopControlVariable(VD).first) {
ImplicitFirstprivate.push_back(E);
return;
@@ -3112,7 +3494,7 @@ public:
return;
auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
OpenMPDirectiveKind DKind = Stack->getCurrentDirective();
- if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParens())) {
+ if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParenCasts())) {
if (!FD)
return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(FD, /*FromParent=*/false);
@@ -3204,8 +3586,10 @@ public:
// Do both expressions have the same kind?
if (CCI->getAssociatedExpression()->getStmtClass() !=
SC.getAssociatedExpression()->getStmtClass())
- if (!(isa<OMPArraySectionExpr>(
- SC.getAssociatedExpression()) &&
+ if (!((isa<OMPArraySectionExpr>(
+ SC.getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(
+ SC.getAssociatedExpression())) &&
isa<ArraySubscriptExpr>(
CCI->getAssociatedExpression())))
return false;
@@ -3516,7 +3900,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
};
// Start a captured region for 'parallel'.
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- ParamsParallel, /*OpenMPCaptureLevel=*/1);
+ ParamsParallel, /*OpenMPCaptureLevel=*/0);
QualType Args[] = {VoidPtrTy};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
@@ -3537,7 +3921,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params, /*OpenMPCaptureLevel=*/2);
+ Params, /*OpenMPCaptureLevel=*/1);
// Mark this captured region as inlined, because we don't use outlined
// function directly.
getCurCapturedRegion()->TheCapturedDecl->addAttr(
@@ -3688,6 +4072,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
@@ -3695,8 +4081,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_end_declare_target:
case OMPD_requires:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
}
@@ -3841,6 +4230,36 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) {
}
}
+static bool checkOrderedOrderSpecified(Sema &S,
+ const ArrayRef<OMPClause *> Clauses) {
+ const OMPOrderedClause *Ordered = nullptr;
+ const OMPOrderClause *Order = nullptr;
+
+ for (const OMPClause *Clause : Clauses) {
+ if (Clause->getClauseKind() == OMPC_ordered)
+ Ordered = cast<OMPOrderedClause>(Clause);
+ else if (Clause->getClauseKind() == OMPC_order) {
+ Order = cast<OMPOrderClause>(Clause);
+ if (Order->getKind() != OMPC_ORDER_concurrent)
+ Order = nullptr;
+ }
+ if (Ordered && Order)
+ break;
+ }
+
+ if (Ordered && Order) {
+ S.Diag(Order->getKindKwLoc(),
+ diag::err_omp_simple_clause_incompatible_with_ordered)
+ << getOpenMPClauseName(OMPC_order)
+ << getOpenMPSimpleClauseTypeName(OMPC_order, OMPC_ORDER_concurrent)
+ << SourceRange(Order->getBeginLoc(), Order->getEndLoc());
+ S.Diag(Ordered->getBeginLoc(), diag::note_omp_ordered_param)
+ << 0 << SourceRange(Ordered->getBeginLoc(), Ordered->getEndLoc());
+ return true;
+ }
+ return false;
+}
+
StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ArrayRef<OMPClause *> Clauses) {
bool ErrorFound = false;
@@ -3859,7 +4278,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
SmallVector<const OMPClauseWithPreInit *, 4> PICs;
// This is required for proper codegen.
for (OMPClause *Clause : Clauses) {
- if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
+ if (!LangOpts.OpenMPSimd &&
+ isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) &&
Clause->getClauseKind() == OMPC_in_reduction) {
// Capture taskgroup task_reduction descriptors inside the tasking regions
// with the corresponding in_reduction items.
@@ -3897,6 +4317,9 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
else if (Clause->getClauseKind() == OMPC_linear)
LCs.push_back(cast<OMPLinearClause>(Clause));
}
+ // Capture allocator expressions if used.
+ for (Expr *E : DSAStack->getInnerAllocators())
+ MarkDeclarationsReferencedInExpr(E);
// OpenMP, 2.7.1 Loop Construct, Restrictions
// The nonmonotonic modifier cannot be specified if an ordered clause is
// specified.
@@ -3908,10 +4331,18 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic
? SC->getFirstScheduleModifierLoc()
: SC->getSecondScheduleModifierLoc(),
- diag::err_omp_schedule_nonmonotonic_ordered)
+ diag::err_omp_simple_clause_incompatible_with_ordered)
+ << getOpenMPClauseName(OMPC_schedule)
+ << getOpenMPSimpleClauseTypeName(OMPC_schedule,
+ OMPC_SCHEDULE_MODIFIER_nonmonotonic)
<< SourceRange(OC->getBeginLoc(), OC->getEndLoc());
ErrorFound = true;
}
+ // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Restrictions.
+ // If an order(concurrent) clause is present, an ordered clause may not appear
+ // on the same directive.
+ if (checkOrderedOrderSpecified(*this, Clauses))
+ ErrorFound = true;
if (!LCs.empty() && OC && OC->getNumForLoops()) {
for (const OMPLinearClause *C : LCs) {
Diag(C->getBeginLoc(), diag::err_omp_linear_ordered)
@@ -3952,6 +4383,21 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
}
}
}
+ if (ThisCaptureRegion == OMPD_target) {
+ // Capture allocator traits in the target region. They are used implicitly
+ // and, thus, are not captured by default.
+ for (OMPClause *C : Clauses) {
+ if (const auto *UAC = dyn_cast<OMPUsesAllocatorsClause>(C)) {
+ for (unsigned I = 0, End = UAC->getNumberOfAllocators(); I < End;
+ ++I) {
+ OMPUsesAllocatorsClause::Data D = UAC->getAllocatorData(I);
+ if (Expr *E = D.AllocatorTraits)
+ MarkDeclarationsReferencedInExpr(E);
+ }
+ continue;
+ }
+ }
+ }
if (++CompletedRegions == CaptureRegions.size())
DSAStack->setBodyComplete();
SR = ActOnCapturedRegionEnd(SR.get());
@@ -3991,12 +4437,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ShouldBeInParallelRegion,
ShouldBeInOrderedRegion,
ShouldBeInTargetRegion,
- ShouldBeInTeamsRegion
+ ShouldBeInTeamsRegion,
+ ShouldBeInLoopSimdRegion,
} Recommend = NoRecommend;
if (isOpenMPSimdDirective(ParentRegion) &&
((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) ||
(SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered &&
- CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic))) {
+ CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic &&
+ CurrentRegion != OMPD_scan))) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
// OpenMP [2.8.1,simd Construct, Restrictions]
@@ -4041,7 +4489,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
if (ParentRegion == OMPD_unknown &&
!isOpenMPNestingTeamsDirective(CurrentRegion) &&
CurrentRegion != OMPD_cancellation_point &&
- CurrentRegion != OMPD_cancel)
+ CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_scan)
return false;
if (CurrentRegion == OMPD_cancellation_point ||
CurrentRegion == OMPD_cancel) {
@@ -4066,7 +4514,12 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ParentRegion == OMPD_distribute_parallel_for ||
ParentRegion == OMPD_teams_distribute_parallel_for ||
ParentRegion == OMPD_target_teams_distribute_parallel_for)) ||
- (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) ||
+ (CancelRegion == OMPD_taskgroup &&
+ (ParentRegion == OMPD_task ||
+ (SemaRef.getLangOpts().OpenMP >= 50 &&
+ (ParentRegion == OMPD_taskloop ||
+ ParentRegion == OMPD_master_taskloop ||
+ ParentRegion == OMPD_parallel_master_taskloop)))) ||
(CancelRegion == OMPD_sections &&
(ParentRegion == OMPD_section || ParentRegion == OMPD_sections ||
ParentRegion == OMPD_parallel_sections)));
@@ -4150,6 +4603,17 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack,
ParentRegion != OMPD_target);
OrphanSeen = ParentRegion == OMPD_unknown;
Recommend = ShouldBeInTargetRegion;
+ } else if (CurrentRegion == OMPD_scan) {
+ // OpenMP [2.16, Nesting of Regions]
+ // If specified, a teams construct must be contained within a target
+ // construct.
+ NestingProhibited =
+ SemaRef.LangOpts.OpenMP < 50 ||
+ (ParentRegion != OMPD_simd && ParentRegion != OMPD_for &&
+ ParentRegion != OMPD_for_simd && ParentRegion != OMPD_parallel_for &&
+ ParentRegion != OMPD_parallel_for_simd);
+ OrphanSeen = ParentRegion == OMPD_unknown;
+ Recommend = ShouldBeInLoopSimdRegion;
}
if (!NestingProhibited &&
!isOpenMPTargetExecutionDirective(CurrentRegion) &&
@@ -4216,7 +4680,7 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind,
bool ErrorFound = false;
unsigned NamedModifiersNumber = 0;
llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers;
- FoundNameModifiers.resize(unsigned(OMPD_unknown) + 1);
+ FoundNameModifiers.resize(llvm::omp::Directive_enumSize + 1);
SmallVector<SourceLocation, 4> NameModifierLoc;
for (const OMPClause *C : Clauses) {
if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) {
@@ -4353,6 +4817,30 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr,
getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false);
}
+namespace {
+/// Checks if the allocator is used in uses_allocators clause to be allowed in
+/// target regions.
+class AllocatorChecker final : public ConstStmtVisitor<AllocatorChecker, bool> {
+ DSAStackTy *S = nullptr;
+
+public:
+ bool VisitDeclRefExpr(const DeclRefExpr *E) {
+ return S->isUsesAllocatorsDecl(E->getDecl())
+ .getValueOr(
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) ==
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait;
+ }
+ bool VisitStmt(const Stmt *S) {
+ for (const Stmt *Child : S->children()) {
+ if (Child && Visit(Child))
+ return true;
+ }
+ return false;
+ }
+ explicit AllocatorChecker(DSAStackTy *S) : S(S) {}
+};
+} // namespace
+
static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
ArrayRef<OMPClause *> Clauses) {
assert(!S.CurContext->isDependentContext() &&
@@ -4421,6 +4909,22 @@ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
}
for (OMPClause *C : AllocateRange) {
auto *AC = cast<OMPAllocateClause>(C);
+ if (S.getLangOpts().OpenMP >= 50 &&
+ !Stack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>() &&
+ isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) &&
+ AC->getAllocator()) {
+ Expr *Allocator = AC->getAllocator();
+ // OpenMP, 2.12.5 target Construct
+ // Memory allocators that do not appear in a uses_allocators clause cannot
+ // appear as an allocator in an allocate clause or be used in the target
+ // region unless a requires directive with the dynamic_allocators clause
+ // is present in the same compilation unit.
+ AllocatorChecker Checker(Stack);
+ if (Checker.Visit(Allocator))
+ S.Diag(Allocator->getExprLoc(),
+ diag::err_omp_allocator_not_in_uses_allocators)
+ << Allocator->getSourceRange();
+ }
OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
getAllocatorKind(S, Stack, AC->getAllocator());
// OpenMP, 2.11.4 allocate Clause, Restrictions.
@@ -4513,6 +5017,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
if (E)
ImplicitFirstprivates.emplace_back(E);
}
+ // OpenMP 5.0, 2.10.1 task Construct
+ // [detach clause]... The event-handle will be considered as if it was
+ // specified on a firstprivate clause.
+ if (auto *DC = dyn_cast<OMPDetachClause>(C))
+ ImplicitFirstprivates.push_back(DC->getEventHandler());
}
if (!ImplicitFirstprivates.empty()) {
if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
@@ -4648,6 +5157,16 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
"No associated statement allowed for 'omp flush' directive");
Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc);
break;
+ case OMPD_depobj:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp depobj' directive");
+ Res = ActOnOpenMPDepobjDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
+ case OMPD_scan:
+ assert(AStmt == nullptr &&
+ "No associated statement allowed for 'omp scan' directive");
+ Res = ActOnOpenMPScanDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ break;
case OMPD_ordered:
Res = ActOnOpenMPOrderedDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);
@@ -4848,15 +5367,20 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPD_declare_simd:
case OMPD_requires:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
ErrorFound = Res.isInvalid() || ErrorFound;
- // Check variables in the clauses if default(none) was specified.
- if (DSAStack->getDefaultDSA() == DSA_none) {
+ // Check variables in the clauses if default(none) or
+ // default(firstprivate) was specified.
+ if (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_firstprivate) {
DSAAttrChecker DSAChecker(DSAStack, *this, nullptr);
for (OMPClause *C : Clauses) {
switch (C->getClauseKind()) {
@@ -4876,6 +5400,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
break;
continue;
case OMPC_schedule:
+ case OMPC_detach:
break;
case OMPC_grainsize:
case OMPC_num_tasks:
@@ -4915,6 +5440,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
@@ -4924,11 +5453,19 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
continue;
case OMPC_allocator:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_threadprivate:
case OMPC_uniform:
case OMPC_unknown:
@@ -4939,6 +5476,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ default:
llvm_unreachable("Unexpected clause");
}
for (Stmt *CC : C->children()) {
@@ -4946,14 +5484,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
DSAChecker.Visit(CC);
}
}
- for (auto &P : DSAChecker.getVarsWithInheritedDSA())
+ for (const 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;
- if (DSAStack->getDefaultDSA() == DSA_none) {
+ if (DSAStack->getDefaultDSA() == DSA_none ||
+ DSAStack->getDefaultDSA() == DSA_firstprivate) {
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);
@@ -4973,12 +5512,6 @@ 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>() ||
@@ -5166,7 +5699,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
E->containsUnexpandedParameterPack())
continue;
(void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind,
- PVD->getOriginalType());
+ PVD->getOriginalType(),
+ /*IsDeclareSimd=*/true);
continue;
}
}
@@ -5186,7 +5720,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
continue;
(void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind,
- E->getType());
+ E->getType(), /*IsDeclareSimd=*/true);
continue;
}
Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
@@ -5264,9 +5798,170 @@ static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
FD->setParams(Params);
}
+Sema::OMPDeclareVariantScope::OMPDeclareVariantScope(OMPTraitInfo &TI)
+ : TI(&TI), NameSuffix(TI.getMangledName()) {}
+
+FunctionDecl *
+Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S,
+ Declarator &D) {
+ IdentifierInfo *BaseII = D.getIdentifier();
+ LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(),
+ LookupOrdinaryName);
+ LookupParsedName(Lookup, S, &D.getCXXScopeSpec());
+
+ TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S);
+ QualType FType = TInfo->getType();
+
+ bool IsConstexpr = D.getDeclSpec().getConstexprSpecifier() == CSK_constexpr;
+ bool IsConsteval = D.getDeclSpec().getConstexprSpecifier() == CSK_consteval;
+
+ FunctionDecl *BaseFD = nullptr;
+ for (auto *Candidate : Lookup) {
+ auto *UDecl = dyn_cast<FunctionDecl>(Candidate->getUnderlyingDecl());
+ if (!UDecl)
+ continue;
+
+ // Don't specialize constexpr/consteval functions with
+ // non-constexpr/consteval functions.
+ if (UDecl->isConstexpr() && !IsConstexpr)
+ continue;
+ if (UDecl->isConsteval() && !IsConsteval)
+ continue;
+
+ QualType NewType = Context.mergeFunctionTypes(
+ FType, UDecl->getType(), /* OfBlockPointer */ false,
+ /* Unqualified */ false, /* AllowCXX */ true);
+ if (NewType.isNull())
+ continue;
+
+ // Found a base!
+ BaseFD = UDecl;
+ break;
+ }
+ if (!BaseFD) {
+ BaseFD = cast<FunctionDecl>(ActOnDeclarator(S, D));
+ BaseFD->setImplicit(true);
+ }
+
+ OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back();
+ std::string MangledName;
+ MangledName += D.getIdentifier()->getName();
+ MangledName += getOpenMPVariantManglingSeparatorStr();
+ MangledName += DVScope.NameSuffix;
+ IdentifierInfo &VariantII = Context.Idents.get(MangledName);
+
+ VariantII.setMangledOpenMPVariantName(true);
+ D.SetIdentifier(&VariantII, D.getBeginLoc());
+ return BaseFD;
+}
+
+void Sema::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope(
+ FunctionDecl *FD, FunctionDecl *BaseFD) {
+ // Do not mark function as is used to prevent its emission if this is the
+ // only place where it is used.
+ EnterExpressionEvaluationContext Unevaluated(
+ *this, Sema::ExpressionEvaluationContext::Unevaluated);
+
+ Expr *VariantFuncRef = DeclRefExpr::Create(
+ Context, NestedNameSpecifierLoc(), SourceLocation(), FD,
+ /* RefersToEnclosingVariableOrCapture */ false,
+ /* NameLoc */ FD->getLocation(), FD->getType(), ExprValueKind::VK_RValue);
+
+ OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back();
+ auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit(
+ Context, VariantFuncRef, DVScope.TI);
+ BaseFD->addAttr(OMPDeclareVariantA);
+}
+
+ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
+ SourceLocation LParenLoc,
+ MultiExprArg ArgExprs,
+ SourceLocation RParenLoc, Expr *ExecConfig) {
+ // The common case is a regular call we do not want to specialize at all. Try
+ // to make that case fast by bailing early.
+ CallExpr *CE = dyn_cast<CallExpr>(Call.get());
+ if (!CE)
+ return Call;
+
+ FunctionDecl *CalleeFnDecl = CE->getDirectCallee();
+ if (!CalleeFnDecl)
+ return Call;
+
+ if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>())
+ return Call;
+
+ ASTContext &Context = getASTContext();
+ OMPContext OMPCtx(getLangOpts().OpenMPIsDevice,
+ Context.getTargetInfo().getTriple());
+
+ SmallVector<Expr *, 4> Exprs;
+ SmallVector<VariantMatchInfo, 4> VMIs;
+ while (CalleeFnDecl) {
+ for (OMPDeclareVariantAttr *A :
+ CalleeFnDecl->specific_attrs<OMPDeclareVariantAttr>()) {
+ Expr *VariantRef = A->getVariantFuncRef();
+
+ VariantMatchInfo VMI;
+ OMPTraitInfo &TI = A->getTraitInfo();
+ TI.getAsVariantMatchInfo(Context, VMI);
+ if (!isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ false))
+ continue;
+
+ VMIs.push_back(VMI);
+ Exprs.push_back(VariantRef);
+ }
+
+ CalleeFnDecl = CalleeFnDecl->getPreviousDecl();
+ }
+
+ ExprResult NewCall;
+ do {
+ int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
+ if (BestIdx < 0)
+ return Call;
+ Expr *BestExpr = cast<DeclRefExpr>(Exprs[BestIdx]);
+ Decl *BestDecl = cast<DeclRefExpr>(BestExpr)->getDecl();
+
+ {
+ // Try to build a (member) call expression for the current best applicable
+ // variant expression. We allow this to fail in which case we continue
+ // with the next best variant expression. The fail case is part of the
+ // implementation defined behavior in the OpenMP standard when it talks
+ // about what differences in the function prototypes: "Any differences
+ // that the specific OpenMP context requires in the prototype of the
+ // variant from the base function prototype are implementation defined."
+ // This wording is there to allow the specialized variant to have a
+ // different type than the base function. This is intended and OK but if
+ // we cannot create a call the difference is not in the "implementation
+ // defined range" we allow.
+ Sema::TentativeAnalysisScope Trap(*this);
+
+ if (auto *SpecializedMethod = dyn_cast<CXXMethodDecl>(BestDecl)) {
+ auto *MemberCall = dyn_cast<CXXMemberCallExpr>(CE);
+ BestExpr = MemberExpr::CreateImplicit(
+ Context, MemberCall->getImplicitObjectArgument(),
+ /* IsArrow */ false, SpecializedMethod, Context.BoundMemberTy,
+ MemberCall->getValueKind(), MemberCall->getObjectKind());
+ }
+ NewCall = BuildCallExpr(Scope, BestExpr, LParenLoc, ArgExprs, RParenLoc,
+ ExecConfig);
+ if (NewCall.isUsable())
+ break;
+ }
+
+ VMIs.erase(VMIs.begin() + BestIdx);
+ Exprs.erase(Exprs.begin() + BestIdx);
+ } while (!VMIs.empty());
+
+ if (!NewCall.isUsable())
+ return Call;
+ return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0);
+}
+
Optional<std::pair<FunctionDecl *, Expr *>>
Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
- Expr *VariantRef, SourceRange SR) {
+ Expr *VariantRef, OMPTraitInfo &TI,
+ SourceRange SR) {
if (!DG || DG.get().isNull())
return None;
@@ -5319,12 +6014,41 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return None;
}
+ auto ShouldDelayChecks = [](Expr *&E, bool) {
+ return E && (E->isTypeDependent() || E->isValueDependent() ||
+ E->containsUnexpandedParameterPack() ||
+ E->isInstantiationDependent());
+ };
// Do not check templates, wait until instantiation.
- if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() ||
- VariantRef->containsUnexpandedParameterPack() ||
- VariantRef->isInstantiationDependent() || FD->isDependentContext())
+ if (FD->isDependentContext() || ShouldDelayChecks(VariantRef, false) ||
+ TI.anyScoreOrCondition(ShouldDelayChecks))
return std::make_pair(FD, VariantRef);
+ // Deal with non-constant score and user condition expressions.
+ auto HandleNonConstantScoresAndConditions = [this](Expr *&E,
+ bool IsScore) -> bool {
+ llvm::APSInt Result;
+ if (!E || E->isIntegerConstantExpr(Result, Context))
+ return false;
+
+ if (IsScore) {
+ // We warn on non-constant scores and pretend they were not present.
+ Diag(E->getExprLoc(), diag::warn_omp_declare_variant_score_not_constant)
+ << E;
+ E = nullptr;
+ } else {
+ // We could replace a non-constant user condition with "false" but we
+ // will soon need to handle these anyway for the dynamic version of
+ // OpenMP context selectors.
+ Diag(E->getExprLoc(),
+ diag::err_omp_declare_variant_user_condition_not_constant)
+ << E;
+ }
+ return true;
+ };
+ if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions))
+ return None;
+
// Convert VariantRef expression to the type of the original function to
// resolve possible conflicts.
ExprResult VariantRefCast;
@@ -5355,7 +6079,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
ImplicitConversionSequence ICS =
TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(),
/*SuppressUserConversions=*/false,
- /*AllowExplicit=*/false,
+ AllowedExplicit::None,
/*InOverloadResolution=*/false,
/*CStyle=*/false,
/*AllowObjCWritebackConversion=*/false);
@@ -5497,94 +6221,13 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG,
return std::make_pair(FD, cast<Expr>(DRE));
}
-void Sema::ActOnOpenMPDeclareVariantDirective(
- FunctionDecl *FD, Expr *VariantRef, SourceRange SR,
- ArrayRef<OMPCtxSelectorData> Data) {
- if (Data.empty())
- return;
- SmallVector<Expr *, 4> CtxScores;
- SmallVector<unsigned, 4> CtxSets;
- SmallVector<unsigned, 4> Ctxs;
- SmallVector<StringRef, 4> ImplVendors, DeviceKinds;
- bool IsError = false;
- for (const OMPCtxSelectorData &D : Data) {
- OpenMPContextSelectorSetKind CtxSet = D.CtxSet;
- OpenMPContextSelectorKind Ctx = D.Ctx;
- if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown)
- return;
- Expr *Score = nullptr;
- if (D.Score.isUsable()) {
- Score = D.Score.get();
- if (!Score->isTypeDependent() && !Score->isValueDependent() &&
- !Score->isInstantiationDependent() &&
- !Score->containsUnexpandedParameterPack()) {
- Score =
- PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score)
- .get();
- if (Score)
- Score = VerifyIntegerConstantExpression(Score).get();
- }
- } else {
- // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors.
- // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and
- // 2^(l+2), respectively, where l is the number of traits in the construct
- // set.
- // TODO: implement correct logic for isa and arch traits.
- // TODO: take the construct context set into account when it is
- // implemented.
- int L = 0; // Currently set the number of traits in construct set to 0,
- // since the construct trait set in not supported yet.
- if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind)
- Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get();
- else
- Score = ActOnIntegerConstant(SourceLocation(), 0).get();
- }
- switch (Ctx) {
- case OMP_CTX_vendor:
- assert(CtxSet == OMP_CTX_SET_implementation &&
- "Expected implementation context selector set.");
- ImplVendors.append(D.Names.begin(), D.Names.end());
- break;
- case OMP_CTX_kind:
- assert(CtxSet == OMP_CTX_SET_device &&
- "Expected device context selector set.");
- DeviceKinds.append(D.Names.begin(), D.Names.end());
- break;
- case OMP_CTX_unknown:
- llvm_unreachable("Unknown context selector kind.");
- }
- IsError = IsError || !Score;
- CtxSets.push_back(CtxSet);
- Ctxs.push_back(Ctx);
- CtxScores.push_back(Score);
- }
- if (!IsError) {
- auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit(
- Context, VariantRef, CtxScores.begin(), CtxScores.size(),
- CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(),
- ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(),
- DeviceKinds.size(), SR);
- FD->addAttr(NewAttr);
- }
-}
-
-void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc,
- FunctionDecl *Func,
- bool MightBeOdrUse) {
- assert(LangOpts.OpenMP && "Expected OpenMP mode.");
-
- if (!Func->isDependentContext() && Func->hasAttrs()) {
- for (OMPDeclareVariantAttr *A :
- Func->specific_attrs<OMPDeclareVariantAttr>()) {
- // TODO: add checks for active OpenMP context where possible.
- Expr *VariantRef = A->getVariantFuncRef();
- auto *DRE = cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts());
- auto *F = cast<FunctionDecl>(DRE->getDecl());
- if (!F->isDefined() && F->isTemplateInstantiation())
- InstantiateFunctionDefinition(Loc, F->getFirstDecl());
- MarkFunctionReferenced(Loc, F, MightBeOdrUse);
- }
- }
+void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD,
+ Expr *VariantRef,
+ OMPTraitInfo &TI,
+ SourceRange SR) {
+ auto *NewAttr =
+ OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR);
+ FD->addAttr(NewAttr);
}
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
@@ -5605,6 +6248,7 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(),
DSAStack->isCancelRegion());
}
@@ -6300,8 +6944,8 @@ bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) {
static ExprResult
tryBuildCapture(Sema &SemaRef, Expr *Capture,
llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
- if (SemaRef.CurContext->isDependentContext())
- return ExprResult(Capture);
+ if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors())
+ return Capture;
if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects))
return SemaRef.PerformImplicitConversion(
Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting,
@@ -6315,221 +6959,344 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture,
return Res;
}
-/// Build the expression to calculate the number of iterations.
-Expr *OpenMPIterationSpaceChecker::buildNumIterations(
- Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
- llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
- ExprResult Diff;
- QualType VarType = LCDecl->getType().getNonReferenceType();
- if (VarType->isIntegerType() || VarType->isPointerType() ||
- SemaRef.getLangOpts().CPlusPlus) {
- Expr *LBVal = LB;
- Expr *UBVal = UB;
- // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
- // max(LB(MinVal), LB(MaxVal))
- if (InitDependOnLC) {
- const LoopIterationSpace &IS =
- ResultIterSpaces[ResultIterSpaces.size() - 1 -
- InitDependOnLC.getValueOr(
- CondDependOnLC.getValueOr(0))];
- if (!IS.MinValue || !IS.MaxValue)
- return nullptr;
- // OuterVar = Min
- ExprResult MinValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
- if (!MinValue.isUsable())
- return nullptr;
-
- ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MinValue.get());
- if (!LBMinVal.isUsable())
- return nullptr;
- // OuterVar = Min, LBVal
- LBMinVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal);
- if (!LBMinVal.isUsable())
- return nullptr;
- // (OuterVar = Min, LBVal)
- LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get());
- if (!LBMinVal.isUsable())
- return nullptr;
-
- // OuterVar = Max
- ExprResult MaxValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
- if (!MaxValue.isUsable())
- return nullptr;
-
- ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MaxValue.get());
- if (!LBMaxVal.isUsable())
- return nullptr;
- // OuterVar = Max, LBVal
- LBMaxVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal);
- if (!LBMaxVal.isUsable())
- return nullptr;
- // (OuterVar = Max, LBVal)
- LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get());
- if (!LBMaxVal.isUsable())
- return nullptr;
-
- Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get();
- Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get();
- if (!LBMin || !LBMax)
- return nullptr;
- // LB(MinVal) < LB(MaxVal)
- ExprResult MinLessMaxRes =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
- if (!MinLessMaxRes.isUsable())
- return nullptr;
- Expr *MinLessMax =
- tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
- if (!MinLessMax)
- return nullptr;
- if (TestIsLessOp.getValue()) {
- // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
- // LB(MaxVal))
- ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
- MinLessMax, LBMin, LBMax);
- if (!MinLB.isUsable())
- return nullptr;
- LBVal = MinLB.get();
- } else {
- // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
- // LB(MaxVal))
- ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
- MinLessMax, LBMax, LBMin);
- if (!MaxLB.isUsable())
- return nullptr;
- LBVal = MaxLB.get();
- }
+/// Calculate number of iterations, transforming to unsigned, if number of
+/// iterations may be larger than the original type.
+static Expr *
+calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc,
+ Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy,
+ bool TestIsStrictOp, bool RoundToStep,
+ llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) {
+ ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
+ if (!NewStep.isUsable())
+ return nullptr;
+ llvm::APSInt LRes, URes, SRes;
+ bool IsLowerConst = Lower->isIntegerConstantExpr(LRes, SemaRef.Context);
+ bool IsStepConst = Step->isIntegerConstantExpr(SRes, SemaRef.Context);
+ bool NoNeedToConvert = IsLowerConst && !RoundToStep &&
+ ((!TestIsStrictOp && LRes.isNonNegative()) ||
+ (TestIsStrictOp && LRes.isStrictlyPositive()));
+ bool NeedToReorganize = false;
+ // Check if any subexpressions in Lower -Step [+ 1] lead to overflow.
+ if (!NoNeedToConvert && IsLowerConst &&
+ (TestIsStrictOp || (RoundToStep && IsStepConst))) {
+ NoNeedToConvert = true;
+ if (RoundToStep) {
+ unsigned BW = LRes.getBitWidth() > SRes.getBitWidth()
+ ? LRes.getBitWidth()
+ : SRes.getBitWidth();
+ LRes = LRes.extend(BW + 1);
+ LRes.setIsSigned(true);
+ SRes = SRes.extend(BW + 1);
+ SRes.setIsSigned(true);
+ LRes -= SRes;
+ NoNeedToConvert = LRes.trunc(BW).extend(BW + 1) == LRes;
+ LRes = LRes.trunc(BW);
+ }
+ if (TestIsStrictOp) {
+ unsigned BW = LRes.getBitWidth();
+ LRes = LRes.extend(BW + 1);
+ LRes.setIsSigned(true);
+ ++LRes;
+ NoNeedToConvert =
+ NoNeedToConvert && LRes.trunc(BW).extend(BW + 1) == LRes;
+ // truncate to the original bitwidth.
+ LRes = LRes.trunc(BW);
+ }
+ NeedToReorganize = NoNeedToConvert;
+ }
+ bool IsUpperConst = Upper->isIntegerConstantExpr(URes, SemaRef.Context);
+ if (NoNeedToConvert && IsLowerConst && IsUpperConst &&
+ (!RoundToStep || IsStepConst)) {
+ unsigned BW = LRes.getBitWidth() > URes.getBitWidth() ? LRes.getBitWidth()
+ : URes.getBitWidth();
+ LRes = LRes.extend(BW + 1);
+ LRes.setIsSigned(true);
+ URes = URes.extend(BW + 1);
+ URes.setIsSigned(true);
+ URes -= LRes;
+ NoNeedToConvert = URes.trunc(BW).extend(BW + 1) == URes;
+ NeedToReorganize = NoNeedToConvert;
+ }
+ // If the boundaries are not constant or (Lower - Step [+ 1]) is not constant
+ // or less than zero (Upper - (Lower - Step [+ 1]) may overflow) - promote to
+ // unsigned.
+ if ((!NoNeedToConvert || (LRes.isNegative() && !IsUpperConst)) &&
+ !LCTy->isDependentType() && LCTy->isIntegerType()) {
+ QualType LowerTy = Lower->getType();
+ QualType UpperTy = Upper->getType();
+ uint64_t LowerSize = SemaRef.Context.getTypeSize(LowerTy);
+ uint64_t UpperSize = SemaRef.Context.getTypeSize(UpperTy);
+ if ((LowerSize <= UpperSize && UpperTy->hasSignedIntegerRepresentation()) ||
+ (LowerSize > UpperSize && LowerTy->hasSignedIntegerRepresentation())) {
+ QualType CastType = SemaRef.Context.getIntTypeForBitwidth(
+ LowerSize > UpperSize ? LowerSize : UpperSize, /*Signed=*/0);
+ Upper =
+ SemaRef
+ .PerformImplicitConversion(
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(),
+ CastType, Sema::AA_Converting)
+ .get();
+ Lower = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get();
+ NewStep = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, NewStep.get());
}
- // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
- // min(UB(MinVal), UB(MaxVal))
- if (CondDependOnLC) {
- const LoopIterationSpace &IS =
- ResultIterSpaces[ResultIterSpaces.size() - 1 -
- InitDependOnLC.getValueOr(
- CondDependOnLC.getValueOr(0))];
- if (!IS.MinValue || !IS.MaxValue)
- return nullptr;
- // OuterVar = Min
- ExprResult MinValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
- if (!MinValue.isUsable())
- return nullptr;
-
- ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MinValue.get());
- if (!UBMinVal.isUsable())
- return nullptr;
- // OuterVar = Min, UBVal
- UBMinVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal);
- if (!UBMinVal.isUsable())
- return nullptr;
- // (OuterVar = Min, UBVal)
- UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get());
- if (!UBMinVal.isUsable())
- return nullptr;
+ }
+ if (!Lower || !Upper || NewStep.isInvalid())
+ return nullptr;
- // OuterVar = Max
- ExprResult MaxValue =
- SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
- if (!MaxValue.isUsable())
+ ExprResult Diff;
+ // If need to reorganize, then calculate the form as Upper - (Lower - Step [+
+ // 1]).
+ if (NeedToReorganize) {
+ Diff = Lower;
+
+ if (RoundToStep) {
+ // Lower - Step
+ Diff =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
return nullptr;
+ }
- ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
- IS.CounterVar, MaxValue.get());
- if (!UBMaxVal.isUsable())
- return nullptr;
- // OuterVar = Max, UBVal
- UBMaxVal =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal);
- if (!UBMaxVal.isUsable())
- return nullptr;
- // (OuterVar = Max, UBVal)
- UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get());
- if (!UBMaxVal.isUsable())
- return nullptr;
+ // Lower - Step [+ 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Add, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return nullptr;
- Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get();
- Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get();
- if (!UBMin || !UBMax)
- return nullptr;
- // UB(MinVal) > UB(MaxVal)
- ExprResult MinGreaterMaxRes =
- SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax);
- if (!MinGreaterMaxRes.isUsable())
- return nullptr;
- Expr *MinGreaterMax =
- tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
- if (!MinGreaterMax)
- return nullptr;
- if (TestIsLessOp.getValue()) {
- // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
- // UB(MaxVal))
- ExprResult MaxUB = SemaRef.ActOnConditionalOp(
- DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax);
- if (!MaxUB.isUsable())
- return nullptr;
- UBVal = MaxUB.get();
- } else {
- // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
- // UB(MaxVal))
- ExprResult MinUB = SemaRef.ActOnConditionalOp(
- DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin);
- if (!MinUB.isUsable())
- return nullptr;
- UBVal = MinUB.get();
- }
- }
- // Upper - Lower
- Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
- Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
- Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
- Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
- if (!Upper || !Lower)
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
+ if (!Diff.isUsable())
return nullptr;
+ // Upper - (Lower - Step [+ 1]).
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get());
+ if (!Diff.isUsable())
+ return nullptr;
+ } else {
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
- if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) {
+ if (!Diff.isUsable() && LCTy->getAsCXXRecordDecl()) {
// BuildBinOp already emitted error, this one is to point user to upper
// and lower bound, and to tell what is passed to 'operator-'.
SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx)
<< Upper->getSourceRange() << Lower->getSourceRange();
return nullptr;
}
+
+ if (!Diff.isUsable())
+ return nullptr;
+
+ // Upper - Lower [- 1]
+ if (TestIsStrictOp)
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub, Diff.get(),
+ SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ if (!Diff.isUsable())
+ return nullptr;
+
+ if (RoundToStep) {
+ // Upper - Lower [- 1] + Step
+ Diff =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get());
+ if (!Diff.isUsable())
+ return nullptr;
+ }
}
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return nullptr;
- // Upper - Lower [- 1]
- if (TestIsStrictOp)
- Diff = SemaRef.BuildBinOp(
- S, DefaultLoc, BO_Sub, Diff.get(),
- SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ // (Upper - Lower [- 1] + Step) / Step or (Upper - Lower) / Step
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
- // Upper - Lower [- 1] + Step
- ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
- if (!NewStep.isUsable())
- return nullptr;
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get());
- if (!Diff.isUsable())
+ return Diff.get();
+}
+
+/// Build the expression to calculate the number of iterations.
+Expr *OpenMPIterationSpaceChecker::buildNumIterations(
+ Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType,
+ llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const {
+ QualType VarType = LCDecl->getType().getNonReferenceType();
+ if (!VarType->isIntegerType() && !VarType->isPointerType() &&
+ !SemaRef.getLangOpts().CPlusPlus)
return nullptr;
+ Expr *LBVal = LB;
+ Expr *UBVal = UB;
+ // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) :
+ // max(LB(MinVal), LB(MaxVal))
+ if (InitDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
+ ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, LBVal
+ LBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal);
+ if (!LBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, LBVal)
+ LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get());
+ if (!LBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, LBVal
+ LBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal);
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, LBVal)
+ LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get());
+ if (!LBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get();
+ Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get();
+ if (!LBMin || !LBMax)
+ return nullptr;
+ // LB(MinVal) < LB(MaxVal)
+ ExprResult MinLessMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax);
+ if (!MinLessMaxRes.isUsable())
+ return nullptr;
+ Expr *MinLessMax =
+ tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get();
+ if (!MinLessMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMin, LBMax);
+ if (!MinLB.isUsable())
+ return nullptr;
+ LBVal = MinLB.get();
+ } else {
+ // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal),
+ // LB(MaxVal))
+ ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc,
+ MinLessMax, LBMax, LBMin);
+ if (!MaxLB.isUsable())
+ return nullptr;
+ LBVal = MaxLB.get();
+ }
+ }
+ // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) :
+ // min(UB(MinVal), UB(MaxVal))
+ if (CondDependOnLC) {
+ const LoopIterationSpace &IS =
+ ResultIterSpaces[ResultIterSpaces.size() - 1 -
+ InitDependOnLC.getValueOr(
+ CondDependOnLC.getValueOr(0))];
+ if (!IS.MinValue || !IS.MaxValue)
+ return nullptr;
+ // OuterVar = Min
+ ExprResult MinValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue);
+ if (!MinValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MinValue.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // OuterVar = Min, UBVal
+ UBMinVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal);
+ if (!UBMinVal.isUsable())
+ return nullptr;
+ // (OuterVar = Min, UBVal)
+ UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get());
+ if (!UBMinVal.isUsable())
+ return nullptr;
+
+ // OuterVar = Max
+ ExprResult MaxValue =
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue);
+ if (!MaxValue.isUsable())
+ return nullptr;
+
+ ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign,
+ IS.CounterVar, MaxValue.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // OuterVar = Max, UBVal
+ UBMaxVal =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal);
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+ // (OuterVar = Max, UBVal)
+ UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get());
+ if (!UBMaxVal.isUsable())
+ return nullptr;
+
+ Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get();
+ Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get();
+ if (!UBMin || !UBMax)
+ return nullptr;
+ // UB(MinVal) > UB(MaxVal)
+ ExprResult MinGreaterMaxRes =
+ SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax);
+ if (!MinGreaterMaxRes.isUsable())
+ return nullptr;
+ Expr *MinGreaterMax =
+ tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get();
+ if (!MinGreaterMax)
+ return nullptr;
+ if (TestIsLessOp.getValue()) {
+ // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MaxUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax);
+ if (!MaxUB.isUsable())
+ return nullptr;
+ UBVal = MaxUB.get();
+ } else {
+ // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal),
+ // UB(MaxVal))
+ ExprResult MinUB = SemaRef.ActOnConditionalOp(
+ DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin);
+ if (!MinUB.isUsable())
+ return nullptr;
+ UBVal = MinUB.get();
+ }
+ }
+ Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal;
+ Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal;
+ Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
+ Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
+ if (!Upper || !Lower)
return nullptr;
- // (Upper - Lower [- 1] + Step) / Step
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ ExprResult Diff =
+ calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType,
+ TestIsStrictOp, /*RoundToStep=*/true, Captures);
if (!Diff.isUsable())
return nullptr;
@@ -6603,55 +7370,37 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
MaxExpr = Upper;
// Build minimum/maximum value based on number of iterations.
- ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
+ ExprResult Diff =
+ calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType,
+ TestIsStrictOp, /*RoundToStep=*/false, Captures);
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // Upper - Lower [- 1]
- if (TestIsStrictOp)
- Diff = SemaRef.BuildBinOp(
- S, DefaultLoc, BO_Sub, Diff.get(),
- SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
+ // ((Upper - Lower [- 1]) / Step) * Step
+ // Parentheses (for dumping/debugging purposes only).
+ Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // Upper - Lower [- 1] + Step
ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
if (!NewStep.isUsable())
return std::make_pair(nullptr, nullptr);
-
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
-
- // (Upper - Lower [- 1]) / Step
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // ((Upper - Lower [- 1]) / Step) * Step
// Parentheses (for dumping/debugging purposes only).
Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
-
- // Convert to the original type or ptrdiff_t, if original type is pointer.
- if (!VarType->isAnyPointerType() &&
- !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) {
- Diff = SemaRef.PerformImplicitConversion(
- Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true);
- } else if (VarType->isAnyPointerType() &&
- !SemaRef.Context.hasSameType(
- Diff.get()->getType(),
- SemaRef.Context.getUnsignedPointerDiffType())) {
+ // Convert to the ptrdiff_t, if original type is pointer.
+ if (VarType->isAnyPointerType() &&
+ !SemaRef.Context.hasSameType(
+ Diff.get()->getType(),
+ SemaRef.Context.getUnsignedPointerDiffType())) {
Diff = SemaRef.PerformImplicitConversion(
Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(),
Sema::AA_Converting, /*AllowExplicit=*/true);
@@ -6659,33 +7408,43 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues(
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
-
if (TestIsLessOp.getValue()) {
// MinExpr = Lower;
// MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step)
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
- Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Add,
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get(),
+ Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- MaxExpr = Diff.get();
} else {
// MaxExpr = Upper;
// MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step)
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get());
- if (!Diff.isUsable())
- return std::make_pair(nullptr, nullptr);
- Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false);
+ Diff = SemaRef.BuildBinOp(
+ S, DefaultLoc, BO_Sub,
+ SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(),
+ Diff.get());
if (!Diff.isUsable())
return std::make_pair(nullptr, nullptr);
- MinExpr = Diff.get();
}
+ // Convert to the original type.
+ if (SemaRef.Context.hasSameType(Diff.get()->getType(), VarType))
+ Diff = SemaRef.PerformImplicitConversion(Diff.get(), VarType,
+ Sema::AA_Converting,
+ /*AllowExplicit=*/true);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue=*/false);
+ if (!Diff.isUsable())
+ return std::make_pair(nullptr, nullptr);
+
+ if (TestIsLessOp.getValue())
+ MaxExpr = Diff.get();
+ else
+ MinExpr = Diff.get();
+
return std::make_pair(MinExpr, MaxExpr);
}
@@ -6791,44 +7550,23 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData(
if (!Cnt)
return nullptr;
}
- ExprResult Diff;
QualType VarType = LCDecl->getType().getNonReferenceType();
- 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;
- if (!Upper || !Lower)
- return nullptr;
-
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower);
-
- if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) {
- // BuildBinOp already emitted error, this one is to point user to upper
- // and lower bound, and to tell what is passed to 'operator-'.
- SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx)
- << Upper->getSourceRange() << Lower->getSourceRange();
- return nullptr;
- }
- }
-
- if (!Diff.isUsable())
+ if (!VarType->isIntegerType() && !VarType->isPointerType() &&
+ !SemaRef.getLangOpts().CPlusPlus)
return nullptr;
-
- // Parentheses (for dumping/debugging purposes only).
- Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get());
- if (!Diff.isUsable())
+ // Upper - Lower
+ Expr *Upper = TestIsLessOp.getValue()
+ ? Cnt
+ : tryBuildCapture(SemaRef, LB, Captures).get();
+ Expr *Lower = TestIsLessOp.getValue()
+ ? tryBuildCapture(SemaRef, LB, Captures).get()
+ : Cnt;
+ if (!Upper || !Lower)
return nullptr;
- ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures);
- if (!NewStep.isUsable())
- return nullptr;
- // (Upper - Lower) / Step
- Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
+ ExprResult Diff = calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper,
+ Step, VarType, /*TestIsStrictOp=*/false,
+ /*RoundToStep=*/false, Captures);
if (!Diff.isUsable())
return nullptr;
@@ -8088,8 +8826,9 @@ Sema::ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt,
}
setFunctionHasBranchProtectedScope();
- return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount,
- Clauses, AStmt, B, DSAStack->isCancelRegion());
+ return OMPForDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPForSimdDirective(
@@ -8166,6 +8905,7 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(),
DSAStack->isCancelRegion());
}
@@ -8326,9 +9066,9 @@ StmtResult Sema::ActOnOpenMPParallelForDirective(
}
setFunctionHasBranchProtectedScope();
- return OMPParallelForDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ return OMPParallelForDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
@@ -8392,8 +9132,9 @@ Sema::ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
- return OMPParallelMasterDirective::Create(Context, StartLoc, EndLoc, Clauses,
- AStmt);
+ return OMPParallelMasterDirective::Create(
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef());
}
StmtResult
@@ -8432,7 +9173,31 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
return OMPParallelSectionsDirective::Create(
- Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion());
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
+}
+
+/// detach and mergeable clauses are mutially exclusive, check for it.
+static bool checkDetachMergeableClauses(Sema &S,
+ ArrayRef<OMPClause *> Clauses) {
+ const OMPClause *PrevClause = nullptr;
+ bool ErrorFound = false;
+ for (const OMPClause *C : Clauses) {
+ if (C->getClauseKind() == OMPC_detach ||
+ C->getClauseKind() == OMPC_mergeable) {
+ if (!PrevClause) {
+ PrevClause = C;
+ } else if (PrevClause->getClauseKind() != C->getClauseKind()) {
+ S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive)
+ << getOpenMPClauseName(C->getClauseKind())
+ << getOpenMPClauseName(PrevClause->getClauseKind());
+ S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause)
+ << getOpenMPClauseName(PrevClause->getClauseKind());
+ ErrorFound = true;
+ }
+ }
+ }
+ return ErrorFound;
}
StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
@@ -8441,6 +9206,12 @@ StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses,
if (!AStmt)
return StmtError();
+ // OpenMP 5.0, 2.10.1 task Construct
+ // If a detach clause appears on the directive, then a mergeable clause cannot
+ // appear on the same directive.
+ if (checkDetachMergeableClauses(*this, Clauses))
+ return StmtError();
+
auto *CS = cast<CapturedStmt>(AStmt);
// 1.2.2 OpenMP Language Terminology
// Structured block - An executable statement with a single entry at the
@@ -8489,10 +9260,94 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses,
StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc) {
- assert(Clauses.size() <= 1 && "Extra clauses in flush directive");
+ OMPFlushClause *FC = nullptr;
+ OMPClause *OrderClause = nullptr;
+ for (OMPClause *C : Clauses) {
+ if (C->getClauseKind() == OMPC_flush)
+ FC = cast<OMPFlushClause>(C);
+ else
+ OrderClause = C;
+ }
+ OpenMPClauseKind MemOrderKind = OMPC_unknown;
+ SourceLocation MemOrderLoc;
+ for (const OMPClause *C : Clauses) {
+ if (C->getClauseKind() == OMPC_acq_rel ||
+ C->getClauseKind() == OMPC_acquire ||
+ C->getClauseKind() == OMPC_release) {
+ if (MemOrderKind != OMPC_unknown) {
+ Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses)
+ << getOpenMPDirectiveName(OMPD_flush) << 1
+ << SourceRange(C->getBeginLoc(), C->getEndLoc());
+ Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause)
+ << getOpenMPClauseName(MemOrderKind);
+ } else {
+ MemOrderKind = C->getClauseKind();
+ MemOrderLoc = C->getBeginLoc();
+ }
+ }
+ }
+ if (FC && OrderClause) {
+ Diag(FC->getLParenLoc(), diag::err_omp_flush_order_clause_and_list)
+ << getOpenMPClauseName(OrderClause->getClauseKind());
+ Diag(OrderClause->getBeginLoc(), diag::note_omp_flush_order_clause_here)
+ << getOpenMPClauseName(OrderClause->getClauseKind());
+ return StmtError();
+ }
return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses);
}
+StmtResult Sema::ActOnOpenMPDepobjDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (Clauses.empty()) {
+ Diag(StartLoc, diag::err_omp_depobj_expected);
+ return StmtError();
+ } else if (Clauses[0]->getClauseKind() != OMPC_depobj) {
+ Diag(Clauses[0]->getBeginLoc(), diag::err_omp_depobj_expected);
+ return StmtError();
+ }
+ // Only depobj expression and another single clause is allowed.
+ if (Clauses.size() > 2) {
+ Diag(Clauses[2]->getBeginLoc(),
+ diag::err_omp_depobj_single_clause_expected);
+ return StmtError();
+ } else if (Clauses.size() < 1) {
+ Diag(Clauses[0]->getEndLoc(), diag::err_omp_depobj_single_clause_expected);
+ return StmtError();
+ }
+ return OMPDepobjDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
+StmtResult Sema::ActOnOpenMPScanDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ // Check that exactly one clause is specified.
+ if (Clauses.size() != 1) {
+ Diag(Clauses.empty() ? EndLoc : Clauses[1]->getBeginLoc(),
+ diag::err_omp_scan_single_clause_expected);
+ return StmtError();
+ }
+ // Check that scan directive is used in the scopeof the OpenMP loop body.
+ if (Scope *S = DSAStack->getCurScope()) {
+ Scope *ParentS = S->getParent();
+ if (!ParentS || ParentS->getParent() != ParentS->getBreakParent() ||
+ !ParentS->getBreakParent()->isOpenMPLoopScope())
+ return StmtError(Diag(StartLoc, diag::err_omp_orphaned_device_directive)
+ << getOpenMPDirectiveName(OMPD_scan) << 5);
+ }
+ // Check that only one instance of scan directives is used in the same outer
+ // region.
+ if (DSAStack->doesParentHasScanDirective()) {
+ Diag(StartLoc, diag::err_omp_several_directives_in_region) << "scan";
+ Diag(DSAStack->getParentScanDirectiveLoc(),
+ diag::note_omp_previous_directive)
+ << "scan";
+ return StmtError();
+ }
+ DSAStack->setParentHasScanDirective(StartLoc);
+ return OMPScanDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -8555,13 +9410,29 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation ErrLoc = TC ? TC->getBeginLoc() : StartLoc;
Diag(ErrLoc, diag::err_omp_ordered_directive_with_param)
<< (TC != nullptr);
- Diag(Param->getBeginLoc(), diag::note_omp_ordered_param);
+ Diag(Param->getBeginLoc(), diag::note_omp_ordered_param) << 1;
ErrorFound = true;
}
}
if ((!AStmt && !DependFound) || ErrorFound)
return StmtError();
+ // OpenMP 5.0, 2.17.9, ordered Construct, Restrictions.
+ // During execution of an iteration of a worksharing-loop or a loop nest
+ // within a worksharing-loop, simd, or worksharing-loop SIMD region, a thread
+ // must not execute more than one ordered region corresponding to an ordered
+ // construct without a depend clause.
+ if (!DependFound) {
+ if (DSAStack->doesParentHasOrderedDirective()) {
+ Diag(StartLoc, diag::err_omp_several_directives_in_region) << "ordered";
+ Diag(DSAStack->getParentOrderedDirectiveLoc(),
+ diag::note_omp_previous_directive)
+ << "ordered";
+ return StmtError();
+ }
+ DSAStack->setParentHasOrderedDirective(StartLoc);
+ }
+
if (AStmt) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
@@ -8817,6 +9688,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
+ // Register location of the first atomic directive.
+ DSAStack->addAtomicDirectiveLoc(StartLoc);
if (!AStmt)
return StmtError();
@@ -8828,6 +9701,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
// longjmp() and throw() must not violate the entry/exit criteria.
OpenMPClauseKind AtomicKind = OMPC_unknown;
SourceLocation AtomicKindLoc;
+ OpenMPClauseKind MemOrderKind = OMPC_unknown;
+ SourceLocation MemOrderLoc;
for (const OMPClause *C : Clauses) {
if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write ||
C->getClauseKind() == OMPC_update ||
@@ -8835,13 +9710,51 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
if (AtomicKind != OMPC_unknown) {
Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses)
<< SourceRange(C->getBeginLoc(), C->getEndLoc());
- Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause)
+ Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause)
<< getOpenMPClauseName(AtomicKind);
} else {
AtomicKind = C->getClauseKind();
AtomicKindLoc = C->getBeginLoc();
}
}
+ if (C->getClauseKind() == OMPC_seq_cst ||
+ C->getClauseKind() == OMPC_acq_rel ||
+ C->getClauseKind() == OMPC_acquire ||
+ C->getClauseKind() == OMPC_release ||
+ C->getClauseKind() == OMPC_relaxed) {
+ if (MemOrderKind != OMPC_unknown) {
+ Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses)
+ << getOpenMPDirectiveName(OMPD_atomic) << 0
+ << SourceRange(C->getBeginLoc(), C->getEndLoc());
+ Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause)
+ << getOpenMPClauseName(MemOrderKind);
+ } else {
+ MemOrderKind = C->getClauseKind();
+ MemOrderLoc = C->getBeginLoc();
+ }
+ }
+ }
+ // OpenMP 5.0, 2.17.7 atomic Construct, Restrictions
+ // If atomic-clause is read then memory-order-clause must not be acq_rel or
+ // release.
+ // If atomic-clause is write then memory-order-clause must not be acq_rel or
+ // acquire.
+ // If atomic-clause is update or not present then memory-order-clause must not
+ // be acq_rel or acquire.
+ if ((AtomicKind == OMPC_read &&
+ (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_release)) ||
+ ((AtomicKind == OMPC_write || AtomicKind == OMPC_update ||
+ AtomicKind == OMPC_unknown) &&
+ (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_acquire))) {
+ SourceLocation Loc = AtomicKindLoc;
+ if (AtomicKind == OMPC_unknown)
+ Loc = StartLoc;
+ Diag(Loc, diag::err_omp_atomic_incompatible_mem_order_clause)
+ << getOpenMPClauseName(AtomicKind)
+ << (AtomicKind == OMPC_unknown ? 1 : 0)
+ << getOpenMPClauseName(MemOrderKind);
+ Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause)
+ << getOpenMPClauseName(MemOrderKind);
}
Stmt *Body = CS->getCapturedStmt();
@@ -9338,8 +10251,9 @@ Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses,
setFunctionHasBranchProtectedScope();
- return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses,
- AStmt);
+ return OMPTargetParallelDirective::Create(
+ Context, StartLoc, EndLoc, Clauses, AStmt,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
@@ -9391,9 +10305,9 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
}
setFunctionHasBranchProtectedScope();
- return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt,
- B, DSAStack->isCancelRegion());
+ return OMPTargetParallelForDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
/// Check for existence of a map clause in the list of clauses.
@@ -9418,12 +10332,18 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
- // OpenMP [2.10.1, Restrictions, p. 97]
- // At least one map clause must appear on the directive.
- if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) {
+ // OpenMP [2.12.2, target data Construct, Restrictions]
+ // At least one map, use_device_addr or use_device_ptr clause must appear on
+ // the directive.
+ if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr) &&
+ (LangOpts.OpenMP < 50 || !hasClauses(Clauses, OMPC_use_device_addr))) {
+ StringRef Expected;
+ if (LangOpts.OpenMP < 50)
+ Expected = "'map' or 'use_device_ptr'";
+ else
+ Expected = "'map', 'use_device_ptr', or 'use_device_addr'";
Diag(StartLoc, diag::err_omp_no_clause_for_directive)
- << "'map' or 'use_device_ptr'"
- << getOpenMPDirectiveName(OMPD_target_data);
+ << Expected << getOpenMPDirectiveName(OMPD_target_data);
return StmtError();
}
@@ -9604,12 +10524,10 @@ static bool checkGrainsizeNumTasksClauses(Sema &S,
if (!PrevClause)
PrevClause = C;
else if (PrevClause->getClauseKind() != C->getClauseKind()) {
- S.Diag(C->getBeginLoc(),
- diag::err_omp_grainsize_num_tasks_mutually_exclusive)
+ S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive)
<< getOpenMPClauseName(C->getClauseKind())
<< getOpenMPClauseName(PrevClause->getClauseKind());
- S.Diag(PrevClause->getBeginLoc(),
- diag::note_omp_previous_grainsize_num_tasks)
+ S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause)
<< getOpenMPClauseName(PrevClause->getClauseKind());
ErrorFound = true;
}
@@ -9678,7 +10596,8 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective(
setFunctionHasBranchProtectedScope();
return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt, B);
+ NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
@@ -9763,7 +10682,8 @@ StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective(
setFunctionHasBranchProtectedScope();
return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc,
- NestedLoopCount, Clauses, AStmt, B);
+ NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective(
@@ -9867,7 +10787,8 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective(
setFunctionHasBranchProtectedScope();
return OMPParallelMasterTaskLoopDirective::Create(
- Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective(
@@ -10004,7 +10925,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective(
setFunctionHasBranchProtectedScope();
return OMPDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective(
@@ -10301,7 +11222,6 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective(
CS->getCapturedDecl()->setNothrow();
}
-
OMPLoopDirective::HelperExprs B;
// In presence of clause 'collapse' with number of loops, it will
// define the nested loops number.
@@ -10446,7 +11366,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective(
return OMPTeamsDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses,
@@ -10575,7 +11495,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective(
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsDistributeParallelForDirective::Create(
Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
- DSAStack->isCancelRegion());
+ DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion());
}
StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective(
@@ -10721,9 +11641,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_ordered:
Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr);
break;
- case OMPC_device:
- Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc);
- break;
case OMPC_num_teams:
Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
@@ -10742,6 +11659,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_hint:
Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_depobj:
+ Res = ActOnOpenMPDepobjClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_detach:
+ Res = ActOnOpenMPDetachClause(Expr, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_device:
case OMPC_if:
case OMPC_default:
case OMPC_proc_bind:
@@ -10768,6 +11692,10 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
@@ -10780,6 +11708,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -10789,6 +11718,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -10918,10 +11854,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -10939,6 +11879,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with if-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -10988,10 +11929,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_teams:
@@ -11013,6 +11958,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_threads-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11063,10 +12009,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11085,6 +12035,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11135,10 +12086,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11157,6 +12112,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11208,10 +12164,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11229,6 +12189,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with schedule clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11280,10 +12241,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11301,6 +12266,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with schedule clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11351,10 +12317,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11373,6 +12343,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11425,10 +12396,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_taskwait:
case OMPD_cancellation_point:
case OMPD_flush:
+ case OMPD_depobj:
+ case OMPD_scan:
case OMPD_declare_reduction:
case OMPD_declare_mapper:
case OMPD_declare_simd:
case OMPD_declare_variant:
+ case OMPD_begin_declare_variant:
+ case OMPD_end_declare_variant:
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_simd:
@@ -11447,6 +12422,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_requires:
llvm_unreachable("Unexpected OpenMP directive with grainsize-clause");
case OMPD_unknown:
+ default:
llvm_unreachable("Unknown OpenMP directive");
}
break;
@@ -11474,11 +12450,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
@@ -11491,6 +12472,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -11500,6 +12482,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -11747,8 +12737,7 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
return true;
// Build the predefined allocator expressions.
bool ErrorFound = false;
- for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
- I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
StringRef Allocator =
OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind);
@@ -11775,7 +12764,8 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc,
Stack->setAllocator(AllocatorKind, Res.get());
}
if (ErrorFound) {
- S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found);
+ S.Diag(Loc, diag::err_omp_implied_type_not_found)
+ << "omp_allocator_handle_t";
return false;
}
OMPAllocatorHandleT.addConst();
@@ -11852,9 +12842,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_default:
- Res =
- ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument),
- ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPDefaultClause(static_cast<DefaultKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_proc_bind:
Res = ActOnOpenMPProcBindClause(static_cast<ProcBindKind>(Argument),
@@ -11865,6 +12854,14 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument),
ArgumentLoc, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_order:
+ Res = ActOnOpenMPOrderClause(static_cast<OpenMPOrderClauseKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_update:
+ Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument),
+ ArgumentLoc, StartLoc, LParenLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -11891,11 +12888,15 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_read:
case OMPC_write:
- case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
@@ -11915,6 +12916,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -11923,6 +12925,13 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -11946,34 +12955,36 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last,
else if (I + Skipped + 1 != Last)
Out << ", ";
}
- return Out.str();
+ return std::string(Out.str());
}
-OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind,
+OMPClause *Sema::ActOnOpenMPDefaultClause(DefaultKind Kind,
SourceLocation KindKwLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- if (Kind == OMPC_DEFAULT_unknown) {
- static_assert(OMPC_DEFAULT_unknown > 0,
- "OMPC_DEFAULT_unknown not greater than 0");
+ if (Kind == OMP_DEFAULT_unknown) {
Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
<< getListOfPossibleValues(OMPC_default, /*First=*/0,
- /*Last=*/OMPC_DEFAULT_unknown)
+ /*Last=*/unsigned(OMP_DEFAULT_unknown))
<< getOpenMPClauseName(OMPC_default);
return nullptr;
}
+
switch (Kind) {
- case OMPC_DEFAULT_none:
+ case OMP_DEFAULT_none:
DSAStack->setDefaultDSANone(KindKwLoc);
break;
- case OMPC_DEFAULT_shared:
+ case OMP_DEFAULT_shared:
DSAStack->setDefaultDSAShared(KindKwLoc);
break;
- case OMPC_DEFAULT_unknown:
- llvm_unreachable("Clause kind is not allowed.");
+ case OMP_DEFAULT_firstprivate:
+ DSAStack->setDefaultDSAFirstPrivate(KindKwLoc);
break;
+ default:
+ llvm_unreachable("DSA unexpected in OpenMP default clause");
}
+
return new (Context)
OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
}
@@ -12010,6 +13021,43 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause(
LParenLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_ORDER_unknown) {
+ static_assert(OMPC_ORDER_unknown > 0,
+ "OMPC_ORDER_unknown not greater than 0");
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_order, /*First=*/0,
+ /*Last=*/OMPC_ORDER_unknown)
+ << getOpenMPClauseName(OMPC_order);
+ return nullptr;
+ }
+ return new (Context)
+ OMPOrderClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind,
+ SourceLocation KindKwLoc,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_DEPEND_unknown || Kind == OMPC_DEPEND_source ||
+ Kind == OMPC_DEPEND_sink || Kind == OMPC_DEPEND_depobj) {
+ unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink,
+ OMPC_DEPEND_depobj};
+ Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_depend, /*First=*/0,
+ /*Last=*/OMPC_DEPEND_unknown, Except)
+ << getOpenMPClauseName(OMPC_update);
+ return nullptr;
+ }
+ return OMPUpdateClause::Create(Context, StartLoc, LParenLoc, KindKwLoc, Kind,
+ EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr,
SourceLocation StartLoc, SourceLocation LParenLoc,
@@ -12047,6 +13095,12 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind],
EndLoc);
break;
+ case OMPC_device:
+ assert(Argument.size() == 1 && ArgumentLoc.size() == 1);
+ Res = ActOnOpenMPDeviceClause(
+ static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr,
+ StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc);
+ break;
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
@@ -12073,13 +13127,17 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_read:
case OMPC_write:
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_depend:
- case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_map:
@@ -12095,6 +13153,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_unified_address:
case OMPC_unified_shared_memory:
@@ -12104,6 +13163,14 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12170,7 +13237,9 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
// OpenMP, 2.7.1, Loop Construct, Restrictions
// The nonmonotonic modifier can only be specified with schedule(dynamic) or
// schedule(guided).
- if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
+ // OpenMP 5.0 does not have this restriction.
+ if (LangOpts.OpenMP < 50 &&
+ (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ||
M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) &&
Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) {
Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc,
@@ -12250,6 +13319,18 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_seq_cst:
Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc);
break;
+ case OMPC_acq_rel:
+ Res = ActOnOpenMPAcqRelClause(StartLoc, EndLoc);
+ break;
+ case OMPC_acquire:
+ Res = ActOnOpenMPAcquireClause(StartLoc, EndLoc);
+ break;
+ case OMPC_release:
+ Res = ActOnOpenMPReleaseClause(StartLoc, EndLoc);
+ break;
+ case OMPC_relaxed:
+ Res = ActOnOpenMPRelaxedClause(StartLoc, EndLoc);
+ break;
case OMPC_threads:
Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc);
break;
@@ -12271,6 +13352,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_dynamic_allocators:
Res = ActOnOpenMPDynamicAllocatorsClause(StartLoc, EndLoc);
break;
+ case OMPC_destroy:
+ Res = ActOnOpenMPDestroyClause(StartLoc, EndLoc);
+ break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@@ -12295,6 +13379,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_threadprivate:
case OMPC_allocate:
case OMPC_flush:
+ case OMPC_depobj:
case OMPC_depend:
case OMPC_device:
case OMPC_map:
@@ -12311,11 +13396,19 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_to:
case OMPC_from:
case OMPC_use_device_ptr:
+ case OMPC_use_device_addr:
case OMPC_is_device_ptr:
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
case OMPC_nontemporal:
+ case OMPC_order:
+ case OMPC_detach:
+ case OMPC_inclusive:
+ case OMPC_exclusive:
+ case OMPC_uses_allocators:
+ case OMPC_affinity:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12349,7 +13442,7 @@ OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc,
OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
- return new (Context) OMPUpdateClause(StartLoc, EndLoc);
+ return OMPUpdateClause::Create(Context, StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc,
@@ -12362,6 +13455,26 @@ OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc,
return new (Context) OMPSeqCstClause(StartLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPAcqRelClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPAcqRelClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPAcquireClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPAcquireClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPReleaseClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPReleaseClause(StartLoc, EndLoc);
+}
+
+OMPClause *Sema::ActOnOpenMPRelaxedClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPRelaxedClause(StartLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPThreadsClause(StartLoc, EndLoc);
@@ -12397,14 +13510,19 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc,
return new (Context) OMPDynamicAllocatorsClause(StartLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPDestroyClause(SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ return new (Context) OMPDestroyClause(StartLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPVarListClause(
- OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
+ OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *DepModOrTailExpr,
const OMPVarListLocTy &Locs, SourceLocation ColonLoc,
CXXScopeSpec &ReductionOrMapperIdScopeSpec,
DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier,
ArrayRef<OpenMPMapModifierKind> MapTypeModifiers,
ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit,
- SourceLocation DepLinMapLastLoc) {
+ SourceLocation ExtraModifierLoc) {
SourceLocation StartLoc = Locs.StartLoc;
SourceLocation LParenLoc = Locs.LParenLoc;
SourceLocation EndLoc = Locs.EndLoc;
@@ -12421,15 +13539,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
"Unexpected lastprivate modifier.");
Res = ActOnOpenMPLastprivateClause(
VarList, static_cast<OpenMPLastprivateModifier>(ExtraModifier),
- DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
+ ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_shared:
Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_reduction:
- Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
- EndLoc, ReductionOrMapperIdScopeSpec,
- ReductionOrMapperId);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_REDUCTION_unknown &&
+ "Unexpected lastprivate modifier.");
+ Res = ActOnOpenMPReductionClause(
+ VarList, static_cast<OpenMPReductionClauseModifier>(ExtraModifier),
+ StartLoc, LParenLoc, ExtraModifierLoc, ColonLoc, EndLoc,
+ ReductionOrMapperIdScopeSpec, ReductionOrMapperId);
break;
case OMPC_task_reduction:
Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc,
@@ -12445,13 +13566,13 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown &&
"Unexpected linear modifier.");
Res = ActOnOpenMPLinearClause(
- VarList, TailExpr, StartLoc, LParenLoc,
- static_cast<OpenMPLinearClauseKind>(ExtraModifier), DepLinMapLastLoc,
+ VarList, DepModOrTailExpr, StartLoc, LParenLoc,
+ static_cast<OpenMPLinearClauseKind>(ExtraModifier), ExtraModifierLoc,
ColonLoc, EndLoc);
break;
case OMPC_aligned:
- Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc,
- ColonLoc, EndLoc);
+ Res = ActOnOpenMPAlignedClause(VarList, DepModOrTailExpr, StartLoc,
+ LParenLoc, ColonLoc, EndLoc);
break;
case OMPC_copyin:
Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc);
@@ -12466,8 +13587,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown &&
"Unexpected depend modifier.");
Res = ActOnOpenMPDependClause(
- static_cast<OpenMPDependClauseKind>(ExtraModifier), DepLinMapLastLoc,
- ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
+ DepModOrTailExpr, static_cast<OpenMPDependClauseKind>(ExtraModifier),
+ ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown &&
@@ -12475,7 +13596,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
Res = ActOnOpenMPMapClause(
MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec,
ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier),
- IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs);
+ IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs);
break;
case OMPC_to:
Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec,
@@ -12488,17 +13609,31 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_use_device_ptr:
Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs);
break;
+ case OMPC_use_device_addr:
+ Res = ActOnOpenMPUseDeviceAddrClause(VarList, Locs);
+ break;
case OMPC_is_device_ptr:
Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs);
break;
case OMPC_allocate:
- Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc,
- ColonLoc, EndLoc);
+ Res = ActOnOpenMPAllocateClause(DepModOrTailExpr, VarList, StartLoc,
+ LParenLoc, ColonLoc, EndLoc);
break;
case OMPC_nontemporal:
Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
+ case OMPC_inclusive:
+ Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_exclusive:
+ Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_affinity:
+ Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc,
+ DepModOrTailExpr, VarList);
+ break;
case OMPC_if:
+ case OMPC_depobj:
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
@@ -12518,6 +13653,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_update:
case OMPC_capture:
case OMPC_seq_cst:
+ case OMPC_acq_rel:
+ case OMPC_acquire:
+ case OMPC_release:
+ case OMPC_relaxed:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
@@ -12539,6 +13678,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_atomic_default_mem_order:
case OMPC_device_type:
case OMPC_match:
+ case OMPC_order:
+ case OMPC_destroy:
+ case OMPC_detach:
+ case OMPC_uses_allocators:
+ default:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12985,7 +14129,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
ExprCaptures.push_back(Ref->getDecl());
}
}
- DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
+ if (!IsImplicitClause)
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
Vars.push_back((VD || CurContext->isDependentContext())
? RefExpr->IgnoreParens()
: Ref);
@@ -13518,6 +14663,12 @@ struct ReductionData {
SmallVector<Expr *, 8> RHSs;
/// Reduction operation expression.
SmallVector<Expr *, 8> ReductionOps;
+ /// inscan copy operation expressions.
+ SmallVector<Expr *, 8> InscanCopyOps;
+ /// inscan copy temp array expressions for prefix sums.
+ SmallVector<Expr *, 8> InscanCopyArrayTemps;
+ /// inscan copy temp array element expressions for prefix sums.
+ SmallVector<Expr *, 8> InscanCopyArrayElems;
/// Taskgroup descriptors for the corresponding reduction items in
/// in_reduction clauses.
SmallVector<Expr *, 8> TaskgroupDescriptors;
@@ -13525,14 +14676,21 @@ struct ReductionData {
SmallVector<Decl *, 4> ExprCaptures;
/// List of postupdate expressions.
SmallVector<Expr *, 4> ExprPostUpdates;
+ /// Reduction modifier.
+ unsigned RedModifier = 0;
ReductionData() = delete;
/// Reserves required memory for the reduction data.
- ReductionData(unsigned Size) {
+ ReductionData(unsigned Size, unsigned Modifier = 0) : RedModifier(Modifier) {
Vars.reserve(Size);
Privates.reserve(Size);
LHSs.reserve(Size);
RHSs.reserve(Size);
ReductionOps.reserve(Size);
+ if (RedModifier == OMPC_REDUCTION_inscan) {
+ InscanCopyOps.reserve(Size);
+ InscanCopyArrayTemps.reserve(Size);
+ InscanCopyArrayElems.reserve(Size);
+ }
TaskgroupDescriptors.reserve(Size);
ExprCaptures.reserve(Size);
ExprPostUpdates.reserve(Size);
@@ -13546,16 +14704,31 @@ struct ReductionData {
RHSs.emplace_back(nullptr);
ReductionOps.emplace_back(ReductionOp);
TaskgroupDescriptors.emplace_back(nullptr);
+ if (RedModifier == OMPC_REDUCTION_inscan) {
+ InscanCopyOps.push_back(nullptr);
+ InscanCopyArrayTemps.push_back(nullptr);
+ InscanCopyArrayElems.push_back(nullptr);
+ }
}
/// Stores reduction data.
void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp,
- Expr *TaskgroupDescriptor) {
+ Expr *TaskgroupDescriptor, Expr *CopyOp, Expr *CopyArrayTemp,
+ Expr *CopyArrayElem) {
Vars.emplace_back(Item);
Privates.emplace_back(Private);
LHSs.emplace_back(LHS);
RHSs.emplace_back(RHS);
ReductionOps.emplace_back(ReductionOp);
TaskgroupDescriptors.emplace_back(TaskgroupDescriptor);
+ if (RedModifier == OMPC_REDUCTION_inscan) {
+ InscanCopyOps.push_back(CopyOp);
+ InscanCopyArrayTemps.push_back(CopyArrayTemp);
+ InscanCopyArrayElems.push_back(CopyArrayElem);
+ } else {
+ assert(CopyOp == nullptr && CopyArrayTemp == nullptr &&
+ CopyArrayElem == nullptr &&
+ "Copy operation must be used for inscan reductions only.");
+ }
}
};
} // namespace
@@ -13567,7 +14740,7 @@ static bool checkOMPArraySectionConstantForReduction(
if (Length == nullptr) {
// For array sections of the form [1:] or [:], we would need to analyze
// the lower bound...
- if (OASE->getColonLoc().isValid())
+ if (OASE->getColonLocFirst().isValid())
return false;
// This is an array subscript which has implicit length 1!
@@ -13593,7 +14766,7 @@ static bool checkOMPArraySectionConstantForReduction(
if (Length == nullptr) {
// For array sections of the form [1:] or [:], we would need to analyze
// the lower bound...
- if (OASE->getColonLoc().isValid())
+ if (OASE->getColonLocFirst().isValid())
return false;
// This is an array subscript which has implicit length 1!
@@ -13948,11 +15121,11 @@ static bool actOnOMPReductionKindClause(
if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective())) {
S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
S.Diag(ELoc, diag::note_vla_unsupported);
+ continue;
} else {
S.targetDiag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE;
S.targetDiag(ELoc, diag::note_vla_unsupported);
}
- continue;
}
// For arrays/array sections only:
// Create pseudo array type for private copy. The size for this array will
@@ -14007,9 +15180,9 @@ static bool actOnOMPReductionKindClause(
if (auto *ComplexTy = OrigType->getAs<ComplexType>())
Type = ComplexTy->getElementType();
if (Type->isRealFloatingType()) {
- llvm::APFloat InitValue =
- llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
- /*isIEEE=*/true);
+ llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue(
+ Context.getFloatTypeSemantics(Type),
+ Context.getTypeSize(Type));
Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
Type, ELoc);
} else if (Type->isScalarType()) {
@@ -14157,6 +15330,53 @@ static bool actOnOMPReductionKindClause(
continue;
}
+ // Add copy operations for inscan reductions.
+ // LHS = RHS;
+ ExprResult CopyOpRes, TempArrayRes, TempArrayElem;
+ if (ClauseKind == OMPC_reduction &&
+ RD.RedModifier == OMPC_REDUCTION_inscan) {
+ ExprResult RHS = S.DefaultLvalueConversion(RHSDRE);
+ CopyOpRes = S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, LHSDRE,
+ RHS.get());
+ if (!CopyOpRes.isUsable())
+ continue;
+ CopyOpRes =
+ S.ActOnFinishFullExpr(CopyOpRes.get(), /*DiscardedValue=*/true);
+ if (!CopyOpRes.isUsable())
+ continue;
+ // For simd directive and simd-based directives in simd mode no need to
+ // construct temp array, need just a single temp element.
+ if (Stack->getCurrentDirective() == OMPD_simd ||
+ (S.getLangOpts().OpenMPSimd &&
+ isOpenMPSimdDirective(Stack->getCurrentDirective()))) {
+ VarDecl *TempArrayVD =
+ buildVarDecl(S, ELoc, PrivateTy, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ // Add a constructor to the temp decl.
+ S.ActOnUninitializedDecl(TempArrayVD);
+ TempArrayRes = buildDeclRefExpr(S, TempArrayVD, PrivateTy, ELoc);
+ } else {
+ // Build temp array for prefix sum.
+ auto *Dim = new (S.Context)
+ OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue);
+ QualType ArrayTy =
+ S.Context.getVariableArrayType(PrivateTy, Dim, ArrayType::Normal,
+ /*IndexTypeQuals=*/0, {ELoc, ELoc});
+ VarDecl *TempArrayVD =
+ buildVarDecl(S, ELoc, ArrayTy, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ // Add a constructor to the temp decl.
+ S.ActOnUninitializedDecl(TempArrayVD);
+ TempArrayRes = buildDeclRefExpr(S, TempArrayVD, ArrayTy, ELoc);
+ TempArrayElem =
+ S.DefaultFunctionArrayLvalueConversion(TempArrayRes.get());
+ auto *Idx = new (S.Context)
+ OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue);
+ TempArrayElem = S.CreateBuiltinArraySubscriptExpr(TempArrayElem.get(),
+ ELoc, Idx, ELoc);
+ }
+ }
+
// OpenMP [2.15.4.6, Restrictions, p.2]
// A list item that appears in an in_reduction clause of a task construct
// must appear in a task_reduction clause of a construct associated with a
@@ -14167,8 +15387,8 @@ static bool actOnOMPReductionKindClause(
if (ClauseKind == OMPC_in_reduction) {
SourceRange ParentSR;
BinaryOperatorKind ParentBOK;
- const Expr *ParentReductionOp;
- Expr *ParentBOKTD, *ParentReductionOpTD;
+ const Expr *ParentReductionOp = nullptr;
+ Expr *ParentBOKTD = nullptr, *ParentReductionOpTD = nullptr;
DSAStackTy::DSAVarData ParentBOKDSA =
Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK,
ParentBOKTD);
@@ -14177,13 +15397,9 @@ static bool actOnOMPReductionKindClause(
D, ParentSR, ParentReductionOp, ParentReductionOpTD);
bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown;
bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown;
- if (!IsParentBOK && !IsParentReductionOp) {
- S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction);
- continue;
- }
if ((DeclareReductionRef.isUnset() && IsParentReductionOp) ||
- (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK ||
- IsParentReductionOp) {
+ (DeclareReductionRef.isUsable() && IsParentBOK) ||
+ (IsParentBOK && BOK != ParentBOK) || IsParentReductionOp) {
bool EmitError = true;
if (IsParentReductionOp && DeclareReductionRef.isUsable()) {
llvm::FoldingSetNodeID RedId, ParentRedId;
@@ -14206,7 +15422,6 @@ static bool actOnOMPReductionKindClause(
}
}
TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD;
- assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined.");
}
DeclRefExpr *Ref = nullptr;
@@ -14245,8 +15460,17 @@ static bool actOnOMPReductionKindClause(
}
// All reduction items are still marked as reduction (to do not increase
// code base size).
- Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
- if (CurrDir == OMPD_taskgroup) {
+ unsigned Modifier = RD.RedModifier;
+ // Consider task_reductions as reductions with task modifier. Required for
+ // correct analysis of in_reduction clauses.
+ if (CurrDir == OMPD_taskgroup && ClauseKind == OMPC_task_reduction)
+ Modifier = OMPC_REDUCTION_task;
+ Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref, Modifier);
+ if (Modifier == OMPC_REDUCTION_task &&
+ (CurrDir == OMPD_taskgroup ||
+ ((isOpenMPParallelDirective(CurrDir) ||
+ isOpenMPWorksharingDirective(CurrDir)) &&
+ !isOpenMPSimdDirective(CurrDir)))) {
if (DeclareReductionRef.isUsable())
Stack->addTaskgroupReductionData(D, ReductionIdRange,
DeclareReductionRef.get());
@@ -14254,17 +15478,41 @@ static bool actOnOMPReductionKindClause(
Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK);
}
RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(),
- TaskgroupDescriptor);
+ TaskgroupDescriptor, CopyOpRes.get(), TempArrayRes.get(),
+ TempArrayElem.get());
}
return RD.Vars.empty();
}
OMPClause *Sema::ActOnOpenMPReductionClause(
- ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation ColonLoc, SourceLocation EndLoc,
+ ArrayRef<Expr *> VarList, OpenMPReductionClauseModifier Modifier,
+ SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
ArrayRef<Expr *> UnresolvedReductions) {
- ReductionData RD(VarList.size());
+ if (ModifierLoc.isValid() && Modifier == OMPC_REDUCTION_unknown) {
+ Diag(LParenLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_reduction, /*First=*/0,
+ /*Last=*/OMPC_REDUCTION_unknown)
+ << getOpenMPClauseName(OMPC_reduction);
+ return nullptr;
+ }
+ // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions
+ // A reduction clause with the inscan reduction-modifier may only appear on a
+ // worksharing-loop construct, a worksharing-loop SIMD construct, a simd
+ // construct, a parallel worksharing-loop construct or a parallel
+ // worksharing-loop SIMD construct.
+ if (Modifier == OMPC_REDUCTION_inscan &&
+ (DSAStack->getCurrentDirective() != OMPD_for &&
+ DSAStack->getCurrentDirective() != OMPD_for_simd &&
+ DSAStack->getCurrentDirective() != OMPD_simd &&
+ DSAStack->getCurrentDirective() != OMPD_parallel_for &&
+ DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) {
+ Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction);
+ return nullptr;
+ }
+
+ ReductionData RD(VarList.size(), Modifier);
if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList,
StartLoc, LParenLoc, ColonLoc, EndLoc,
ReductionIdScopeSpec, ReductionId,
@@ -14272,9 +15520,10 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
return nullptr;
return OMPReductionClause::Create(
- Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars,
- ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
- RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps,
+ Context, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, Modifier,
+ RD.Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId,
+ RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.InscanCopyOps,
+ RD.InscanCopyArrayTemps, RD.InscanCopyArrayElems,
buildPreInits(Context, RD.ExprCaptures),
buildPostUpdate(*this, RD.ExprPostUpdates));
}
@@ -14330,8 +15579,8 @@ bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
}
bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
- OpenMPLinearClauseKind LinKind,
- QualType Type) {
+ OpenMPLinearClauseKind LinKind, QualType Type,
+ bool IsDeclareSimd) {
const auto *VD = dyn_cast_or_null<VarDecl>(D);
// A variable must not have an incomplete type or a reference type.
if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type))
@@ -14347,8 +15596,10 @@ bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc,
// OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions]
// A variable that is privatized must not have a const-qualified type
// unless it is of class type with a mutable member. This restriction does
- // not apply to the firstprivate clause.
- if (rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc))
+ // not apply to the firstprivate clause, nor to the linear clause on
+ // declarative directives (like declare simd).
+ if (!IsDeclareSimd &&
+ rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc))
return true;
// A list item must be of integral or pointer type.
@@ -14900,8 +16151,53 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList,
return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList);
}
+/// Tries to find omp_depend_t. type.
+static bool findOMPDependT(Sema &S, SourceLocation Loc, DSAStackTy *Stack,
+ bool Diagnose = true) {
+ QualType OMPDependT = Stack->getOMPDependT();
+ if (!OMPDependT.isNull())
+ return true;
+ IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_depend_t");
+ ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope());
+ if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
+ if (Diagnose)
+ S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_depend_t";
+ return false;
+ }
+ Stack->setOMPDependT(PT.get());
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (!Depobj)
+ return nullptr;
+
+ bool OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack);
+
+ // OpenMP 5.0, 2.17.10.1 depobj Construct
+ // depobj is an lvalue expression of type omp_depend_t.
+ if (!Depobj->isTypeDependent() && !Depobj->isValueDependent() &&
+ !Depobj->isInstantiationDependent() &&
+ !Depobj->containsUnexpandedParameterPack() &&
+ (OMPDependTFound &&
+ !Context.typesAreCompatible(DSAStack->getOMPDependT(), Depobj->getType(),
+ /*CompareUnqualified=*/true))) {
+ Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue)
+ << 0 << Depobj->getType() << Depobj->getSourceRange();
+ }
+
+ if (!Depobj->isLValue()) {
+ Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue)
+ << 1 << Depobj->getSourceRange();
+ }
+
+ return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj);
+}
+
OMPClause *
-Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
+Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind,
SourceLocation DepLoc, SourceLocation ColonLoc,
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
@@ -14911,16 +16207,38 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
<< "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend);
return nullptr;
}
- if (DSAStack->getCurrentDirective() != OMPD_ordered &&
+ if ((DSAStack->getCurrentDirective() != OMPD_ordered ||
+ DSAStack->getCurrentDirective() == OMPD_depobj) &&
(DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source ||
- DepKind == OMPC_DEPEND_sink)) {
- unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink};
+ DepKind == OMPC_DEPEND_sink ||
+ ((LangOpts.OpenMP < 50 ||
+ DSAStack->getCurrentDirective() == OMPD_depobj) &&
+ DepKind == OMPC_DEPEND_depobj))) {
+ SmallVector<unsigned, 3> Except;
+ Except.push_back(OMPC_DEPEND_source);
+ Except.push_back(OMPC_DEPEND_sink);
+ if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj)
+ Except.push_back(OMPC_DEPEND_depobj);
+ std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier)
+ ? "depend modifier(iterator) or "
+ : "";
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
- << getListOfPossibleValues(OMPC_depend, /*First=*/0,
- /*Last=*/OMPC_DEPEND_unknown, Except)
+ << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0,
+ /*Last=*/OMPC_DEPEND_unknown,
+ Except)
<< getOpenMPClauseName(OMPC_depend);
return nullptr;
}
+ if (DepModifier &&
+ (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) {
+ Diag(DepModifier->getExprLoc(),
+ diag::err_omp_depend_sink_source_with_modifier);
+ return nullptr;
+ }
+ if (DepModifier &&
+ !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator))
+ Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator);
+
SmallVector<Expr *, 8> Vars;
DSAStackTy::OperatorOffsetTy OpsOffs;
llvm::APSInt DepCounter(/*BitWidth=*/32);
@@ -15021,42 +16339,97 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
}
OpsOffs.emplace_back(RHS, OOK);
} else {
- // OpenMP 5.0 [2.17.11, Restrictions]
- // List items used in depend clauses cannot be zero-length array sections.
- const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
- if (OASE) {
- const Expr *Length = OASE->getLength();
- Expr::EvalResult Result;
- if (Length && !Length->isValueDependent() &&
- Length->EvaluateAsInt(Result, Context) &&
- Result.Val.getInt().isNullValue()) {
- Diag(ELoc,
- diag::err_omp_depend_zero_length_array_section_not_allowed)
- << SimpleExpr->getSourceRange();
+ bool OMPDependTFound = LangOpts.OpenMP >= 50;
+ if (OMPDependTFound)
+ OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack,
+ DepKind == OMPC_DEPEND_depobj);
+ if (DepKind == OMPC_DEPEND_depobj) {
+ // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
+ // List items used in depend clauses with the depobj dependence type
+ // must be expressions of the omp_depend_t type.
+ if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
+ !RefExpr->isInstantiationDependent() &&
+ !RefExpr->containsUnexpandedParameterPack() &&
+ (OMPDependTFound &&
+ !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(),
+ RefExpr->getType()))) {
+ Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
+ << 0 << RefExpr->getType() << RefExpr->getSourceRange();
continue;
}
- }
+ if (!RefExpr->isLValue()) {
+ Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue)
+ << 1 << RefExpr->getType() << RefExpr->getSourceRange();
+ continue;
+ }
+ } else {
+ // OpenMP 5.0 [2.17.11, Restrictions]
+ // List items used in depend clauses cannot be zero-length array
+ // sections.
+ QualType ExprTy = RefExpr->getType().getNonReferenceType();
+ const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
+ if (OASE) {
+ QualType BaseType =
+ OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
+ if (const auto *ATy = BaseType->getAsArrayTypeUnsafe())
+ ExprTy = ATy->getElementType();
+ else
+ ExprTy = BaseType->getPointeeType();
+ ExprTy = ExprTy.getNonReferenceType();
+ const Expr *Length = OASE->getLength();
+ Expr::EvalResult Result;
+ if (Length && !Length->isValueDependent() &&
+ Length->EvaluateAsInt(Result, Context) &&
+ Result.Val.getInt().isNullValue()) {
+ Diag(ELoc,
+ diag::err_omp_depend_zero_length_array_section_not_allowed)
+ << SimpleExpr->getSourceRange();
+ continue;
+ }
+ }
- auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
- if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
- (ASE &&
- !ASE->getBase()->getType().getNonReferenceType()->isPointerType() &&
- !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
- Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
- << RefExpr->getSourceRange();
- continue;
- }
+ // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++
+ // List items used in depend clauses with the in, out, inout or
+ // mutexinoutset dependence types cannot be expressions of the
+ // omp_depend_t type.
+ if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() &&
+ !RefExpr->isInstantiationDependent() &&
+ !RefExpr->containsUnexpandedParameterPack() &&
+ (OMPDependTFound &&
+ DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr())) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0) << 1
+ << RefExpr->getSourceRange();
+ continue;
+ }
- ExprResult Res;
- {
- Sema::TentativeAnalysisScope Trap(*this);
- Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
- RefExpr->IgnoreParenImpCasts());
- }
- if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) {
- Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
- << RefExpr->getSourceRange();
- continue;
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
+ if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
+ (ASE && !ASE->getBase()->isTypeDependent() &&
+ !ASE->getBase()
+ ->getType()
+ .getNonReferenceType()
+ ->isPointerType() &&
+ !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
+ continue;
+ }
+
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf,
+ RefExpr->IgnoreParenImpCasts());
+ }
+ if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
+ !isa<OMPArrayShapingExpr>(SimpleExpr)) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0)
+ << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange();
+ continue;
+ }
}
}
Vars.push_back(RefExpr->IgnoreParenImpCasts());
@@ -15074,24 +16447,40 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
return nullptr;
auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- DepKind, DepLoc, ColonLoc, Vars,
- TotalDepCount.getZExtValue());
+ DepModifier, DepKind, DepLoc, ColonLoc,
+ Vars, TotalDepCount.getZExtValue());
if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) &&
DSAStack->isParentOrderedRegion())
DSAStack->addDoacrossDependClause(C, OpsOffs);
return C;
}
-OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
+OMPClause *Sema::ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier,
+ Expr *Device, SourceLocation StartLoc,
SourceLocation LParenLoc,
+ SourceLocation ModifierLoc,
SourceLocation EndLoc) {
+ assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 50) &&
+ "Unexpected device modifier in OpenMP < 50.");
+
+ bool ErrorFound = false;
+ if (ModifierLoc.isValid() && Modifier == OMPC_DEVICE_unknown) {
+ std::string Values =
+ getListOfPossibleValues(OMPC_device, /*First=*/0, OMPC_DEVICE_unknown);
+ Diag(ModifierLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_device);
+ ErrorFound = true;
+ }
+
Expr *ValExpr = Device;
Stmt *HelperValStmt = nullptr;
// OpenMP [2.9.1, Restrictions]
// The device expression must evaluate to a non-negative integer value.
- if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_device,
- /*StrictlyPositive=*/false))
+ ErrorFound = !isNonNegativeIntegerValue(ValExpr, *this, OMPC_device,
+ /*StrictlyPositive=*/false) ||
+ ErrorFound;
+ if (ErrorFound)
return nullptr;
OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective();
@@ -15104,8 +16493,9 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
HelperValStmt = buildPreInits(Context, Captures);
}
- return new (Context) OMPDeviceClause(ValExpr, HelperValStmt, CaptureRegion,
- StartLoc, LParenLoc, EndLoc);
+ return new (Context)
+ OMPDeviceClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc,
+ LParenLoc, ModifierLoc, EndLoc);
}
static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
@@ -15133,7 +16523,8 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef,
// If this is an array subscript, it refers to the whole size if the size of
// the dimension is constant and equals 1. Also, an array section assumes the
// format of an array subscript if no colon is used.
- if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) {
+ if (isa<ArraySubscriptExpr>(E) ||
+ (OASE && OASE->getColonLocFirst().isInvalid())) {
if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
return ATy->getSize().getSExtValue() != 1;
// Size can't be evaluated statically.
@@ -15189,7 +16580,8 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
// An array subscript always refer to a single element. Also, an array section
// assumes the format of an array subscript if no colon is used.
- if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid()))
+ if (isa<ArraySubscriptExpr>(E) ||
+ (OASE && OASE->getColonLocFirst().isInvalid()))
return false;
assert(OASE && "Expecting array section if not an array subscript.");
@@ -15214,256 +16606,338 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
return ConstLength.getSExtValue() != 1;
}
-// Return the expression of the base of the mappable expression or null if it
-// cannot be determined and do all the necessary checks to see if the expression
-// is valid as a standalone mappable expression. In the process, record all the
-// components of the expression.
-static const Expr *checkMapClauseExpressionBase(
- Sema &SemaRef, Expr *E,
- OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
- OpenMPClauseKind CKind, bool NoDiagnose) {
- SourceLocation ELoc = E->getExprLoc();
- SourceRange ERange = E->getSourceRange();
-
- // The base of elements of list in a map clause have to be either:
- // - a reference to variable or field.
- // - a member expression.
- // - an array expression.
- //
- // E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the
- // reference to 'r'.
- //
- // If we have:
- //
- // struct SS {
- // Bla S;
- // foo() {
- // #pragma omp target map (S.Arr[:12]);
- // }
- // }
- //
- // We want to retrieve the member expression 'this->S';
+// The base of elements of list in a map clause have to be either:
+// - a reference to variable or field.
+// - a member expression.
+// - an array expression.
+//
+// E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the
+// reference to 'r'.
+//
+// If we have:
+//
+// struct SS {
+// Bla S;
+// foo() {
+// #pragma omp target map (S.Arr[:12]);
+// }
+// }
+//
+// We want to retrieve the member expression 'this->S';
+// OpenMP 5.0 [2.19.7.1, map Clause, Restrictions, p.2]
+// If a list item is an array section, it must specify contiguous storage.
+//
+// For this restriction it is sufficient that we make sure only references
+// to variables or fields and array expressions, and that no array sections
+// exist except in the rightmost expression (unless they cover the whole
+// dimension of the array). E.g. these would be invalid:
+//
+// r.ArrS[3:5].Arr[6:7]
+//
+// r.ArrS[3:5].x
+//
+// but these would be valid:
+// r.ArrS[3].Arr[6:7]
+//
+// r.ArrS[3].x
+namespace {
+class MapBaseChecker final : public StmtVisitor<MapBaseChecker, bool> {
+ Sema &SemaRef;
+ OpenMPClauseKind CKind = OMPC_unknown;
+ OMPClauseMappableExprCommon::MappableExprComponentList &Components;
+ bool NoDiagnose = false;
const Expr *RelevantExpr = nullptr;
-
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2]
- // If a list item is an array section, it must specify contiguous storage.
- //
- // For this restriction it is sufficient that we make sure only references
- // to variables or fields and array expressions, and that no array sections
- // exist except in the rightmost expression (unless they cover the whole
- // dimension of the array). E.g. these would be invalid:
- //
- // r.ArrS[3:5].Arr[6:7]
- //
- // r.ArrS[3:5].x
- //
- // but these would be valid:
- // r.ArrS[3].Arr[6:7]
- //
- // r.ArrS[3].x
-
bool AllowUnitySizeArraySection = true;
bool AllowWholeSizeArraySection = true;
+ SourceLocation ELoc;
+ SourceRange ERange;
- while (!RelevantExpr) {
- E = E->IgnoreParenImpCasts();
+ void emitErrorMsg() {
+ // If nothing else worked, this is not a valid map clause expression.
+ if (SemaRef.getLangOpts().OpenMP < 50) {
+ SemaRef.Diag(ELoc,
+ diag::err_omp_expected_named_var_member_or_array_expression)
+ << ERange;
+ } else {
+ SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses)
+ << getOpenMPClauseName(CKind) << ERange;
+ }
+ }
- if (auto *CurE = dyn_cast<DeclRefExpr>(E)) {
- if (!isa<VarDecl>(CurE->getDecl()))
- return nullptr;
+public:
+ bool VisitDeclRefExpr(DeclRefExpr *DRE) {
+ if (!isa<VarDecl>(DRE->getDecl())) {
+ emitErrorMsg();
+ return false;
+ }
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = DRE;
+ // Record the component.
+ Components.emplace_back(DRE, DRE->getDecl());
+ return true;
+ }
- RelevantExpr = CurE;
+ bool VisitMemberExpr(MemberExpr *ME) {
+ Expr *E = ME;
+ Expr *BaseE = ME->getBase()->IgnoreParenCasts();
- // If we got a reference to a declaration, we should not expect any array
- // section before that.
- AllowUnitySizeArraySection = false;
- AllowWholeSizeArraySection = false;
+ if (isa<CXXThisExpr>(BaseE)) {
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ // We found a base expression: this->Val.
+ RelevantExpr = ME;
+ } else {
+ E = BaseE;
+ }
- // Record the component.
- CurComponents.emplace_back(CurE, CurE->getDecl());
- } else if (auto *CurE = dyn_cast<MemberExpr>(E)) {
- Expr *BaseE = CurE->getBase()->IgnoreParenImpCasts();
+ if (!isa<FieldDecl>(ME->getMemberDecl())) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
+ << ME->getSourceRange();
+ return false;
+ }
+ if (RelevantExpr)
+ return false;
+ return Visit(E);
+ }
- if (isa<CXXThisExpr>(BaseE))
- // We found a base expression: this->Val.
- RelevantExpr = CurE;
- else
- E = BaseE;
+ auto *FD = cast<FieldDecl>(ME->getMemberDecl());
- if (!isa<FieldDecl>(CurE->getMemberDecl())) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
- << CurE->getSourceRange();
- return nullptr;
- }
- if (RelevantExpr)
- return nullptr;
- continue;
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
+ // A bit-field cannot appear in a map clause.
+ //
+ if (FD->isBitField()) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
+ << ME->getSourceRange() << getOpenMPClauseName(CKind);
+ return false;
}
+ if (RelevantExpr)
+ return false;
+ return Visit(E);
+ }
- auto *FD = cast<FieldDecl>(CurE->getMemberDecl());
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type
+ // will be considered to be T for all purposes of this clause.
+ QualType CurType = BaseE->getType().getNonReferenceType();
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
- // A bit-field cannot appear in a map clause.
- //
- if (FD->isBitField()) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
- << CurE->getSourceRange() << getOpenMPClauseName(CKind);
- return nullptr;
- }
- if (RelevantExpr)
- return nullptr;
- continue;
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
+ // A list item cannot be a variable that is a member of a structure with
+ // a union type.
+ //
+ if (CurType->isUnionType()) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
+ << ME->getSourceRange();
+ return false;
}
+ return RelevantExpr || Visit(E);
+ }
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
- // If the type of a list item is a reference to a type T then the type
- // will be considered to be T for all purposes of this clause.
- QualType CurType = BaseE->getType().getNonReferenceType();
+ // If we got a member expression, we should not expect any array section
+ // before that:
+ //
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
+ // If a list item is an element of a structure, only the rightmost symbol
+ // of the variable reference can be an array section.
+ //
+ AllowUnitySizeArraySection = false;
+ AllowWholeSizeArraySection = false;
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
- // A list item cannot be a variable that is a member of a structure with
- // a union type.
- //
- if (CurType->isUnionType()) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
- << CurE->getSourceRange();
- return nullptr;
- }
- continue;
+ // Record the component.
+ Components.emplace_back(ME, FD);
+ return RelevantExpr || Visit(E);
+ }
+
+ bool VisitArraySubscriptExpr(ArraySubscriptExpr *AE) {
+ Expr *E = AE->getBase()->IgnoreParenImpCasts();
+
+ if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
+ if (!NoDiagnose) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
+ << 0 << AE->getSourceRange();
+ return false;
}
+ return RelevantExpr || Visit(E);
+ }
- // If we got a member expression, we should not expect any array section
- // before that:
- //
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
- // If a list item is an element of a structure, only the rightmost symbol
- // of the variable reference can be an array section.
- //
- AllowUnitySizeArraySection = false;
+ // If we got an array subscript that express the whole dimension we
+ // can have any array expressions before. If it only expressing part of
+ // the dimension, we can only have unitary-size array expressions.
+ if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, AE,
+ E->getType()))
AllowWholeSizeArraySection = false;
- // Record the component.
- CurComponents.emplace_back(CurE, FD);
- } else if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) {
- E = CurE->getBase()->IgnoreParenImpCasts();
-
- if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
- if (!NoDiagnose) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
- << 0 << CurE->getSourceRange();
- return nullptr;
- }
- continue;
+ if (const auto *TE = dyn_cast<CXXThisExpr>(E->IgnoreParenCasts())) {
+ Expr::EvalResult Result;
+ if (!AE->getIdx()->isValueDependent() &&
+ AE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext()) &&
+ !Result.Val.getInt().isNullValue()) {
+ SemaRef.Diag(AE->getIdx()->getExprLoc(),
+ diag::err_omp_invalid_map_this_expr);
+ SemaRef.Diag(AE->getIdx()->getExprLoc(),
+ diag::note_omp_invalid_subscript_on_this_ptr_map);
}
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = TE;
+ }
- // If we got an array subscript that express the whole dimension we
- // can have any array expressions before. If it only expressing part of
- // the dimension, we can only have unitary-size array expressions.
- if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE,
- E->getType()))
- AllowWholeSizeArraySection = false;
+ // Record the component - we don't have any declaration associated.
+ Components.emplace_back(AE, nullptr);
- if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
- Expr::EvalResult Result;
- if (CurE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext())) {
- if (!Result.Val.getInt().isNullValue()) {
- SemaRef.Diag(CurE->getIdx()->getExprLoc(),
- diag::err_omp_invalid_map_this_expr);
- SemaRef.Diag(CurE->getIdx()->getExprLoc(),
- diag::note_omp_invalid_subscript_on_this_ptr_map);
- }
- }
- RelevantExpr = TE;
- }
+ return RelevantExpr || Visit(E);
+ }
- // Record the component - we don't have any declaration associated.
- CurComponents.emplace_back(CurE, nullptr);
- } else if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) {
- assert(!NoDiagnose && "Array sections cannot be implicitly mapped.");
- E = CurE->getBase()->IgnoreParenImpCasts();
+ bool VisitOMPArraySectionExpr(OMPArraySectionExpr *OASE) {
+ assert(!NoDiagnose && "Array sections cannot be implicitly mapped.");
+ Expr *E = OASE->getBase()->IgnoreParenImpCasts();
+ QualType CurType =
+ OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
- QualType CurType =
- OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type
+ // will be considered to be T for all purposes of this clause.
+ if (CurType->isReferenceType())
+ CurType = CurType->getPointeeType();
- // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
- // If the type of a list item is a reference to a type T then the type
- // will be considered to be T for all purposes of this clause.
- if (CurType->isReferenceType())
- CurType = CurType->getPointeeType();
+ bool IsPointer = CurType->isAnyPointerType();
- bool IsPointer = CurType->isAnyPointerType();
+ if (!IsPointer && !CurType->isArrayType()) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
+ << 0 << OASE->getSourceRange();
+ return false;
+ }
- if (!IsPointer && !CurType->isArrayType()) {
- SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
- << 0 << CurE->getSourceRange();
- return nullptr;
- }
+ bool NotWhole =
+ checkArrayExpressionDoesNotReferToWholeSize(SemaRef, OASE, CurType);
+ bool NotUnity =
+ checkArrayExpressionDoesNotReferToUnitySize(SemaRef, OASE, CurType);
- bool NotWhole =
- checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType);
- bool NotUnity =
- checkArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType);
+ if (AllowWholeSizeArraySection) {
+ // Any array section is currently allowed. Allowing a whole size array
+ // section implies allowing a unity array section as well.
+ //
+ // If this array section refers to the whole dimension we can still
+ // accept other array sections before this one, except if the base is a
+ // pointer. Otherwise, only unitary sections are accepted.
+ if (NotWhole || IsPointer)
+ AllowWholeSizeArraySection = false;
+ } else if (AllowUnitySizeArraySection && NotUnity) {
+ // A unity or whole array section is not allowed and that is not
+ // compatible with the properties of the current array section.
+ SemaRef.Diag(
+ ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
+ << OASE->getSourceRange();
+ return false;
+ }
- if (AllowWholeSizeArraySection) {
- // Any array section is currently allowed. Allowing a whole size array
- // section implies allowing a unity array section as well.
- //
- // If this array section refers to the whole dimension we can still
- // accept other array sections before this one, except if the base is a
- // pointer. Otherwise, only unitary sections are accepted.
- if (NotWhole || IsPointer)
- AllowWholeSizeArraySection = false;
- } else if (AllowUnitySizeArraySection && NotUnity) {
- // A unity or whole array section is not allowed and that is not
- // compatible with the properties of the current array section.
- SemaRef.Diag(
- ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
- << CurE->getSourceRange();
- return nullptr;
+ if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
+ Expr::EvalResult ResultR;
+ Expr::EvalResult ResultL;
+ if (!OASE->getLength()->isValueDependent() &&
+ OASE->getLength()->EvaluateAsInt(ResultR, SemaRef.getASTContext()) &&
+ !ResultR.Val.getInt().isOneValue()) {
+ SemaRef.Diag(OASE->getLength()->getExprLoc(),
+ diag::err_omp_invalid_map_this_expr);
+ SemaRef.Diag(OASE->getLength()->getExprLoc(),
+ diag::note_omp_invalid_length_on_this_ptr_mapping);
}
-
- if (const auto *TE = dyn_cast<CXXThisExpr>(E)) {
- Expr::EvalResult ResultR;
- Expr::EvalResult ResultL;
- if (CurE->getLength()->EvaluateAsInt(ResultR,
- SemaRef.getASTContext())) {
- if (!ResultR.Val.getInt().isOneValue()) {
- SemaRef.Diag(CurE->getLength()->getExprLoc(),
- diag::err_omp_invalid_map_this_expr);
- SemaRef.Diag(CurE->getLength()->getExprLoc(),
- diag::note_omp_invalid_length_on_this_ptr_mapping);
- }
- }
- if (CurE->getLowerBound() && CurE->getLowerBound()->EvaluateAsInt(
- ResultL, SemaRef.getASTContext())) {
- if (!ResultL.Val.getInt().isNullValue()) {
- SemaRef.Diag(CurE->getLowerBound()->getExprLoc(),
- diag::err_omp_invalid_map_this_expr);
- SemaRef.Diag(CurE->getLowerBound()->getExprLoc(),
- diag::note_omp_invalid_lower_bound_on_this_ptr_mapping);
- }
- }
- RelevantExpr = TE;
+ if (OASE->getLowerBound() && !OASE->getLowerBound()->isValueDependent() &&
+ OASE->getLowerBound()->EvaluateAsInt(ResultL,
+ SemaRef.getASTContext()) &&
+ !ResultL.Val.getInt().isNullValue()) {
+ SemaRef.Diag(OASE->getLowerBound()->getExprLoc(),
+ diag::err_omp_invalid_map_this_expr);
+ SemaRef.Diag(OASE->getLowerBound()->getExprLoc(),
+ diag::note_omp_invalid_lower_bound_on_this_ptr_mapping);
}
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = TE;
+ }
- // Record the component - we don't have any declaration associated.
- CurComponents.emplace_back(CurE, nullptr);
- } else {
- if (!NoDiagnose) {
- // If nothing else worked, this is not a valid map clause expression.
- SemaRef.Diag(
- ELoc, diag::err_omp_expected_named_var_member_or_array_expression)
- << ERange;
- }
- return nullptr;
+ // Record the component - we don't have any declaration associated.
+ Components.emplace_back(OASE, nullptr);
+ return RelevantExpr || Visit(E);
+ }
+ bool VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) {
+ Expr *Base = E->getBase();
+
+ // Record the component - we don't have any declaration associated.
+ Components.emplace_back(E, nullptr);
+
+ return Visit(Base->IgnoreParenImpCasts());
+ }
+
+ bool VisitUnaryOperator(UnaryOperator *UO) {
+ if (SemaRef.getLangOpts().OpenMP < 50 || !UO->isLValue() ||
+ UO->getOpcode() != UO_Deref) {
+ emitErrorMsg();
+ return false;
}
+ if (!RelevantExpr) {
+ // Record the component if haven't found base decl.
+ Components.emplace_back(UO, nullptr);
+ }
+ return RelevantExpr || Visit(UO->getSubExpr()->IgnoreParenImpCasts());
}
+ bool VisitBinaryOperator(BinaryOperator *BO) {
+ if (SemaRef.getLangOpts().OpenMP < 50 || !BO->getType()->isPointerType()) {
+ emitErrorMsg();
+ return false;
+ }
+
+ // Pointer arithmetic is the only thing we expect to happen here so after we
+ // make sure the binary operator is a pointer type, the we only thing need
+ // to to is to visit the subtree that has the same type as root (so that we
+ // know the other subtree is just an offset)
+ Expr *LE = BO->getLHS()->IgnoreParenImpCasts();
+ Expr *RE = BO->getRHS()->IgnoreParenImpCasts();
+ Components.emplace_back(BO, nullptr);
+ assert((LE->getType().getTypePtr() == BO->getType().getTypePtr() ||
+ RE->getType().getTypePtr() == BO->getType().getTypePtr()) &&
+ "Either LHS or RHS have base decl inside");
+ if (BO->getType().getTypePtr() == LE->getType().getTypePtr())
+ return RelevantExpr || Visit(LE);
+ return RelevantExpr || Visit(RE);
+ }
+ bool VisitCXXThisExpr(CXXThisExpr *CTE) {
+ assert(!RelevantExpr && "RelevantExpr is expected to be nullptr");
+ RelevantExpr = CTE;
+ Components.emplace_back(CTE, nullptr);
+ return true;
+ }
+ bool VisitStmt(Stmt *) {
+ emitErrorMsg();
+ return false;
+ }
+ const Expr *getFoundBase() const {
+ return RelevantExpr;
+ }
+ explicit MapBaseChecker(
+ Sema &SemaRef, OpenMPClauseKind CKind,
+ OMPClauseMappableExprCommon::MappableExprComponentList &Components,
+ bool NoDiagnose, SourceLocation &ELoc, SourceRange &ERange)
+ : SemaRef(SemaRef), CKind(CKind), Components(Components),
+ NoDiagnose(NoDiagnose), ELoc(ELoc), ERange(ERange) {}
+};
+} // namespace
- return RelevantExpr;
+/// Return the expression of the base of the mappable expression or null if it
+/// cannot be determined and do all the necessary checks to see if the expression
+/// is valid as a standalone mappable expression. In the process, record all the
+/// components of the expression.
+static const Expr *checkMapClauseExpressionBase(
+ Sema &SemaRef, Expr *E,
+ OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
+ OpenMPClauseKind CKind, bool NoDiagnose) {
+ SourceLocation ELoc = E->getExprLoc();
+ SourceRange ERange = E->getSourceRange();
+ MapBaseChecker Checker(SemaRef, CKind, CurComponents, NoDiagnose, ELoc,
+ ERange);
+ if (Checker.Visit(E->IgnoreParens()))
+ return Checker.getFoundBase();
+ return nullptr;
}
// Return true if expression E associated with value VD has conflicts with other
@@ -15520,9 +16994,11 @@ static bool checkMapConflicts(
// variable in map clauses of the same construct.
if (CurrentRegionOnly &&
(isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) ||
- isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) &&
+ isa<OMPArraySectionExpr>(CI->getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(CI->getAssociatedExpression())) &&
(isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) ||
- isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) {
+ isa<OMPArraySectionExpr>(SI->getAssociatedExpression()) ||
+ isa<OMPArrayShapingExpr>(SI->getAssociatedExpression()))) {
SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(),
diag::err_omp_multiple_array_items_in_map_clause)
<< CI->getAssociatedExpression()->getSourceRange();
@@ -15554,6 +17030,9 @@ static bool checkMapConflicts(
const Expr *E = OASE->getBase()->IgnoreParenImpCasts();
Type =
OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
+ } else if (const auto *OASE = dyn_cast<OMPArrayShapingExpr>(
+ SI->getAssociatedExpression())) {
+ Type = OASE->getBase()->getType()->getPointeeType();
}
if (Type.isNull() || Type->isAnyPointerType() ||
checkArrayExpressionDoesNotReferToWholeSize(
@@ -15916,10 +17395,15 @@ static void checkMappableExpressionList(
Expr *SimpleExpr = RE->IgnoreParenCasts();
- if (!RE->IgnoreParenImpCasts()->isLValue()) {
- SemaRef.Diag(ELoc,
- diag::err_omp_expected_named_var_member_or_array_expression)
- << RE->getSourceRange();
+ if (!RE->isLValue()) {
+ if (SemaRef.getLangOpts().OpenMP < 50) {
+ SemaRef.Diag(
+ ELoc, diag::err_omp_expected_named_var_member_or_array_expression)
+ << RE->getSourceRange();
+ } else {
+ SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses)
+ << getOpenMPClauseName(CKind) << RE->getSourceRange();
+ }
continue;
}
@@ -16011,6 +17495,7 @@ static void checkMappableExpressionList(
QualType Type;
auto *ASE = dyn_cast<ArraySubscriptExpr>(VE->IgnoreParens());
auto *OASE = dyn_cast<OMPArraySectionExpr>(VE->IgnoreParens());
+ auto *OAShE = dyn_cast<OMPArrayShapingExpr>(VE->IgnoreParens());
if (ASE) {
Type = ASE->getType().getNonReferenceType();
} else if (OASE) {
@@ -16021,6 +17506,8 @@ static void checkMappableExpressionList(
else
Type = BaseType->getPointeeType();
Type = Type.getNonReferenceType();
+ } else if (OAShE) {
+ Type = OAShE->getBase()->getType()->getPointeeType();
} else {
Type = VE->getType();
}
@@ -16064,6 +17551,21 @@ static void checkMappableExpressionList(
continue;
}
+ // target, target data
+ // OpenMP 5.0 [2.12.2, Restrictions, p. 163]
+ // OpenMP 5.0 [2.12.5, Restrictions, p. 174]
+ // A map-type in a map clause must be to, from, tofrom or alloc
+ if ((DKind == OMPD_target_data ||
+ isOpenMPTargetExecutionDirective(DKind)) &&
+ !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_from ||
+ MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc)) {
+ SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
+ << (IsMapTypeImplicit ? 1 : 0)
+ << getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
+ << getOpenMPDirectiveName(DKind);
+ continue;
+ }
+
// OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
// A list item cannot appear in both a map clause and a data-sharing
// attribute clause on the same construct
@@ -16124,7 +17626,7 @@ OMPClause *Sema::ActOnOpenMPMapClause(
OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown,
OMPC_MAP_MODIFIER_unknown,
OMPC_MAP_MODIFIER_unknown};
- SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers];
+ SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers];
// Process map-type-modifiers, flag errors for duplicate modifiers.
unsigned Count = 0;
@@ -16134,7 +17636,7 @@ OMPClause *Sema::ActOnOpenMPMapClause(
Diag(MapTypeModifiersLoc[I], diag::err_omp_duplicate_map_type_modifier);
continue;
}
- assert(Count < OMPMapClause::NumberOfModifiers &&
+ assert(Count < NumberOfOMPMapClauseModifiers &&
"Modifiers exceed the allowed number of map type modifiers");
Modifiers[Count] = MapTypeModifiers[I];
ModifiersLoc[Count] = MapTypeModifiersLoc[I];
@@ -16678,6 +18180,69 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc);
}
+/// Tries to find omp_event_handle_t type.
+static bool findOMPEventHandleT(Sema &S, SourceLocation Loc,
+ DSAStackTy *Stack) {
+ QualType OMPEventHandleT = Stack->getOMPEventHandleT();
+ if (!OMPEventHandleT.isNull())
+ return true;
+ IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_event_handle_t");
+ ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope());
+ if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
+ S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_event_handle_t";
+ return false;
+ }
+ Stack->setOMPEventHandleT(PT.get());
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ if (!Evt->isValueDependent() && !Evt->isTypeDependent() &&
+ !Evt->isInstantiationDependent() &&
+ !Evt->containsUnexpandedParameterPack()) {
+ if (!findOMPEventHandleT(*this, Evt->getExprLoc(), DSAStack))
+ return nullptr;
+ // OpenMP 5.0, 2.10.1 task Construct.
+ // event-handle is a variable of the omp_event_handle_t type.
+ auto *Ref = dyn_cast<DeclRefExpr>(Evt->IgnoreParenImpCasts());
+ if (!Ref) {
+ Diag(Evt->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_event_handle_t" << 0 << Evt->getSourceRange();
+ return nullptr;
+ }
+ auto *VD = dyn_cast_or_null<VarDecl>(Ref->getDecl());
+ if (!VD) {
+ Diag(Evt->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_event_handle_t" << 0 << Evt->getSourceRange();
+ return nullptr;
+ }
+ if (!Context.hasSameUnqualifiedType(DSAStack->getOMPEventHandleT(),
+ VD->getType()) ||
+ VD->getType().isConstant(Context)) {
+ Diag(Evt->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_event_handle_t" << 1 << VD->getType()
+ << Evt->getSourceRange();
+ return nullptr;
+ }
+ // OpenMP 5.0, 2.10.1 task Construct
+ // [detach clause]... The event-handle will be considered as if it was
+ // specified on a firstprivate clause.
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, /*FromParent=*/false);
+ if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate &&
+ DVar.RefExpr) {
+ Diag(Evt->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPClauseName(OMPC_firstprivate);
+ reportOriginalDsa(*this, DSAStack, VD, DVar);
+ return nullptr;
+ }
+ }
+
+ return new (Context) OMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc);
+}
+
OMPClause *Sema::ActOnOpenMPDistScheduleClause(
OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
@@ -16758,7 +18323,8 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
}
} else {
bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown);
- bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown);
+ bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown) ||
+ (LangOpts.OpenMP >= 50 && KindLoc.isInvalid());
if (!isDefaultmapKind || !isDefaultmapModifier) {
std::string ModifierValue = "'alloc', 'from', 'to', 'tofrom', "
"'firstprivate', 'none', 'default'";
@@ -16786,7 +18352,14 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause(
return nullptr;
}
}
- DSAStack->setDefaultDMAAttr(M, Kind, StartLoc);
+ if (Kind == OMPC_DEFAULTMAP_unknown) {
+ // Variable category is not specified - mark all categories.
+ DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_aggregate, StartLoc);
+ DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_scalar, StartLoc);
+ DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_pointer, StartLoc);
+ } else {
+ DSAStack->setDefaultDMAAttr(M, Kind, StartLoc);
+ }
return new (Context)
OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
@@ -16955,15 +18528,6 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D,
Diag(FD->getLocation(), diag::note_defined_here) << FD;
return;
}
- // Mark the function as must be emitted for the device.
- Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy =
- OMPDeclareTargetDeclAttr::getDeviceType(FD);
- if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
- *DevTy != OMPDeclareTargetDeclAttr::DT_Host)
- checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false);
- if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() &&
- *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost)
- checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false);
}
if (auto *VD = dyn_cast<ValueDecl>(D)) {
// Problem if any with var declared with incomplete type will be reported
@@ -17109,6 +18673,58 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
MVLI.VarBaseDeclarations, MVLI.VarComponents);
}
+OMPClause *Sema::ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList,
+ const OMPVarListLocTy &Locs) {
+ MappableVarListInfo MVLI(VarList);
+
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP use_device_addr clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second) {
+ // It will be analyzed later.
+ MVLI.ProcessedVarList.push_back(RefExpr);
+ }
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+ auto *VD = dyn_cast<VarDecl>(D);
+
+ // If required, build a capture to implement the privatization initialized
+ // with the current list item value.
+ DeclRefExpr *Ref = nullptr;
+ if (!VD)
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
+ MVLI.ProcessedVarList.push_back(VD ? RefExpr->IgnoreParens() : Ref);
+
+ // We need to add a data sharing attribute for this variable to make sure it
+ // is correctly captured. A variable that shows up in a use_device_addr has
+ // similar properties of a first private variable.
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
+
+ // Create a mappable component for the list item. List items in this clause
+ // only need a component.
+ MVLI.VarBaseDeclarations.push_back(D);
+ MVLI.VarComponents.emplace_back();
+ Expr *Component = SimpleRefExpr;
+ if (VD && (isa<OMPArraySectionExpr>(RefExpr->IgnoreParenImpCasts()) ||
+ isa<ArraySubscriptExpr>(RefExpr->IgnoreParenImpCasts())))
+ Component = DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get();
+ MVLI.VarComponents.back().push_back(
+ OMPClauseMappableExprCommon::MappableComponent(Component, D));
+ }
+
+ if (MVLI.ProcessedVarList.empty())
+ return nullptr;
+
+ return OMPUseDeviceAddrClause::Create(Context, Locs, MVLI.ProcessedVarList,
+ MVLI.VarBaseDeclarations,
+ MVLI.VarComponents);
+}
+
OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
const OMPVarListLocTy &Locs) {
MappableVarListInfo MVLI(VarList);
@@ -17248,6 +18864,8 @@ OMPClause *Sema::ActOnOpenMPAllocateClause(
if (Vars.empty())
return nullptr;
+ if (Allocator)
+ DSAStack->addInnerAllocatorExpr(Allocator);
return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator,
ColonLoc, EndLoc, Vars);
}
@@ -17290,3 +18908,266 @@ OMPClause *Sema::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList,
return OMPNontemporalClause::Create(Context, StartLoc, LParenLoc, EndLoc,
Vars);
}
+
+OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second)
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ const DSAStackTy::DSAVarData DVar =
+ DSAStack->getTopDSA(D, /*FromParent=*/true);
+ // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
+ // A list item that appears in the inclusive or exclusive clause must appear
+ // in a reduction clause with the inscan modifier on the enclosing
+ // worksharing-loop, worksharing-loop SIMD, or simd construct.
+ if (DVar.CKind != OMPC_reduction ||
+ DVar.Modifier != OMPC_REDUCTION_inscan)
+ Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction)
+ << RefExpr->getSourceRange();
+
+ if (DSAStack->getParentDirective() != OMPD_unknown)
+ DSAStack->markDeclAsUsedInScanDirective(D);
+ Vars.push_back(RefExpr);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPInclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP nontemporal clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second)
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
+ DSAStackTy::DSAVarData DVar;
+ if (ParentDirective != OMPD_unknown)
+ DVar = DSAStack->getTopDSA(D, /*FromParent=*/true);
+ // OpenMP 5.0, 2.9.6, scan Directive, Restrictions.
+ // A list item that appears in the inclusive or exclusive clause must appear
+ // in a reduction clause with the inscan modifier on the enclosing
+ // worksharing-loop, worksharing-loop SIMD, or simd construct.
+ if (ParentDirective == OMPD_unknown || DVar.CKind != OMPC_reduction ||
+ DVar.Modifier != OMPC_REDUCTION_inscan) {
+ Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction)
+ << RefExpr->getSourceRange();
+ } else {
+ DSAStack->markDeclAsUsedInScanDirective(D);
+ }
+ Vars.push_back(RefExpr);
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPExclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars);
+}
+
+/// Tries to find omp_alloctrait_t type.
+static bool findOMPAlloctraitT(Sema &S, SourceLocation Loc, DSAStackTy *Stack) {
+ QualType OMPAlloctraitT = Stack->getOMPAlloctraitT();
+ if (!OMPAlloctraitT.isNull())
+ return true;
+ IdentifierInfo &II = S.PP.getIdentifierTable().get("omp_alloctrait_t");
+ ParsedType PT = S.getTypeName(II, Loc, S.getCurScope());
+ if (!PT.getAsOpaquePtr() || PT.get().isNull()) {
+ S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_alloctrait_t";
+ return false;
+ }
+ Stack->setOMPAlloctraitT(PT.get());
+ return true;
+}
+
+OMPClause *Sema::ActOnOpenMPUsesAllocatorClause(
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<UsesAllocatorsData> Data) {
+ // OpenMP [2.12.5, target Construct]
+ // allocator is an identifier of omp_allocator_handle_t type.
+ if (!findOMPAllocatorHandleT(*this, StartLoc, DSAStack))
+ return nullptr;
+ // OpenMP [2.12.5, target Construct]
+ // allocator-traits-array is an identifier of const omp_alloctrait_t * type.
+ if (llvm::any_of(
+ Data,
+ [](const UsesAllocatorsData &D) { return D.AllocatorTraits; }) &&
+ !findOMPAlloctraitT(*this, StartLoc, DSAStack))
+ return nullptr;
+ llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> PredefinedAllocators;
+ for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) {
+ auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I);
+ StringRef Allocator =
+ OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind);
+ DeclarationName AllocatorName = &Context.Idents.get(Allocator);
+ PredefinedAllocators.insert(LookupSingleName(
+ TUScope, AllocatorName, StartLoc, Sema::LookupAnyName));
+ }
+
+ SmallVector<OMPUsesAllocatorsClause::Data, 4> NewData;
+ for (const UsesAllocatorsData &D : Data) {
+ Expr *AllocatorExpr = nullptr;
+ // Check allocator expression.
+ if (D.Allocator->isTypeDependent()) {
+ AllocatorExpr = D.Allocator;
+ } else {
+ // Traits were specified - need to assign new allocator to the specified
+ // allocator, so it must be an lvalue.
+ AllocatorExpr = D.Allocator->IgnoreParenImpCasts();
+ auto *DRE = dyn_cast<DeclRefExpr>(AllocatorExpr);
+ bool IsPredefinedAllocator = false;
+ if (DRE)
+ IsPredefinedAllocator = PredefinedAllocators.count(DRE->getDecl());
+ if (!DRE ||
+ !(Context.hasSameUnqualifiedType(
+ AllocatorExpr->getType(), DSAStack->getOMPAllocatorHandleT()) ||
+ Context.typesAreCompatible(AllocatorExpr->getType(),
+ DSAStack->getOMPAllocatorHandleT(),
+ /*CompareUnqualified=*/true)) ||
+ (!IsPredefinedAllocator &&
+ (AllocatorExpr->getType().isConstant(Context) ||
+ !AllocatorExpr->isLValue()))) {
+ Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected)
+ << "omp_allocator_handle_t" << (DRE ? 1 : 0)
+ << AllocatorExpr->getType() << D.Allocator->getSourceRange();
+ continue;
+ }
+ // OpenMP [2.12.5, target Construct]
+ // Predefined allocators appearing in a uses_allocators clause cannot have
+ // traits specified.
+ if (IsPredefinedAllocator && D.AllocatorTraits) {
+ Diag(D.AllocatorTraits->getExprLoc(),
+ diag::err_omp_predefined_allocator_with_traits)
+ << D.AllocatorTraits->getSourceRange();
+ Diag(D.Allocator->getExprLoc(), diag::note_omp_predefined_allocator)
+ << cast<NamedDecl>(DRE->getDecl())->getName()
+ << D.Allocator->getSourceRange();
+ continue;
+ }
+ // OpenMP [2.12.5, target Construct]
+ // Non-predefined allocators appearing in a uses_allocators clause must
+ // have traits specified.
+ if (!IsPredefinedAllocator && !D.AllocatorTraits) {
+ Diag(D.Allocator->getExprLoc(),
+ diag::err_omp_nonpredefined_allocator_without_traits);
+ continue;
+ }
+ // No allocator traits - just convert it to rvalue.
+ if (!D.AllocatorTraits)
+ AllocatorExpr = DefaultLvalueConversion(AllocatorExpr).get();
+ DSAStack->addUsesAllocatorsDecl(
+ DRE->getDecl(),
+ IsPredefinedAllocator
+ ? DSAStackTy::UsesAllocatorsDeclKind::PredefinedAllocator
+ : DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator);
+ }
+ Expr *AllocatorTraitsExpr = nullptr;
+ if (D.AllocatorTraits) {
+ if (D.AllocatorTraits->isTypeDependent()) {
+ AllocatorTraitsExpr = D.AllocatorTraits;
+ } else {
+ // OpenMP [2.12.5, target Construct]
+ // Arrays that contain allocator traits that appear in a uses_allocators
+ // clause must be constant arrays, have constant values and be defined
+ // in the same scope as the construct in which the clause appears.
+ AllocatorTraitsExpr = D.AllocatorTraits->IgnoreParenImpCasts();
+ // Check that traits expr is a constant array.
+ QualType TraitTy;
+ if (const ArrayType *Ty =
+ AllocatorTraitsExpr->getType()->getAsArrayTypeUnsafe())
+ if (const auto *ConstArrayTy = dyn_cast<ConstantArrayType>(Ty))
+ TraitTy = ConstArrayTy->getElementType();
+ if (TraitTy.isNull() ||
+ !(Context.hasSameUnqualifiedType(TraitTy,
+ DSAStack->getOMPAlloctraitT()) ||
+ Context.typesAreCompatible(TraitTy, DSAStack->getOMPAlloctraitT(),
+ /*CompareUnqualified=*/true))) {
+ Diag(D.AllocatorTraits->getExprLoc(),
+ diag::err_omp_expected_array_alloctraits)
+ << AllocatorTraitsExpr->getType();
+ continue;
+ }
+ // Do not map by default allocator traits if it is a standalone
+ // variable.
+ if (auto *DRE = dyn_cast<DeclRefExpr>(AllocatorTraitsExpr))
+ DSAStack->addUsesAllocatorsDecl(
+ DRE->getDecl(),
+ DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait);
+ }
+ }
+ OMPUsesAllocatorsClause::Data &NewD = NewData.emplace_back();
+ NewD.Allocator = AllocatorExpr;
+ NewD.AllocatorTraits = AllocatorTraitsExpr;
+ NewD.LParenLoc = D.LParenLoc;
+ NewD.RParenLoc = D.RParenLoc;
+ }
+ return OMPUsesAllocatorsClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ NewData);
+}
+
+OMPClause *Sema::ActOnOpenMPAffinityClause(
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
+ SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) {
+ SmallVector<Expr *, 8> Vars;
+ for (Expr *RefExpr : Locators) {
+ assert(RefExpr && "NULL expr in OpenMP shared clause.");
+ if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
+
+ SourceLocation ELoc = RefExpr->getExprLoc();
+ Expr *SimpleExpr = RefExpr->IgnoreParenImpCasts();
+
+ if (!SimpleExpr->isLValue()) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << 1 << 0 << RefExpr->getSourceRange();
+ continue;
+ }
+
+ ExprResult Res;
+ {
+ Sema::TentativeAnalysisScope Trap(*this);
+ Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, SimpleExpr);
+ }
+ if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) &&
+ !isa<OMPArrayShapingExpr>(SimpleExpr)) {
+ Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item)
+ << 1 << 0 << RefExpr->getSourceRange();
+ continue;
+ }
+ Vars.push_back(SimpleExpr);
+ }
+
+ return OMPAffinityClause::Create(Context, StartLoc, LParenLoc, ColonLoc,
+ EndLoc, Modifier, Vars);
+}