[clang] b0de656 - Initial parsing/sema for 'align' clause

Aaron Ballman via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 9 04:34:25 PST 2021


Author: David Pagan
Date: 2021-11-09T07:34:18-05:00
New Revision: b0de656bdf0ee3f4e51d04ae29160dab99819e8e

URL: https://github.com/llvm/llvm-project/commit/b0de656bdf0ee3f4e51d04ae29160dab99819e8e
DIFF: https://github.com/llvm/llvm-project/commit/b0de656bdf0ee3f4e51d04ae29160dab99819e8e.diff

LOG: Initial parsing/sema for 'align' clause

Added basic parsing/sema/serialization support for 'align' clause for use with
'allocate' directive.

Added: 
    clang/test/OpenMP/align_clause_ast_print.cpp
    clang/test/OpenMP/align_clause_messages.cpp

Modified: 
    clang/include/clang/AST/OpenMPClause.h
    clang/include/clang/AST/RecursiveASTVisitor.h
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/DeclPrinter.cpp
    clang/lib/AST/OpenMPClause.cpp
    clang/lib/AST/StmtProfile.cpp
    clang/lib/CodeGen/CGStmtOpenMP.cpp
    clang/lib/Parse/ParseOpenMP.cpp
    clang/lib/Sema/SemaOpenMP.cpp
    clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
    clang/lib/Sema/TreeTransform.h
    clang/lib/Serialization/ASTReader.cpp
    clang/lib/Serialization/ASTReaderDecl.cpp
    clang/lib/Serialization/ASTWriter.cpp
    clang/tools/libclang/CIndex.cpp
    flang/lib/Semantics/check-omp-structure.cpp
    llvm/include/llvm/Frontend/OpenMP/OMP.td

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h
index 99554641a64b8..565eb0c9cf99d 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -322,6 +322,81 @@ class OMPAllocatorClause : public OMPClause {
   }
 };
 
+/// 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

diff  --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h
index 67f0c2758bafd..9797eac53dde6 100644
--- a/clang/include/clang/AST/RecursiveASTVisitor.h
+++ b/clang/include/clang/AST/RecursiveASTVisitor.h
@@ -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()));

diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index a5443c967bf66..d8f0fcd56550c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -3683,7 +3683,8 @@ def OMPAllocateDecl : InheritableAttr {
                    "OMPCGroupMemAlloc", "OMPPTeamMemAlloc", "OMPThreadMemAlloc",
                    "OMPUserDefinedMemAlloc"
                  ]>,
-    ExprArgument<"Allocator">
+    ExprArgument<"Allocator">,
+    ExprArgument<"Alignment">
   ];
   let Documentation = [Undocumented];
 }

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index b22d8530ed6cc..c7a6d04ce8f8c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -11034,6 +11034,10 @@ class Sema final {
                                          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,

diff  --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp
index 7f3d3c5a9ec33..38f2d10cdc903 100644
--- a/clang/lib/AST/DeclPrinter.cpp
+++ b/clang/lib/AST/DeclPrinter.cpp
@@ -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);
+    }
   }
 }
 

diff  --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index ddc31aa9e93fe..f721e56f7fdd1 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -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);

diff  --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 97bc7e6aabeb6..4339c249e0270 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -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());

diff  --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 4d4037001ee0a..3dbebc5d3296f 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -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'.");
   }
 }

diff  --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 5444969f110f2..613ad742c93f5 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -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();

diff  --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 446132886ee0e..debc9c5df3820 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -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,

diff  --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8c433a0e8cca7..27ac2cd08f2a8 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -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);
   }
 

diff  --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 3f0f21b2e6e73..c1e9890094fde 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -2269,6 +2269,16 @@ class TreeTransform {
                                            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 
diff erent 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) {

diff  --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index fdf75b0d7be9d..a033bccbe5061 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -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());

diff  --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp
index 3e4a2416a3cd4..62a31f299d6bc 100644
--- a/clang/lib/Serialization/ASTReaderDecl.cpp
+++ b/clang/lib/Serialization/ASTReaderDecl.cpp
@@ -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;
     }

diff  --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index 4845dc70469fd..73f9ff280aa95 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -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());

diff  --git a/clang/test/OpenMP/align_clause_ast_print.cpp b/clang/test/OpenMP/align_clause_ast_print.cpp
new file mode 100644
index 0000000000000..2575f64a3c658
--- /dev/null
+++ b/clang/test/OpenMP/align_clause_ast_print.cpp
@@ -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

diff  --git a/clang/test/OpenMP/align_clause_messages.cpp b/clang/test/OpenMP/align_clause_messages.cpp
new file mode 100644
index 0000000000000..c1ea7d1052066
--- /dev/null
+++ b/clang/test/OpenMP/align_clause_messages.cpp
@@ -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 at +1 {{declared here}}
+  int a;
+  // expected-note at +1 {{declared here}}
+  int b;
+  // expected-note at +1 {{declared here}}
+  int c;
+  double f;
+  int foo2[10];
+
+// expected-error at +1 {{expected '(' after 'align'}}
+#pragma omp allocate(a) align
+// expected-error at +3 {{expected expression}}
+// expected-error at +2 {{expected ')'}}
+// expected-note at +1 {{to match this '('}}
+#pragma omp allocate(a) align(
+// expected-error at +1 {{expected expression}}
+#pragma omp allocate(a) align()
+// expected-error at +4 {{expected ')'}}
+// expected-note at +3 {{to match this '('}}
+// expected-error at +2 {{expression is not an integral constant expression}}
+// expected-note at +1 {{read of non-const variable 'a' is not allowed in a constant expression}}
+#pragma omp allocate(a) align(a
+// expected-error at +2 {{expression is not an integral constant expression}}
+// expected-note at +1 {{read of non-const variable 'b' is not allowed in a constant expression}}
+#pragma omp allocate(a) align(b)
+// expected-error at +2 {{expression is not an integral constant expression}}
+// expected-note at +1 {{read of non-const variable 'c' is not allowed in a constant expression}}
+#pragma omp allocate(a) align(c + 1)
+// expected-error at +1 {{expected an OpenMP directive}}
+#pragma omp align(2) allocate(a)
+// expected-error at +1 {{directive '#pragma omp allocate' cannot contain more than one 'align' clause}}
+#pragma omp allocate(a) align(2) align(4)
+// expected-warning at +1 {{aligned clause will be ignored because the requested alignment is not a power of 2}}
+#pragma omp allocate(a) align(9)
+// expected-error at +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 at +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 at +1 {{in instantiation of function template specialization 'run<double, 10U, 3U>' requested here}}
+  d = run<double, 10, 3>();
+  return 0;
+}

diff  --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp
index 0b953b2dd6869..ab3bf222430a9 100644
--- a/clang/tools/libclang/CIndex.cpp
+++ b/clang/tools/libclang/CIndex.cpp
@@ -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 *) {}
 

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 5a06cce481741..2698cafca8ebc 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -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)

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 211573132bac4..5ee379b7fcadf 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -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"> {


        


More information about the cfe-commits mailing list