Initial parsing/sema for 'align' clause

Added basic parsing/sema/serialization support for 'align' clause for use with
'allocate' directive.
This commit is contained in:
David Pagan 2021-11-09 07:33:39 -05:00 committed by Aaron Ballman
parent b702276ad0
commit b0de656bdf
20 changed files with 405 additions and 18 deletions

View file

@ -322,6 +322,81 @@ public:
}
};
/// This represents the 'align' clause in the '#pragma omp allocate'
/// directive.
///
/// \code
/// #pragma omp allocate(a) allocator(omp_default_mem_alloc) align(8)
/// \endcode
/// In this example directive '#pragma omp allocate' has simple 'allocator'
/// clause with the allocator 'omp_default_mem_alloc' and align clause with
/// value of 8.
class OMPAlignClause final : public OMPClause {
friend class OMPClauseReader;
/// Location of '('.
SourceLocation LParenLoc;
/// Alignment specified with align clause.
Stmt *Alignment = nullptr;
/// Set alignment value.
void setAlignment(Expr *A) { Alignment = A; }
/// Sets the location of '('.
void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
/// Build 'align' clause with the given alignment
///
/// \param A Alignment value.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
OMPAlignClause(Expr *A, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
: OMPClause(llvm::omp::OMPC_align, StartLoc, EndLoc),
LParenLoc(LParenLoc), Alignment(A) {}
/// Build an empty clause.
OMPAlignClause()
: OMPClause(llvm::omp::OMPC_align, SourceLocation(), SourceLocation()) {}
public:
/// Build 'align' clause with the given alignment
///
/// \param A Alignment value.
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
static OMPAlignClause *Create(const ASTContext &C, Expr *A,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Returns the location of '('.
SourceLocation getLParenLoc() const { return LParenLoc; }
/// Returns alignment
Expr *getAlignment() const { return cast_or_null<Expr>(Alignment); }
child_range children() { return child_range(&Alignment, &Alignment + 1); }
const_child_range children() const {
return const_child_range(&Alignment, &Alignment + 1);
}
child_range used_children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range used_children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
static bool classof(const OMPClause *T) {
return T->getClauseKind() == llvm::omp::OMPC_align;
}
};
/// This represents clause 'allocate' in the '#pragma omp ...' directives.
///
/// \code

View file

@ -3093,6 +3093,12 @@ RecursiveASTVisitor<Derived>::VisitOMPNumThreadsClause(OMPNumThreadsClause *C) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPAlignClause(OMPAlignClause *C) {
TRY_TO(TraverseStmt(C->getAlignment()));
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSafelenClause(OMPSafelenClause *C) {
TRY_TO(TraverseStmt(C->getSafelen()));

View file

@ -3683,7 +3683,8 @@ def OMPAllocateDecl : InheritableAttr {
"OMPCGroupMemAlloc", "OMPPTeamMemAlloc", "OMPThreadMemAlloc",
"OMPUserDefinedMemAlloc"
]>,
ExprArgument<"Allocator">
ExprArgument<"Allocator">,
ExprArgument<"Alignment">
];
let Documentation = [Undocumented];
}

View file

@ -11034,6 +11034,10 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-formed 'align' clause.
OMPClause *ActOnOpenMPAlignClause(Expr *Alignment, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-formed 'safelen' clause.
OMPClause *ActOnOpenMPSafelenClause(Expr *Length,
SourceLocation StartLoc,

View file

@ -1662,10 +1662,11 @@ void DeclPrinter::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
Out << ")";
}
if (!D->clauselist_empty()) {
Out << " ";
OMPClausePrinter Printer(Out, Policy);
for (OMPClause *C : D->clauselists())
for (OMPClause *C : D->clauselists()) {
Out << " ";
Printer.Visit(C);
}
}
}

View file

@ -629,6 +629,13 @@ OMPAlignedClause *OMPAlignedClause::CreateEmpty(const ASTContext &C,
return new (Mem) OMPAlignedClause(NumVars);
}
OMPAlignClause *OMPAlignClause::Create(const ASTContext &C, Expr *A,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return new (C) OMPAlignClause(A, StartLoc, LParenLoc, EndLoc);
}
void OMPCopyinClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) {
assert(SrcExprs.size() == varlist_size() && "Number of source expressions is "
"not the same as the "
@ -1622,6 +1629,12 @@ void OMPClausePrinter::VisitOMPNumThreadsClause(OMPNumThreadsClause *Node) {
OS << ")";
}
void OMPClausePrinter::VisitOMPAlignClause(OMPAlignClause *Node) {
OS << "align(";
Node->getAlignment()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
}
void OMPClausePrinter::VisitOMPSafelenClause(OMPSafelenClause *Node) {
OS << "safelen(";
Node->getSafelen()->printPretty(OS, nullptr, Policy, 0);

View file

@ -452,6 +452,11 @@ void OMPClauseProfiler::VisitOMPNumThreadsClause(const OMPNumThreadsClause *C) {
Profiler->VisitStmt(C->getNumThreads());
}
void OMPClauseProfiler::VisitOMPAlignClause(const OMPAlignClause *C) {
if (C->getAlignment())
Profiler->VisitStmt(C->getAlignment());
}
void OMPClauseProfiler::VisitOMPSafelenClause(const OMPSafelenClause *C) {
if (C->getSafelen())
Profiler->VisitStmt(C->getSafelen());

View file

@ -5993,6 +5993,7 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_append_args:
case OMPC_memory_order:
case OMPC_bind:
case OMPC_align:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}

View file

@ -3105,6 +3105,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_nocontext:
case OMPC_filter:
case OMPC_partial:
case OMPC_align:
// OpenMP [2.5, Restrictions]
// At most one num_threads clause can appear on the directive.
// OpenMP [2.8.1, simd construct, Restrictions]
@ -3362,6 +3363,9 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
/// detach-clause:
/// 'detach' '(' event-handler-expression ')'
///
/// align-clause
/// 'align' '(' positive-integer-constant ')'
///
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,
bool ParseOnly) {
SourceLocation Loc = ConsumeToken();

View file

@ -3130,16 +3130,22 @@ static bool checkPreviousOMPAllocateAttribute(
static void
applyOMPAllocateAttribute(Sema &S, VarDecl *VD,
OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind,
Expr *Allocator, SourceRange SR) {
Expr *Allocator, Expr *Alignment, SourceRange SR) {
if (VD->hasAttr<OMPAllocateDeclAttr>())
return;
if (Alignment &&
(Alignment->isTypeDependent() || Alignment->isValueDependent() ||
Alignment->isInstantiationDependent() ||
Alignment->containsUnexpandedParameterPack()))
// Apply later when we have a usable value.
return;
if (Allocator &&
(Allocator->isTypeDependent() || Allocator->isValueDependent() ||
Allocator->isInstantiationDependent() ||
Allocator->containsUnexpandedParameterPack()))
return;
auto *A = OMPAllocateDeclAttr::CreateImplicit(S.Context, AllocatorKind,
Allocator, SR);
Allocator, Alignment, SR);
VD->addAttr(A);
if (ASTMutationListener *ML = S.Context.getASTMutationListener())
ML->DeclarationMarkedOpenMPAllocate(VD, A);
@ -3148,7 +3154,8 @@ applyOMPAllocateAttribute(Sema &S, VarDecl *VD,
Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective(
SourceLocation Loc, ArrayRef<Expr *> VarList,
ArrayRef<OMPClause *> Clauses, DeclContext *Owner) {
assert(Clauses.size() <= 1 && "Expected at most one clause.");
assert(Clauses.size() <= 2 && "Expected at most two clauses.");
Expr *Alignment = nullptr;
Expr *Allocator = nullptr;
if (Clauses.empty()) {
// OpenMP 5.0, 2.11.3 allocate Directive, Restrictions.
@ -3159,7 +3166,13 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective(
!DSAStack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>())
targetDiag(Loc, diag::err_expected_allocator_clause);
} else {
Allocator = cast<OMPAllocatorClause>(Clauses.back())->getAllocator();
for (const OMPClause *C : Clauses)
if (const auto *AC = dyn_cast<OMPAllocatorClause>(C))
Allocator = AC->getAllocator();
else if (const auto *AC = dyn_cast<OMPAlignClause>(C))
Alignment = AC->getAlignment();
else
llvm_unreachable("Unexpected clause on allocate directive");
}
OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind =
getAllocatorKind(*this, DSAStack, Allocator);
@ -3200,7 +3213,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPAllocateDirective(
}
Vars.push_back(RefExpr);
applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator,
applyOMPAllocateAttribute(*this, VD, AllocatorKind, Allocator, Alignment,
DE->getSourceRange());
}
if (Vars.empty())
@ -5228,8 +5241,10 @@ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack,
if (checkPreviousOMPAllocateAttribute(S, Stack, E, PrivateVD,
AllocatorKind, AC->getAllocator()))
continue;
// Placeholder until allocate clause supports align modifier.
Expr *Alignment = nullptr;
applyOMPAllocateAttribute(S, PrivateVD, AllocatorKind, AC->getAllocator(),
E->getSourceRange());
Alignment, E->getSourceRange());
}
}
}
@ -13415,6 +13430,9 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_partial:
Res = ActOnOpenMPPartialClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_align:
Res = ActOnOpenMPAlignClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_device:
case OMPC_if:
case OMPC_default:
@ -14528,7 +14546,7 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E,
<< E->getSourceRange();
return ExprError();
}
if (CKind == OMPC_aligned && !Result.isPowerOf2()) {
if ((CKind == OMPC_aligned || CKind == OMPC_align) && !Result.isPowerOf2()) {
Diag(E->getExprLoc(), diag::warn_omp_alignment_not_power_of_two)
<< E->getSourceRange();
return ExprError();
@ -14953,6 +14971,17 @@ OMPClause *Sema::ActOnOpenMPPartialClause(Expr *FactorExpr,
FactorExpr);
}
OMPClause *Sema::ActOnOpenMPAlignClause(Expr *A, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
ExprResult AlignVal;
AlignVal = VerifyPositiveIntegerConstantInClause(A, OMPC_align);
if (AlignVal.isInvalid())
return nullptr;
return OMPAlignClause::Create(Context, AlignVal.get(), StartLoc, LParenLoc,
EndLoc);
}
OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr,
SourceLocation StartLoc, SourceLocation LParenLoc,

View file

@ -3371,12 +3371,23 @@ Decl *TemplateDeclInstantiator::VisitOMPAllocateDecl(OMPAllocateDecl *D) {
SmallVector<OMPClause *, 4> Clauses;
// Copy map clauses from the original mapper.
for (OMPClause *C : D->clauselists()) {
auto *AC = cast<OMPAllocatorClause>(C);
ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs);
if (!NewE.isUsable())
continue;
OMPClause *IC = SemaRef.ActOnOpenMPAllocatorClause(
NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc());
OMPClause *IC = nullptr;
if (auto *AC = dyn_cast<OMPAllocatorClause>(C)) {
ExprResult NewE = SemaRef.SubstExpr(AC->getAllocator(), TemplateArgs);
if (!NewE.isUsable())
continue;
IC = SemaRef.ActOnOpenMPAllocatorClause(
NewE.get(), AC->getBeginLoc(), AC->getLParenLoc(), AC->getEndLoc());
} else if (auto *AC = dyn_cast<OMPAlignClause>(C)) {
ExprResult NewE = SemaRef.SubstExpr(AC->getAlignment(), TemplateArgs);
if (!NewE.isUsable())
continue;
IC = SemaRef.ActOnOpenMPAlignClause(NewE.get(), AC->getBeginLoc(),
AC->getLParenLoc(), AC->getEndLoc());
// If align clause value ends up being invalid, this can end up null.
if (!IC)
continue;
}
Clauses.push_back(IC);
}

View file

@ -2269,6 +2269,16 @@ public:
EndLoc);
}
/// Build a new OpenMP 'align' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPAlignClause(Expr *A, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return getSema().ActOnOpenMPAlignClause(A, StartLoc, LParenLoc, EndLoc);
}
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@ -9547,6 +9557,15 @@ TreeTransform<Derived>::TransformOMPFilterClause(OMPFilterClause *C) {
C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPAlignClause(OMPAlignClause *C) {
ExprResult E = getDerived().TransformExpr(C->getAlignment());
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPAlignClause(E.get(), C->getBeginLoc(),
C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPUnifiedAddressClause(
OMPUnifiedAddressClause *C) {

View file

@ -11974,6 +11974,9 @@ OMPClause *OMPClauseReader::readClause() {
case llvm::omp::OMPC_bind:
C = OMPBindClause::CreateEmpty(Context);
break;
case llvm::omp::OMPC_align:
C = new (Context) OMPAlignClause();
break;
#define OMP_CLAUSE_NO_CLASS(Enum, Str) \
case llvm::omp::Enum: \
break;
@ -12964,6 +12967,11 @@ void OMPClauseReader::VisitOMPBindClause(OMPBindClause *C) {
C->setBindKindLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPAlignClause(OMPAlignClause *C) {
C->setAlignment(Record.readExpr());
C->setLParenLoc(Record.readSourceLocation());
}
OMPTraitInfo *ASTRecordReader::readOMPTraitInfo() {
OMPTraitInfo &TI = getContext().getNewOMPTraitInfo();
TI.Sets.resize(readUInt32());

View file

@ -4757,9 +4757,10 @@ void ASTDeclReader::UpdateDecl(Decl *D,
auto AllocatorKind =
static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(Record.readInt());
Expr *Allocator = Record.readExpr();
Expr *Alignment = Record.readExpr();
SourceRange SR = readSourceRange();
D->addAttr(OMPAllocateDeclAttr::CreateImplicit(
Reader.getContext(), AllocatorKind, Allocator, SR,
Reader.getContext(), AllocatorKind, Allocator, Alignment, SR,
AttributeCommonInfo::AS_Pragma));
break;
}

View file

@ -5026,6 +5026,7 @@ void ASTWriter::WriteDeclUpdatesBlocks(RecordDataImpl &OffsetsRecord) {
auto *A = D->getAttr<OMPAllocateDeclAttr>();
Record.push_back(A->getAllocatorType());
Record.AddStmt(A->getAllocator());
Record.AddStmt(A->getAlignment());
Record.AddSourceRange(A->getRange());
break;
}
@ -6230,6 +6231,11 @@ void OMPClauseWriter::VisitOMPFilterClause(OMPFilterClause *C) {
Record.AddSourceLocation(C->getLParenLoc());
}
void OMPClauseWriter::VisitOMPAlignClause(OMPAlignClause *C) {
Record.AddStmt(C->getAlignment());
Record.AddSourceLocation(C->getLParenLoc());
}
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Record.AddSourceLocation(C->getLParenLoc());

View file

@ -0,0 +1,134 @@
// expected-no-diagnostics
//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \
//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \
//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \
//RUN: -ast-print %s | FileCheck %s --check-prefix=PRINT
//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \
//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \
//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \
//RUN: -ast-dump %s | FileCheck %s --check-prefix=DUMP
//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \
//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \
//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \
//RUN: -emit-pch -o %t %s
//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \
//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \
//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \
//RUN: -include-pch %t -ast-print %s | FileCheck %s --check-prefix=PRINT
//RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=51 \
//RUN: -x c++ -std=c++14 -fexceptions -fcxx-exceptions \
//RUN: -Wno-source-uses-openmp -Wno-openmp-clauses \
//RUN: -include-pch %t -ast-dump-all %s | FileCheck %s --check-prefix=DUMP
#ifndef HEADER
#define HEADER
typedef enum omp_allocator_handle_t {
omp_null_allocator = 0,
omp_default_mem_alloc = 1,
omp_large_cap_mem_alloc = 2,
omp_const_mem_alloc = 3,
omp_high_bw_mem_alloc = 4,
omp_low_lat_mem_alloc = 5,
omp_cgroup_mem_alloc = 6,
omp_pteam_mem_alloc = 7,
omp_thread_mem_alloc = 8,
KMP_ALLOCATOR_MAX_HANDLE = __UINTPTR_MAX__
} omp_allocator_handle_t;
int foo1() {
char a;
#pragma omp allocate(a) align(4) allocator(omp_pteam_mem_alloc)
return a;
}
// DUMP: FunctionDecl {{.*}}
// DUMP: DeclStmt {{.*}}
// DUMP: VarDecl {{.*}}a 'char'
// DUMP: OMPAllocateDeclAttr {{.*}}OMPPTeamMemAlloc
// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}} 'omp_pteam_mem_alloc' 'omp_allocator_handle_t'
// DUMP: ConstantExpr {{.*}}'int'
// DUMP: value: Int 4
// DUMP: IntegerLiteral {{.*}}'int' 4
// DUMP: DeclStmt {{.*}}
// DUMP: OMPAllocateDecl {{.*}}
// DUMP: DeclRefExpr {{.*}}'char' lvalue Var {{.*}} 'a' 'char'
// DUMP: OMPAlignClause {{.*}}
// DUMP: ConstantExpr {{.*}}'int'
// DUMP: value: Int 4
// DUMP: IntegerLiteral {{.*}}'int' 4
// DUMP: OMPAllocatorClause {{.*}}
// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}}'omp_pteam_mem_alloc' 'omp_allocator_handle_t'
// PRINT: #pragma omp allocate(a) align(4) allocator(omp_pteam_mem_alloc)
int foo2() {
char b;
#pragma omp allocate(b) allocator(omp_low_lat_mem_alloc) align(2)
return b;
}
// DUMP: FunctionDecl {{.*}}
// DUMP: DeclStmt {{.*}}
// DUMP: VarDecl {{.*}}b 'char'
// DUMP: OMPAllocateDeclAttr {{.*}}Implicit OMPLowLatMemAlloc
// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}} 'omp_low_lat_mem_alloc' 'omp_allocator_handle_t'
// DUMP: ConstantExpr {{.*}}'int'
// DUMP: value: Int 2
// DUMP: IntegerLiteral {{.*}}'int' 2
// DUMP: DeclStmt {{.*}}
// DUMP: OMPAllocateDecl {{.*}}
// DUMP: DeclRefExpr {{.*}}'char' lvalue Var {{.*}} 'b' 'char'
// DUMP: OMPAllocatorClause {{.*}}
// DUMP: DeclRefExpr {{.*}}'omp_allocator_handle_t' EnumConstant {{.*}} 'omp_low_lat_mem_alloc' 'omp_allocator_handle_t'
// DUMP: OMPAlignClause {{.*}}
// DUMP: ConstantExpr {{.*}}'int'
// DUMP: value: Int 2
// DUMP: IntegerLiteral {{.*}}'int' 2
// PRINT: #pragma omp allocate(b) allocator(omp_low_lat_mem_alloc) align(2)
template <typename T, unsigned size>
T run() {
T foo;
#pragma omp allocate(foo) align(size)
return size;
}
int template_test() {
double d;
d = run<double, 1>();
return 0;
}
// DUMP: FunctionTemplateDecl {{.*}}
// DUMP: TemplateTypeParmDecl {{.*}}
// DUMP: NonTypeTemplateParmDecl {{.*}}'unsigned int' depth 0 index 1 size
// DUMP: FunctionDecl {{.*}}'T ()'
// DUMP: DeclStmt {{.*}}
// DUMP: OMPAllocateDecl {{.*}}
// DUMP: DeclRefExpr {{.*}}'T' lvalue Var {{.*}} 'foo' 'T'
// DUMP: OMPAlignClause {{.*}}
// DUMP: DeclRefExpr {{.*}}'unsigned int' NonTypeTemplateParm {{.*}} 'size' 'unsigned int'
// DUMP: FunctionDecl {{.*}}run 'double ()'
// DUMP: TemplateArgument type 'double'
// DUMP: BuiltinType {{.*}}'double'
// DUMP: TemplateArgument integral 1
// DUMP: OMPAllocateDeclAttr {{.*}}Implicit OMPNullMemAlloc
// DUMP: ConstantExpr {{.*}}'unsigned int'
// DUMP: value: Int 1
// DUMP: SubstNonTypeTemplateParmExpr {{.*}}'unsigned int'
// DUMP: NonTypeTemplateParmDecl {{.*}}'unsigned int' depth 0 index 1 size
// DUMP: IntegerLiteral {{.*}}'unsigned int' 1
// DUMP: OMPAllocateDecl {{.*}}
// DUMP: DeclRefExpr {{.*}}'double':'double' lvalue Var {{.*}} 'foo' 'double':'double'
// DUMP: OMPAlignClause {{.*}}
// DUMP: ConstantExpr {{.*}}'unsigned int'
// DUMP: value: Int 1
// DUMP: SubstNonTypeTemplateParmExpr {{.*}}'unsigned int'
// DUMP: NonTypeTemplateParmDecl {{.*}}'unsigned int' depth 0 index 1 size
// DUMP: IntegerLiteral {{.*}}'unsigned int' 1
// PRINT: #pragma omp allocate(foo) align(size)
// PRINT: #pragma omp allocate(foo) align(1U)
#endif // HEADER

View file

@ -0,0 +1,60 @@
// RUN: %clang_cc1 -fopenmp -fopenmp-version=51 %s -verify
int foobar() {
return 1;
}
int main(int argc, char *argv[]) {
// expected-note@+1 {{declared here}}
int a;
// expected-note@+1 {{declared here}}
int b;
// expected-note@+1 {{declared here}}
int c;
double f;
int foo2[10];
// expected-error@+1 {{expected '(' after 'align'}}
#pragma omp allocate(a) align
// expected-error@+3 {{expected expression}}
// expected-error@+2 {{expected ')'}}
// expected-note@+1 {{to match this '('}}
#pragma omp allocate(a) align(
// expected-error@+1 {{expected expression}}
#pragma omp allocate(a) align()
// expected-error@+4 {{expected ')'}}
// expected-note@+3 {{to match this '('}}
// expected-error@+2 {{expression is not an integral constant expression}}
// expected-note@+1 {{read of non-const variable 'a' is not allowed in a constant expression}}
#pragma omp allocate(a) align(a
// expected-error@+2 {{expression is not an integral constant expression}}
// expected-note@+1 {{read of non-const variable 'b' is not allowed in a constant expression}}
#pragma omp allocate(a) align(b)
// expected-error@+2 {{expression is not an integral constant expression}}
// expected-note@+1 {{read of non-const variable 'c' is not allowed in a constant expression}}
#pragma omp allocate(a) align(c + 1)
// expected-error@+1 {{expected an OpenMP directive}}
#pragma omp align(2) allocate(a)
// expected-error@+1 {{directive '#pragma omp allocate' cannot contain more than one 'align' clause}}
#pragma omp allocate(a) align(2) align(4)
// expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
#pragma omp allocate(a) align(9)
// expected-error@+1 {{integral constant expression must have integral or unscoped enumeration type, not 'double'}}
#pragma omp allocate(a) align(f)
}
// Verify appropriate errors when using templates.
template <typename T, unsigned size, unsigned align>
T run() {
T foo[size];
// expected-warning@+1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
#pragma omp allocate(foo) align(align)
return foo[0];
}
int template_test() {
double d;
// expected-note@+1 {{in instantiation of function template specialization 'run<double, 10U, 3U>' requested here}}
d = run<double, 10, 3>();
return 0;
}

View file

@ -2315,6 +2315,10 @@ void OMPClauseEnqueue::VisitOMPFilterClause(const OMPFilterClause *C) {
Visitor->AddStmt(C->getThreadID());
}
void OMPClauseEnqueue::VisitOMPAlignClause(const OMPAlignClause *C) {
Visitor->AddStmt(C->getAlignment());
}
void OMPClauseEnqueue::VisitOMPUnifiedAddressClause(
const OMPUnifiedAddressClause *) {}

View file

@ -1481,6 +1481,7 @@ CHECK_SIMPLE_CLAUSE(AdjustArgs, OMPC_adjust_args)
CHECK_SIMPLE_CLAUSE(AppendArgs, OMPC_append_args)
CHECK_SIMPLE_CLAUSE(MemoryOrder, OMPC_memory_order)
CHECK_SIMPLE_CLAUSE(Bind, OMPC_bind)
CHECK_SIMPLE_CLAUSE(Align, OMPC_align)
CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks)

View file

@ -363,6 +363,9 @@ def OMPC_Filter : Clause<"filter"> {
let clangClass = "OMPFilterClause";
let flangClass = "ScalarIntExpr";
}
def OMPC_Align : Clause<"align"> {
let clangClass = "OMPAlignClause";
}
def OMPC_When: Clause<"when"> {}
def OMPC_Bind : Clause<"bind"> {
@ -1539,7 +1542,8 @@ def OMP_TargetTeamsDistributeSimd :
}
def OMP_Allocate : Directive<"allocate"> {
let allowedOnceClauses = [
VersionedClause<OMPC_Allocator>
VersionedClause<OMPC_Allocator>,
VersionedClause<OMPC_Align, 51>
];
}
def OMP_DeclareVariant : Directive<"declare variant"> {