[OPENMP50]Basic support for uses_allocators clause.
Summary: Added parsing/sema/serialization supoprt for uses_allocators clause.
Reviewers: jdoerfert
Subscribers: yaxunl, guansong, arphaman, cfe-commits, caomhin
Tags: #clang
Differential Revision: https://reviews.llvm.org/D78577
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index bd98728..d4d398f 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -150,6 +150,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
break;
}
@@ -239,6 +240,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
break;
}
@@ -1302,6 +1304,70 @@
return new (Mem) OMPExclusiveClause(N);
}
+void OMPUsesAllocatorsClause::setAllocatorsData(
+ ArrayRef<OMPUsesAllocatorsClause::Data> Data) {
+ assert(Data.size() == NumOfAllocators &&
+ "Size of allocators data is not the same as the preallocated buffer.");
+ for (unsigned I = 0, E = Data.size(); I < E; ++I) {
+ const OMPUsesAllocatorsClause::Data &D = Data[I];
+ getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
+ static_cast<int>(ExprOffsets::Allocator)] =
+ D.Allocator;
+ getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
+ static_cast<int>(
+ ExprOffsets::AllocatorTraits)] =
+ D.AllocatorTraits;
+ getTrailingObjects<
+ SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
+ static_cast<int>(ParenLocsOffsets::LParen)] =
+ D.LParenLoc;
+ getTrailingObjects<
+ SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
+ static_cast<int>(ParenLocsOffsets::RParen)] =
+ D.RParenLoc;
+ }
+}
+
+OMPUsesAllocatorsClause::Data
+OMPUsesAllocatorsClause::getAllocatorData(unsigned I) const {
+ OMPUsesAllocatorsClause::Data Data;
+ Data.Allocator =
+ getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
+ static_cast<int>(ExprOffsets::Allocator)];
+ Data.AllocatorTraits =
+ getTrailingObjects<Expr *>()[I * static_cast<int>(ExprOffsets::Total) +
+ static_cast<int>(
+ ExprOffsets::AllocatorTraits)];
+ Data.LParenLoc = getTrailingObjects<
+ SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
+ static_cast<int>(ParenLocsOffsets::LParen)];
+ Data.RParenLoc = getTrailingObjects<
+ SourceLocation>()[I * static_cast<int>(ParenLocsOffsets::Total) +
+ static_cast<int>(ParenLocsOffsets::RParen)];
+ return Data;
+}
+
+OMPUsesAllocatorsClause *
+OMPUsesAllocatorsClause::Create(const ASTContext &C, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc,
+ ArrayRef<OMPUsesAllocatorsClause::Data> Data) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *, SourceLocation>(
+ static_cast<int>(ExprOffsets::Total) * Data.size(),
+ static_cast<int>(ParenLocsOffsets::Total) * Data.size()));
+ auto *Clause = new (Mem)
+ OMPUsesAllocatorsClause(StartLoc, LParenLoc, EndLoc, Data.size());
+ Clause->setAllocatorsData(Data);
+ return Clause;
+}
+
+OMPUsesAllocatorsClause *
+OMPUsesAllocatorsClause::CreateEmpty(const ASTContext &C, unsigned N) {
+ void *Mem = C.Allocate(totalSizeToAlloc<Expr *, SourceLocation>(
+ static_cast<int>(ExprOffsets::Total) * N,
+ static_cast<int>(ParenLocsOffsets::Total) * N));
+ return new (Mem) OMPUsesAllocatorsClause(N);
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
@@ -1884,6 +1950,25 @@
}
}
+void OMPClausePrinter::VisitOMPUsesAllocatorsClause(
+ OMPUsesAllocatorsClause *Node) {
+ if (Node->getNumberOfAllocators() == 0)
+ return;
+ OS << "uses_allocators(";
+ for (unsigned I = 0, E = Node->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data Data = Node->getAllocatorData(I);
+ Data.Allocator->printPretty(OS, nullptr, Policy);
+ if (Data.AllocatorTraits) {
+ OS << "(";
+ Data.AllocatorTraits->printPretty(OS, nullptr, Policy);
+ OS << ")";
+ }
+ if (I < E - 1)
+ OS << ",";
+ }
+ OS << ")";
+}
+
void OMPTraitInfo::getAsVariantMatchInfo(ASTContext &ASTCtx,
VariantMatchInfo &VMI) const {
for (const OMPTraitSet &Set : Sets) {
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index be0bc13..869d2fa 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -800,6 +800,15 @@
void OMPClauseProfiler::VisitOMPExclusiveClause(const OMPExclusiveClause *C) {
VisitOMPClauseList(C);
}
+void OMPClauseProfiler::VisitOMPUsesAllocatorsClause(
+ const OMPUsesAllocatorsClause *C) {
+ for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
+ Profiler->VisitStmt(D.Allocator);
+ if (D.AllocatorTraits)
+ Profiler->VisitStmt(D.AllocatorTraits);
+ }
+}
void OMPClauseProfiler::VisitOMPOrderClause(const OMPOrderClause *C) {}
} // namespace
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 888666b..841d76b 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -174,6 +174,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@@ -420,6 +421,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index cbc08ac..19bbcb8 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -4627,6 +4627,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 0c0ef15..19acfe1 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2436,6 +2436,50 @@
return !IsCorrect;
}
+OMPClause *Parser::ParseOpenMPUsesAllocatorClause(OpenMPDirectiveKind DKind) {
+ SourceLocation Loc = Tok.getLocation();
+ ConsumeAnyToken();
+
+ // Parse '('.
+ BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end);
+ if (T.expectAndConsume(diag::err_expected_lparen_after, "uses_allocator"))
+ return nullptr;
+ SmallVector<Sema::UsesAllocatorsData, 4> Data;
+ do {
+ ExprResult Allocator = ParseCXXIdExpression();
+ if (Allocator.isInvalid()) {
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ break;
+ }
+ Sema::UsesAllocatorsData &D = Data.emplace_back();
+ D.Allocator = Allocator.get();
+ if (Tok.is(tok::l_paren)) {
+ BalancedDelimiterTracker T(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ T.consumeOpen();
+ ExprResult AllocatorTraits = ParseCXXIdExpression();
+ T.consumeClose();
+ if (AllocatorTraits.isInvalid()) {
+ SkipUntil(tok::comma, tok::r_paren, tok::annot_pragma_openmp_end,
+ StopBeforeMatch);
+ break;
+ }
+ D.AllocatorTraits = AllocatorTraits.get();
+ D.LParenLoc = T.getOpenLocation();
+ D.RParenLoc = T.getCloseLocation();
+ }
+ if (Tok.isNot(tok::comma) && Tok.isNot(tok::r_paren))
+ Diag(Tok, diag::err_omp_expected_punc) << "uses_allocators" << 0;
+ // Parse ','
+ if (Tok.is(tok::comma))
+ ConsumeAnyToken();
+ } while (Tok.isNot(tok::r_paren) && Tok.isNot(tok::annot_pragma_openmp_end));
+ T.consumeClose();
+ return Actions.ActOnOpenMPUsesAllocatorClause(Loc, T.getOpenLocation(),
+ T.getCloseLocation(), Data);
+}
+
/// Parsing of OpenMP clauses.
///
/// clause:
@@ -2453,7 +2497,7 @@
/// in_reduction-clause | allocator-clause | allocate-clause |
/// acq_rel-clause | acquire-clause | release-clause | relaxed-clause |
/// depobj-clause | destroy-clause | detach-clause | inclusive-clause |
-/// exclusive-clause
+/// exclusive-clause | uses_allocators-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@@ -2626,6 +2670,9 @@
case OMPC_exclusive:
Clause = ParseOpenMPVarListClause(DKind, CKind, WrongDirective);
break;
+ case OMPC_uses_allocators:
+ Clause = ParseOpenMPUsesAllocatorClause(DKind);
+ break;
case OMPC_device_type:
case OMPC_unknown:
skipUntilPragmaOpenMPEnd(DKind);
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 41bfca9..7364af7 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -170,6 +170,7 @@
llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls;
/// List of decls used in inclusive/exclusive clauses of the scan directive.
llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective;
+ llvm::DenseSet<CanonicalDeclPtr<const Decl>> UsesAllocatorsDecls;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
: Directive(DKind), DirectiveName(Name), CurScope(CurScope),
@@ -279,6 +280,8 @@
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};
@@ -293,6 +296,10 @@
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) {
@@ -1006,6 +1013,19 @@
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) {
+ getTopOfStack().UsesAllocatorsDecls.insert(D);
+ }
+ /// Checks if specified decl is used in uses allocator clause as the
+ /// allocator.
+ bool isUsesAllocatorsDecl(unsigned Level, const Decl *D) const {
+ return getStackElemAtLevel(Level).UsesAllocatorsDecls.count(D) > 0;
+ }
+ bool isUsesAllocatorsDecl(const Decl *D) const {
+ return getTopOfStack().UsesAllocatorsDecls.count(D) > 0;
+ }
};
bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) {
@@ -1990,10 +2010,13 @@
((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>() &&
@@ -2435,6 +2458,11 @@
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
@@ -2504,6 +2532,51 @@
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)
+ 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())
@@ -3032,7 +3105,7 @@
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);
@@ -3187,6 +3260,9 @@
if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) &&
!Stack->isImplicitTaskFirstprivate(VD))
return;
+ // Skip allocators in uses_allocators clauses.
+ if (Stack->isUsesAllocatorsDecl(VD))
+ return;
DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false);
// Check if the variable has explicit DSA set and stop analysis if it so.
@@ -4640,6 +4716,27 @@
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());
+ }
+ 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() &&
@@ -4708,6 +4805,22 @@
}
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.
@@ -5239,6 +5352,7 @@
case OMPC_destroy:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
continue;
case OMPC_allocator:
case OMPC_flush:
@@ -11365,6 +11479,7 @@
case OMPC_destroy:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12118,6 +12233,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
llvm_unreachable("Unexpected OpenMP clause.");
}
return CaptureRegion;
@@ -12557,6 +12673,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -12782,6 +12899,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -13014,6 +13132,7 @@
case OMPC_detach:
case OMPC_inclusive:
case OMPC_exclusive:
+ case OMPC_uses_allocators:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -13279,6 +13398,7 @@
case OMPC_order:
case OMPC_destroy:
case OMPC_detach:
+ case OMPC_uses_allocators:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -17719,21 +17839,22 @@
// 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_event_var_expected)
- << 0 << Evt->getSourceRange();
+ 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_event_var_expected)
- << 0 << Evt->getSourceRange();
+ 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_event_var_expected)
- << 1 << VD->getType() << Evt->getSourceRange();
+ 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
@@ -18450,3 +18571,134 @@
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 = OMPAllocateDeclAttr::OMPDefaultMemAlloc;
+ 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());
+ }
+ 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;
+ }
+ }
+ }
+ 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);
+}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index da6ff8e..0987fee 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2086,6 +2086,17 @@
EndLoc);
}
+ /// Build a new OpenMP 'uses_allocators' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPUsesAllocatorsClause(
+ ArrayRef<Sema::UsesAllocatorsData> Data, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPUsesAllocatorClause(StartLoc, LParenLoc, EndLoc,
+ Data);
+ }
+
/// Build a new OpenMP 'order' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@@ -9673,8 +9684,33 @@
}
template <typename Derived>
-OMPClause *
-TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) {
+OMPClause *TreeTransform<Derived>::TransformOMPUsesAllocatorsClause(
+ OMPUsesAllocatorsClause *C) {
+ SmallVector<Sema::UsesAllocatorsData, 16> Data;
+ Data.reserve(C->getNumberOfAllocators());
+ for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I);
+ ExprResult Allocator = getDerived().TransformExpr(D.Allocator);
+ if (Allocator.isInvalid())
+ continue;
+ ExprResult AllocatorTraits;
+ if (Expr *AT = D.AllocatorTraits) {
+ AllocatorTraits = getDerived().TransformExpr(AT);
+ if (AllocatorTraits.isInvalid())
+ continue;
+ }
+ Sema::UsesAllocatorsData &NewD = Data.emplace_back();
+ NewD.Allocator = Allocator.get();
+ NewD.AllocatorTraits = AllocatorTraits.get();
+ NewD.LParenLoc = D.LParenLoc;
+ NewD.RParenLoc = D.RParenLoc;
+ }
+ return getDerived().RebuildOMPUsesAllocatorsClause(
+ Data, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) {
return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(),
C->getBeginLoc(), C->getLParenLoc(),
C->getEndLoc());
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index 8731158..3ead713 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -11882,6 +11882,9 @@
case llvm::omp::OMPC_detach:
C = new (Context) OMPDetachClause();
break;
+ case llvm::omp::OMPC_uses_allocators:
+ C = OMPUsesAllocatorsClause::CreateEmpty(Context, Record.readInt());
+ break;
#define OMP_CLAUSE_NO_CLASS(Enum, Str) \
case llvm::omp::Enum: \
break;
@@ -12710,6 +12713,21 @@
C->setVarRefs(Vars);
}
+void OMPClauseReader::VisitOMPUsesAllocatorsClause(OMPUsesAllocatorsClause *C) {
+ C->setLParenLoc(Record.readSourceLocation());
+ unsigned NumOfAllocators = C->getNumberOfAllocators();
+ SmallVector<OMPUsesAllocatorsClause::Data, 4> Data;
+ Data.reserve(NumOfAllocators);
+ for (unsigned I = 0; I != NumOfAllocators; ++I) {
+ OMPUsesAllocatorsClause::Data &D = Data.emplace_back();
+ D.Allocator = Record.readSubExpr();
+ D.AllocatorTraits = Record.readSubExpr();
+ D.LParenLoc = Record.readSourceLocation();
+ D.RParenLoc = Record.readSourceLocation();
+ }
+ C->setAllocatorsData(Data);
+}
+
void OMPClauseReader::VisitOMPOrderClause(OMPOrderClause *C) {
C->setKind(Record.readEnum<OpenMPOrderClauseKind>());
C->setLParenLoc(Record.readSourceLocation());
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 748ac06..462f275 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -6651,6 +6651,18 @@
Record.AddSourceLocation(C->getKindKwLoc());
}
+void OMPClauseWriter::VisitOMPUsesAllocatorsClause(OMPUsesAllocatorsClause *C) {
+ Record.push_back(C->getNumberOfAllocators());
+ Record.AddSourceLocation(C->getLParenLoc());
+ for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) {
+ OMPUsesAllocatorsClause::Data Data = C->getAllocatorData(I);
+ Record.AddStmt(Data.Allocator);
+ Record.AddStmt(Data.AllocatorTraits);
+ Record.AddSourceLocation(Data.LParenLoc);
+ Record.AddSourceLocation(Data.RParenLoc);
+ }
+}
+
void ASTRecordWriter::writeOMPTraitInfo(const OMPTraitInfo *TI) {
writeUInt32(TI->Sets.size());
for (const auto &Set : TI->Sets) {