[llvm] 0a90ffa - [flang][openacc] OpenACC 3.0 parser

via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 14 11:29:48 PDT 2020


Author: Valentin Clement
Date: 2020-07-14T14:29:40-04:00
New Revision: 0a90ffa77293e8e2c99843f770cc0f2cd1d8947c

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

LOG: [flang][openacc] OpenACC 3.0 parser

Summary:
This patch introduce the parser for OpenACC 3.0 in Flang. It uses the same TableGen mechanism
than OpenMP.

Reviewers: nvdatian, sscalpone, tskeith, klausler, ichoyjx, jdoerfert, DavidTruby

Reviewed By: klausler

Subscribers: MaskRay, SouraVX, mgorny, hiraditya, jfb, sstefan1, llvm-commits

Tags: #llvm, #flang

Differential Revision: https://reviews.llvm.org/D83649

Added: 
    flang/lib/Parser/openacc-parsers.cpp
    flang/test/Semantics/acc-validity.f90
    llvm/include/llvm/Frontend/CMakeLists.txt
    llvm/include/llvm/Frontend/OpenACC/ACC.td
    llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt
    llvm/lib/Frontend/OpenACC/CMakeLists.txt

Modified: 
    flang/include/flang/Common/Fortran-features.h
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Parser/CMakeLists.txt
    flang/lib/Parser/executable-parsers.cpp
    flang/lib/Parser/openmp-parsers.cpp
    flang/lib/Parser/parsing.cpp
    flang/lib/Parser/program-parsers.cpp
    flang/lib/Parser/stmt-parser.h
    flang/lib/Parser/token-parsers.h
    flang/lib/Parser/type-parsers.h
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/resolve-names.cpp
    flang/tools/f18-parse-demo/CMakeLists.txt
    flang/tools/f18/CMakeLists.txt
    flang/tools/f18/f18.cpp
    llvm/include/llvm/CMakeLists.txt
    llvm/include/llvm/Frontend/Directive/DirectiveBase.td
    llvm/lib/Frontend/CMakeLists.txt
    llvm/test/TableGen/directive1.td
    llvm/test/TableGen/directive2.td
    llvm/utils/TableGen/DirectiveEmitter.cpp

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Common/Fortran-features.h b/flang/include/flang/Common/Fortran-features.h
index 823fa85ad12e..613aa69cc5d6 100644
--- a/flang/include/flang/Common/Fortran-features.h
+++ b/flang/include/flang/Common/Fortran-features.h
@@ -24,7 +24,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
     OldStyleParameter, ComplexConstructor, PercentLOC, SignedPrimary, FileName,
     Convert, Dispose, IOListLeadingComma, AbbreviatedEditDescriptor,
     ProgramParentheses, PercentRefAndVal, OmitFunctionDummies, CrayPointer,
-    Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenMP,
+    Hollerith, ArithmeticIF, Assign, AssignedGOTO, Pause, OpenACC, OpenMP,
     CruftAfterAmpersand, ClassicCComments, AdditionalFormats, BigIntLiterals,
     RealDoControls, EquivalenceNumericWithCharacter, AdditionalIntrinsics,
     AnonymousParents, OldLabelDoEndStatements, LogicalIntegerAssignment,
@@ -37,6 +37,7 @@ class LanguageFeatureControl {
   LanguageFeatureControl() {
     // These features must be explicitly enabled by command line options.
     disable_.set(LanguageFeature::OldDebugLines);
+    disable_.set(LanguageFeature::OpenACC);
     disable_.set(LanguageFeature::OpenMP);
     // These features, if enabled, conflict with valid standard usage,
     // so there are disabled here by default.
@@ -50,7 +51,9 @@ class LanguageFeatureControl {
   void WarnOnAllNonstandard(bool yes = true) { warnAll_ = yes; }
   bool IsEnabled(LanguageFeature f) const { return !disable_.test(f); }
   bool ShouldWarn(LanguageFeature f) const {
-    return (warnAll_ && f != LanguageFeature::OpenMP) || warn_.test(f);
+    return (warnAll_ && f != LanguageFeature::OpenMP &&
+               f != LanguageFeature::OpenACC) ||
+        warn_.test(f);
   }
   // Return all spellings of operators names, depending on features enabled
   std::vector<const char *> GetNames(LogicalOperator) const;

diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index 59333c7405ff..36e593eb3b78 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -53,6 +53,88 @@ class ParseTreeDumper {
   NODE(format, IntrinsicTypeDataEditDesc)
   NODE(format::IntrinsicTypeDataEditDesc, Kind)
   NODE(parser, Abstract)
+  NODE(parser, AccAtomicCapture)
+  NODE(AccAtomicCapture, Stmt1)
+  NODE(AccAtomicCapture, Stmt2)
+  NODE(parser, AccAtomicRead)
+  NODE(parser, AccAtomicUpdate)
+  NODE(parser, AccAtomicWrite)
+  NODE(parser, AccBeginBlockDirective)
+  NODE(parser, AccBeginCombinedDirective)
+  NODE(parser, AccBeginLoopDirective)
+  NODE(parser, AccBlockDirective)
+  NODE(parser, AccClause)
+  NODE(AccClause, Auto)
+  NODE(AccClause, Async)
+  NODE(AccClause, Attach)
+  NODE(AccClause, Bind)
+  NODE(AccClause, Capture)
+  NODE(AccClause, Collapse)
+  NODE(AccClause, Copy)
+  NODE(AccClause, Copyin)
+  NODE(AccClause, Copyout)
+  NODE(AccClause, Create)
+  NODE(AccClause, Default)
+  NODE(AccClause, DefaultAsync)
+  NODE(AccClause, Delete)
+  NODE(AccClause, Detach)
+  NODE(AccClause, Device)
+  NODE(AccClause, DeviceNum)
+  NODE(AccClause, DevicePtr)
+  NODE(AccClause, DeviceResident)
+  NODE(AccClause, DeviceType)
+  NODE(AccClause, Finalize)
+  NODE(AccClause, FirstPrivate)
+  NODE(AccClause, Gang)
+  NODE(AccClause, Host)
+  NODE(AccClause, If)
+  NODE(AccClause, IfPresent)
+  NODE(AccClause, Independent)
+  NODE(AccClause, Link)
+  NODE(AccClause, NoCreate)
+  NODE(AccClause, NoHost)
+  NODE(AccClause, NumGangs)
+  NODE(AccClause, NumWorkers)
+  NODE(AccClause, Present)
+  NODE(AccClause, Private)
+  NODE(AccClause, Tile)
+  NODE(AccClause, UseDevice)
+  NODE(AccClause, Read)
+  NODE(AccClause, Reduction)
+  NODE(AccClause, Self)
+  NODE(AccClause, Seq)
+  NODE(AccClause, Vector)
+  NODE(AccClause, VectorLength)
+  NODE(AccClause, Wait)
+  NODE(AccClause, Worker)
+  NODE(AccClause, Write)
+  NODE(AccClause, Unknown)
+  NODE(parser, AccDefaultClause)
+  NODE_ENUM(parser::AccDefaultClause, Arg)
+  NODE(parser, AccClauseList)
+  NODE(parser, AccCombinedDirective)
+  NODE(parser, AccDataModifier)
+  NODE_ENUM(parser::AccDataModifier, Modifier)
+  NODE(parser, AccDeclarativeDirective)
+  NODE(parser, AccEndAtomic)
+  NODE(parser, AccEndBlockDirective)
+  NODE(parser, AccEndCombinedDirective)
+  NODE(parser, AccGangArgument)
+  NODE(parser, AccObject)
+  NODE(parser, AccObjectList)
+  NODE(parser, AccObjectListWithModifier)
+  NODE(parser, AccObjectListWithReduction)
+  NODE(parser, AccReductionOperator)
+  NODE(parser, AccSizeExpr)
+  NODE(parser, AccSizeExprList)
+  NODE(parser, AccStandaloneDirective)
+  NODE(parser, AccLoopDirective)
+  NODE(parser, AccWaitArgument)
+  static std::string GetNodeName(const llvm::acc::Directive &x) {
+    return llvm::Twine(
+        "llvm::acc::Directive = ", llvm::acc::getOpenACCDirectiveName(x))
+        .str();
+  }
   NODE(parser, AcImpliedDo)
   NODE(parser, AcImpliedDoControl)
   NODE(parser, AcValue)
@@ -510,6 +592,17 @@ class ParseTreeDumper {
   NODE(parser, OmpSectionsDirective)
   NODE(parser, OmpSimpleStandaloneDirective)
   NODE(parser, Only)
+  NODE(parser, OpenACCAtomicConstruct)
+  NODE(parser, OpenACCBlockConstruct)
+  NODE(parser, OpenACCCacheConstruct)
+  NODE(parser, OpenACCCombinedConstruct)
+  NODE(parser, OpenACCConstruct)
+  NODE(parser, OpenACCDeclarativeConstruct)
+  NODE(parser, OpenACCLoopConstruct)
+  NODE(parser, OpenACCRoutineConstruct)
+  NODE(parser, OpenACCStandaloneDeclarativeConstruct)
+  NODE(parser, OpenACCStandaloneConstruct)
+  NODE(parser, OpenACCWaitConstruct)
   NODE(parser, OpenMPAtomicConstruct)
   NODE(parser, OpenMPBlockConstruct)
   NODE(parser, OpenMPCancelConstruct)

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 67fd5741b097..d9ecebfc3fdd 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -25,6 +25,7 @@
 #include "flang/Common/Fortran.h"
 #include "flang/Common/idioms.h"
 #include "flang/Common/indirection.h"
+#include "llvm/Frontend/OpenACC/ACC.h.inc"
 #include "llvm/Frontend/OpenMP/OMPConstants.h"
 #include <cinttypes>
 #include <list>
@@ -256,6 +257,8 @@ struct ArithmeticIfStmt;
 struct AssignStmt;
 struct AssignedGotoStmt;
 struct PauseStmt;
+struct OpenACCConstruct;
+struct OpenACCDeclarativeConstruct;
 struct OpenMPConstruct;
 struct OpenMPDeclarativeConstruct;
 struct OmpEndLoopDirective;
@@ -386,6 +389,7 @@ struct SpecificationConstruct {
       Statement<OtherSpecificationStmt>,
       Statement<common::Indirection<TypeDeclarationStmt>>,
       common::Indirection<StructureDef>,
+      common::Indirection<OpenACCDeclarativeConstruct>,
       common::Indirection<OpenMPDeclarativeConstruct>,
       common::Indirection<CompilerDirective>>
       u;
@@ -424,7 +428,8 @@ struct DeclarationConstruct {
 // from the implicit part to the declaration constructs
 struct SpecificationPart {
   TUPLE_CLASS_BOILERPLATE(SpecificationPart);
-  std::tuple<std::list<OpenMPDeclarativeConstruct>,
+  std::tuple<std::list<OpenACCDeclarativeConstruct>,
+      std::list<OpenMPDeclarativeConstruct>,
       std::list<Statement<common::Indirection<UseStmt>>>,
       std::list<Statement<common::Indirection<ImportStmt>>>, ImplicitPart,
       std::list<DeclarationConstruct>>
@@ -509,6 +514,7 @@ struct ExecutableConstruct {
       common::Indirection<SelectTypeConstruct>,
       common::Indirection<WhereConstruct>, common::Indirection<ForallConstruct>,
       common::Indirection<CompilerDirective>,
+      common::Indirection<OpenACCConstruct>,
       common::Indirection<OpenMPConstruct>,
       common::Indirection<OmpEndLoopDirective>>
       u;
@@ -3789,5 +3795,287 @@ struct OpenMPConstruct {
       OpenMPCriticalConstruct>
       u;
 };
+
+// Parse tree nodes for OpenACC 3.0 directives and clauses
+
+struct AccObject {
+  UNION_CLASS_BOILERPLATE(AccObject);
+  std::variant<Designator, /*common block*/ Name> u;
+};
+
+WRAPPER_CLASS(AccObjectList, std::list<AccObject>);
+
+// OpenACC directive beginning or ending a block
+struct AccBlockDirective {
+  WRAPPER_CLASS_BOILERPLATE(AccBlockDirective, llvm::acc::Directive);
+  CharBlock source;
+};
+
+struct AccLoopDirective {
+  WRAPPER_CLASS_BOILERPLATE(AccLoopDirective, llvm::acc::Directive);
+  CharBlock source;
+};
+
+struct AccStandaloneDirective {
+  WRAPPER_CLASS_BOILERPLATE(AccStandaloneDirective, llvm::acc::Directive);
+  CharBlock source;
+};
+
+// 2.11 Combined constructs
+struct AccCombinedDirective {
+  WRAPPER_CLASS_BOILERPLATE(AccCombinedDirective, llvm::acc::Directive);
+  CharBlock source;
+};
+
+struct AccDeclarativeDirective {
+  WRAPPER_CLASS_BOILERPLATE(AccDeclarativeDirective, llvm::acc::Directive);
+  CharBlock source;
+};
+
+// OpenACC Clauses
+struct AccDefaultClause {
+  ENUM_CLASS(Arg, None, Present)
+  WRAPPER_CLASS_BOILERPLATE(AccDefaultClause, Arg);
+  CharBlock source;
+};
+
+struct AccDataModifier {
+  ENUM_CLASS(Modifier, ReadOnly, Zero)
+  WRAPPER_CLASS_BOILERPLATE(AccDataModifier, Modifier);
+  CharBlock source;
+};
+
+struct AccObjectListWithModifier {
+  TUPLE_CLASS_BOILERPLATE(AccObjectListWithModifier);
+  std::tuple<std::optional<AccDataModifier>, AccObjectList> t;
+};
+
+// 2.5.13: + | * | max | min | iand | ior | ieor | .and. | .or. | .eqv. | .neqv.
+struct AccReductionOperator {
+  UNION_CLASS_BOILERPLATE(AccReductionOperator);
+  std::variant<DefinedOperator, ProcedureDesignator> u;
+};
+
+struct AccObjectListWithReduction {
+  TUPLE_CLASS_BOILERPLATE(AccObjectListWithReduction);
+  std::tuple<AccReductionOperator, AccObjectList> t;
+};
+
+struct AccWaitArgument {
+  TUPLE_CLASS_BOILERPLATE(AccWaitArgument);
+  std::tuple<std::optional<ScalarIntExpr>, std::list<ScalarIntExpr>> t;
+};
+
+struct AccSizeExpr {
+  TUPLE_CLASS_BOILERPLATE(AccSizeExpr);
+  CharBlock source;
+  std::tuple<std::optional<ScalarIntExpr>> t; // if null then *
+};
+
+struct AccSizeExprList {
+  WRAPPER_CLASS_BOILERPLATE(AccSizeExprList, std::list<AccSizeExpr>);
+};
+
+struct AccGangArgument {
+  TUPLE_CLASS_BOILERPLATE(AccGangArgument);
+  std::tuple<std::optional<ScalarIntExpr>, std::optional<AccSizeExpr>> t;
+};
+
+struct AccClause {
+  UNION_CLASS_BOILERPLATE(AccClause);
+
+  EMPTY_CLASS(Auto);
+  WRAPPER_CLASS(Async, std::optional<ScalarIntExpr>);
+  WRAPPER_CLASS(Attach, AccObjectList);
+  WRAPPER_CLASS(Bind, Name);
+  EMPTY_CLASS(Capture);
+  WRAPPER_CLASS(Collapse, ScalarIntConstantExpr);
+  WRAPPER_CLASS(Copy, AccObjectList);
+  WRAPPER_CLASS(Copyin, AccObjectListWithModifier);
+  WRAPPER_CLASS(Copyout, AccObjectListWithModifier);
+  WRAPPER_CLASS(Create, AccObjectListWithModifier);
+  WRAPPER_CLASS(Default, AccDefaultClause);
+  WRAPPER_CLASS(DefaultAsync, ScalarIntExpr);
+  WRAPPER_CLASS(Delete, AccObjectList);
+  WRAPPER_CLASS(Detach, AccObjectList);
+  WRAPPER_CLASS(Device, AccObjectList);
+  WRAPPER_CLASS(DeviceNum, ScalarIntConstantExpr);
+  WRAPPER_CLASS(DevicePtr, AccObjectList);
+  WRAPPER_CLASS(DeviceResident, AccObjectList);
+  WRAPPER_CLASS(DeviceType, std::optional<std::list<Name>>);
+  EMPTY_CLASS(Finalize);
+  WRAPPER_CLASS(FirstPrivate, AccObjectList);
+  WRAPPER_CLASS(Gang, std::optional<AccGangArgument>);
+  WRAPPER_CLASS(Host, AccObjectList);
+  WRAPPER_CLASS(If, ScalarLogicalExpr);
+  EMPTY_CLASS(IfPresent);
+  EMPTY_CLASS(Independent);
+  WRAPPER_CLASS(Link, AccObjectList);
+  WRAPPER_CLASS(NoCreate, AccObjectList);
+  EMPTY_CLASS(NoHost);
+  WRAPPER_CLASS(NumGangs, ScalarIntExpr);
+  WRAPPER_CLASS(NumWorkers, ScalarIntExpr);
+  WRAPPER_CLASS(Present, AccObjectList);
+  WRAPPER_CLASS(Private, AccObjectList);
+  WRAPPER_CLASS(Tile, AccSizeExprList);
+  WRAPPER_CLASS(UseDevice, AccObjectList);
+  EMPTY_CLASS(Read);
+  WRAPPER_CLASS(Reduction, AccObjectListWithReduction);
+  WRAPPER_CLASS(Self, std::optional<ScalarLogicalExpr>);
+  EMPTY_CLASS(Seq);
+  WRAPPER_CLASS(Vector, std::optional<ScalarIntExpr>);
+  WRAPPER_CLASS(VectorLength, ScalarIntExpr);
+  WRAPPER_CLASS(Wait, std::optional<AccWaitArgument>);
+  WRAPPER_CLASS(Worker, std::optional<ScalarIntExpr>);
+  EMPTY_CLASS(Write);
+  EMPTY_CLASS(Unknown);
+
+  CharBlock source;
+
+  std::variant<Auto, Async, Attach, Bind, Capture, Collapse, Copy, Copyin,
+      Copyout, Create, Default, DefaultAsync, Delete, Detach, Device, DeviceNum,
+      DevicePtr, DeviceResident, DeviceType, Finalize, FirstPrivate, Gang, Host,
+      If, IfPresent, Independent, Link, NoCreate, NoHost, NumGangs, NumWorkers,
+      Present, Private, Tile, UseDevice, Read, Reduction, Self, Seq, Vector,
+      VectorLength, Wait, Worker, Write, Unknown>
+      u;
+};
+
+struct AccClauseList {
+  WRAPPER_CLASS_BOILERPLATE(AccClauseList, std::list<AccClause>);
+  CharBlock source;
+};
+
+struct OpenACCRoutineConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCRoutineConstruct);
+  CharBlock source;
+  std::tuple<Verbatim, std::optional<Name>, AccClauseList> t;
+};
+
+struct OpenACCCacheConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCCacheConstruct);
+  CharBlock source;
+  std::tuple<Verbatim, AccObjectListWithModifier> t;
+};
+
+struct OpenACCWaitConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCWaitConstruct);
+  CharBlock source;
+  std::tuple<Verbatim, std::optional<AccWaitArgument>, AccClauseList> t;
+};
+
+struct AccBeginLoopDirective {
+  TUPLE_CLASS_BOILERPLATE(AccBeginLoopDirective);
+  std::tuple<AccLoopDirective, AccClauseList> t;
+  CharBlock source;
+};
+
+struct AccBeginBlockDirective {
+  TUPLE_CLASS_BOILERPLATE(AccBeginBlockDirective);
+  CharBlock source;
+  std::tuple<AccBlockDirective, AccClauseList> t;
+};
+
+struct AccEndBlockDirective {
+  CharBlock source;
+  WRAPPER_CLASS_BOILERPLATE(AccEndBlockDirective, AccBlockDirective);
+};
+
+// ACC END ATOMIC
+EMPTY_CLASS(AccEndAtomic);
+
+// ACC ATOMIC READ
+struct AccAtomicRead {
+  TUPLE_CLASS_BOILERPLATE(AccAtomicRead);
+  std::tuple<Verbatim, Statement<AssignmentStmt>, std::optional<AccEndAtomic>>
+      t;
+};
+
+// ACC ATOMIC WRITE
+struct AccAtomicWrite {
+  TUPLE_CLASS_BOILERPLATE(AccAtomicWrite);
+  std::tuple<Verbatim, Statement<AssignmentStmt>, std::optional<AccEndAtomic>>
+      t;
+};
+
+// ACC ATOMIC UPDATE
+struct AccAtomicUpdate {
+  TUPLE_CLASS_BOILERPLATE(AccAtomicUpdate);
+  std::tuple<std::optional<Verbatim>, Statement<AssignmentStmt>,
+      std::optional<AccEndAtomic>>
+      t;
+};
+
+// ACC ATOMIC CAPTURE
+struct AccAtomicCapture {
+  TUPLE_CLASS_BOILERPLATE(AccAtomicCapture);
+  WRAPPER_CLASS(Stmt1, Statement<AssignmentStmt>);
+  WRAPPER_CLASS(Stmt2, Statement<AssignmentStmt>);
+  std::tuple<Verbatim, Stmt1, Stmt2, AccEndAtomic> t;
+};
+
+struct OpenACCAtomicConstruct {
+  UNION_CLASS_BOILERPLATE(OpenACCAtomicConstruct);
+  std::variant<AccAtomicRead, AccAtomicWrite, AccAtomicCapture, AccAtomicUpdate>
+      u;
+};
+
+struct OpenACCBlockConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCBlockConstruct);
+  std::tuple<AccBeginBlockDirective, Block, AccEndBlockDirective> t;
+};
+
+struct OpenACCStandaloneDeclarativeConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneDeclarativeConstruct);
+  CharBlock source;
+  std::tuple<AccDeclarativeDirective, AccClauseList> t;
+};
+
+struct AccBeginCombinedDirective {
+  TUPLE_CLASS_BOILERPLATE(AccBeginCombinedDirective);
+  std::tuple<AccCombinedDirective, AccClauseList> t;
+};
+
+struct AccEndCombinedDirective {
+  WRAPPER_CLASS_BOILERPLATE(AccEndCombinedDirective, AccCombinedDirective);
+  CharBlock source;
+};
+
+struct OpenACCCombinedConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCCombinedConstruct);
+  CharBlock source;
+  std::tuple<AccBeginCombinedDirective, Block,
+      std::optional<AccEndCombinedDirective>>
+      t;
+};
+
+struct OpenACCDeclarativeConstruct {
+  UNION_CLASS_BOILERPLATE(OpenACCDeclarativeConstruct);
+  CharBlock source;
+  std::variant<OpenACCStandaloneDeclarativeConstruct> u;
+};
+
+// OpenACC directives enclosing do loop
+struct OpenACCLoopConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCLoopConstruct);
+  OpenACCLoopConstruct(AccBeginLoopDirective &&a)
+      : t({std::move(a), std::nullopt}) {}
+  std::tuple<AccBeginLoopDirective, std::optional<DoConstruct>> t;
+};
+
+struct OpenACCStandaloneConstruct {
+  TUPLE_CLASS_BOILERPLATE(OpenACCStandaloneConstruct);
+  CharBlock source;
+  std::tuple<AccStandaloneDirective, AccClauseList> t;
+};
+
+struct OpenACCConstruct {
+  UNION_CLASS_BOILERPLATE(OpenACCConstruct);
+  std::variant<OpenACCBlockConstruct, OpenACCCombinedConstruct,
+      OpenACCLoopConstruct, OpenACCStandaloneConstruct, OpenACCRoutineConstruct,
+      OpenACCCacheConstruct, OpenACCWaitConstruct, OpenACCAtomicConstruct>
+      u;
+};
+
 } // namespace Fortran::parser
 #endif // FORTRAN_PARSER_PARSE_TREE_H_

diff  --git a/flang/lib/Parser/CMakeLists.txt b/flang/lib/Parser/CMakeLists.txt
index eb5126e1b937..e1e77ac6e92d 100644
--- a/flang/lib/Parser/CMakeLists.txt
+++ b/flang/lib/Parser/CMakeLists.txt
@@ -11,6 +11,7 @@ add_flang_library(FortranParser
   instrumented-parser.cpp
   io-parsers.cpp
   message.cpp
+  openacc-parsers.cpp
   openmp-parsers.cpp
   parse-tree.cpp
   parsing.cpp
@@ -32,4 +33,5 @@ add_flang_library(FortranParser
 
   DEPENDS
   omp_gen
+  acc_gen
 )

diff  --git a/flang/lib/Parser/executable-parsers.cpp b/flang/lib/Parser/executable-parsers.cpp
index 160b2dc376a4..d6dd4688dbac 100644
--- a/flang/lib/Parser/executable-parsers.cpp
+++ b/flang/lib/Parser/executable-parsers.cpp
@@ -50,6 +50,7 @@ constexpr auto executableConstruct{
         construct<ExecutableConstruct>(indirect(whereConstruct)),
         construct<ExecutableConstruct>(indirect(forallConstruct)),
         construct<ExecutableConstruct>(indirect(ompEndLoopDirective)),
+        construct<ExecutableConstruct>(indirect(openaccConstruct)),
         construct<ExecutableConstruct>(indirect(openmpConstruct)),
         construct<ExecutableConstruct>(indirect(compilerDirective)))};
 

diff  --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp
new file mode 100644
index 000000000000..a2ab628c0993
--- /dev/null
+++ b/flang/lib/Parser/openacc-parsers.cpp
@@ -0,0 +1,284 @@
+//===-- lib/Parser/openacc-parsers.cpp ------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// Top-level grammar specification for OpenACC 3.0.
+
+#include "basic-parsers.h"
+#include "expr-parsers.h"
+#include "misc-parsers.h"
+#include "stmt-parser.h"
+#include "token-parsers.h"
+#include "type-parser-implementation.h"
+#include "flang/Parser/parse-tree.h"
+
+// OpenACC Directives and Clauses
+namespace Fortran::parser {
+
+constexpr auto startAccLine = skipStuffBeforeStatement >> "!$ACC "_sptok;
+constexpr auto endAccLine = space >> endOfLine;
+
+// Basic clauses
+TYPE_PARSER("AUTO" >> construct<AccClause>(construct<AccClause::Auto>()) ||
+    "ASYNC" >> construct<AccClause>(construct<AccClause::Async>(
+                   maybe(parenthesized(scalarIntExpr)))) ||
+    "ATTACH" >> construct<AccClause>(construct<AccClause::Attach>(
+                    parenthesized(Parser<AccObjectList>{}))) ||
+    "BIND" >>
+        construct<AccClause>(construct<AccClause::Bind>(parenthesized(name))) ||
+    "CAPTURE" >> construct<AccClause>(construct<AccClause::Capture>()) ||
+    "COLLAPSE" >> construct<AccClause>(construct<AccClause::Collapse>(
+                      parenthesized(scalarIntConstantExpr))) ||
+    ("COPY"_tok || "PRESENT_OR_COPY"_tok || "PCOPY"_tok) >>
+        construct<AccClause>(construct<AccClause::Copy>(
+            parenthesized(Parser<AccObjectList>{}))) ||
+    ("COPYIN"_tok || "PRESENT_OR_COPYIN"_tok || "PCOPYIN"_tok) >>
+        construct<AccClause>(construct<AccClause::Copyin>(
+            parenthesized(Parser<AccObjectListWithModifier>{}))) ||
+    ("COPYOUT"_tok || "PRESENT_OR_COPYOUT"_tok || "PCOPYOUT"_tok) >>
+        construct<AccClause>(construct<AccClause::Copyout>(
+            parenthesized(Parser<AccObjectListWithModifier>{}))) ||
+    ("CREATE"_tok || "PRESENT_OR_CREATE"_tok || "PCREATE"_tok) >>
+        construct<AccClause>(construct<AccClause::Create>(
+            parenthesized(Parser<AccObjectListWithModifier>{}))) ||
+    "DEFAULT" >> construct<AccClause>(construct<AccClause::Default>(
+                     Parser<AccDefaultClause>{})) ||
+    "DEFAULT_ASYNC" >> construct<AccClause>(construct<AccClause::DefaultAsync>(
+                           parenthesized(scalarIntExpr))) ||
+    "DELETE" >> construct<AccClause>(construct<AccClause::Delete>(
+                    parenthesized(Parser<AccObjectList>{}))) ||
+    "DETACH" >> construct<AccClause>(construct<AccClause::Detach>(
+                    parenthesized(Parser<AccObjectList>{}))) ||
+    "DEVICE" >> construct<AccClause>(construct<AccClause::Device>(
+                    parenthesized(Parser<AccObjectList>{}))) ||
+    "DEVICEPTR" >> construct<AccClause>(construct<AccClause::DevicePtr>(
+                       parenthesized(Parser<AccObjectList>{}))) ||
+    "DEVICENUM" >> construct<AccClause>(construct<AccClause::DeviceNum>(
+                       parenthesized(scalarIntConstantExpr))) ||
+    "DEVICE_RESIDENT" >>
+        construct<AccClause>(construct<AccClause::DeviceResident>(
+            parenthesized(Parser<AccObjectList>{}))) ||
+    ("DEVICE_TYPE"_tok || "DTYPE"_tok) >>
+        construct<AccClause>(construct<AccClause::DeviceType>(parenthesized(
+            "*" >> construct<std::optional<std::list<Name>>>()))) ||
+    ("DEVICE_TYPE"_tok || "DTYPE"_tok) >>
+        construct<AccClause>(construct<AccClause::DeviceType>(
+            parenthesized(maybe(nonemptyList(name))))) ||
+    "FINALIZE" >> construct<AccClause>(construct<AccClause::Finalize>()) ||
+    "FIRSTPRIVATE" >> construct<AccClause>(construct<AccClause::FirstPrivate>(
+                          parenthesized(Parser<AccObjectList>{}))) ||
+    "GANG" >> construct<AccClause>(construct<AccClause::Gang>(
+                  maybe(parenthesized(Parser<AccGangArgument>{})))) ||
+    "HOST" >> construct<AccClause>(construct<AccClause::Host>(
+                  parenthesized(Parser<AccObjectList>{}))) ||
+    "IF" >> construct<AccClause>(
+                construct<AccClause::If>(parenthesized(scalarLogicalExpr))) ||
+    "IF_PRESENT" >> construct<AccClause>(construct<AccClause::IfPresent>()) ||
+    "INDEPENDENT" >>
+        construct<AccClause>(construct<AccClause::Independent>()) ||
+    "LINK" >> construct<AccClause>(construct<AccClause::Link>(
+                  parenthesized(Parser<AccObjectList>{}))) ||
+    "NO_CREATE" >> construct<AccClause>(construct<AccClause::NoCreate>(
+                       parenthesized(Parser<AccObjectList>{}))) ||
+    "NOHOST" >> construct<AccClause>(construct<AccClause::NoHost>()) ||
+    "NUM_GANGS" >> construct<AccClause>(construct<AccClause::NumGangs>(
+                       parenthesized(scalarIntExpr))) ||
+    "NUM_WORKERS" >> construct<AccClause>(construct<AccClause::NumWorkers>(
+                         parenthesized(scalarIntExpr))) ||
+    "PRESENT" >> construct<AccClause>(construct<AccClause::Present>(
+                     parenthesized(Parser<AccObjectList>{}))) ||
+    "PRIVATE" >> construct<AccClause>(construct<AccClause::Private>(
+                     parenthesized(Parser<AccObjectList>{}))) ||
+    "READ" >> construct<AccClause>(construct<AccClause::Read>()) ||
+    "REDUCTION" >> construct<AccClause>(construct<AccClause::Reduction>(
+                       parenthesized(construct<AccObjectListWithReduction>(
+                           Parser<AccReductionOperator>{} / ":",
+                           Parser<AccObjectList>{})))) ||
+    "SELF" >> construct<AccClause>(construct<AccClause::Self>(
+                  maybe(parenthesized(scalarLogicalExpr)))) ||
+    "SEQ" >> construct<AccClause>(construct<AccClause::Seq>()) ||
+    "TILE" >> construct<AccClause>(construct<AccClause::Tile>(
+                  parenthesized(Parser<AccSizeExprList>{}))) ||
+    "USE_DEVICE" >> construct<AccClause>(construct<AccClause::UseDevice>(
+                        parenthesized(Parser<AccObjectList>{}))) ||
+    "VECTOR_LENGTH" >> construct<AccClause>(construct<AccClause::VectorLength>(
+                           parenthesized(scalarIntExpr))) ||
+    "VECTOR" >>
+        construct<AccClause>(construct<AccClause::Vector>(maybe(
+            parenthesized(("LENGTH:" >> scalarIntExpr || scalarIntExpr))))) ||
+    "WAIT" >> construct<AccClause>(construct<AccClause::Wait>(
+                  maybe(Parser<AccWaitArgument>{}))) ||
+    "WORKER" >>
+        construct<AccClause>(construct<AccClause::Worker>(maybe(
+            parenthesized(("NUM:" >> scalarIntExpr || scalarIntExpr))))) ||
+    "WRITE" >> construct<AccClause>(construct<AccClause::Auto>()))
+
+TYPE_PARSER(
+    construct<AccObject>(designator) || construct<AccObject>("/" >> name / "/"))
+
+TYPE_PARSER(construct<AccObjectList>(nonemptyList(Parser<AccObject>{})))
+
+TYPE_PARSER(construct<AccObjectListWithModifier>(
+    maybe(Parser<AccDataModifier>{}), Parser<AccObjectList>{}))
+
+TYPE_PARSER(construct<AccWaitArgument>(
+    maybe("DEVNUM:" >> scalarIntExpr / ":"), nonemptyList(scalarIntExpr)))
+
+// 2.9 (1609) size-expr is one of:
+//   int-expr
+TYPE_PARSER(construct<AccSizeExpr>(scalarIntExpr) ||
+    construct<AccSizeExpr>("*" >> maybe(scalarIntExpr)))
+TYPE_PARSER(construct<AccSizeExprList>(nonemptyList(Parser<AccSizeExpr>{})))
+
+// 2.9 (1607) gang-arg is one of:
+//   [num:]int-expr
+//   static:size-expr
+TYPE_PARSER(construct<AccGangArgument>(maybe(scalarIntExpr),
+                maybe(","_tok / "STATIC:" >> Parser<AccSizeExpr>{})) ||
+    construct<AccGangArgument>(maybe("NUM:" >> scalarIntExpr),
+        maybe(","_tok / "STATIC:" >> Parser<AccSizeExpr>{})))
+
+// 2.5.13 Reduction
+TYPE_PARSER(construct<AccReductionOperator>(Parser<DefinedOperator>{}) ||
+    construct<AccReductionOperator>(Parser<ProcedureDesignator>{}))
+
+// 2.5.14 Default clause
+TYPE_PARSER(construct<AccDefaultClause>(
+    parenthesized(first("NONE" >> pure(AccDefaultClause::Arg::None),
+        "PRESENT" >> pure(AccDefaultClause::Arg::Present)))))
+
+// Modifier for copyin, copyout, cache and create
+TYPE_PARSER(construct<AccDataModifier>(
+    first("ZERO:" >> pure(AccDataModifier::Modifier::Zero),
+        "READONLY:" >> pure(AccDataModifier::Modifier::ReadOnly))))
+
+// Combined directives
+TYPE_PARSER(sourced(construct<AccCombinedDirective>(
+    first("KERNELS LOOP" >> pure(llvm::acc::Directive::ACCD_kernels_loop),
+        "PARALLEL LOOP" >> pure(llvm::acc::Directive::ACCD_parallel_loop),
+        "SERIAL LOOP" >> pure(llvm::acc::Directive::ACCD_serial_loop)))))
+
+// Block directives
+TYPE_PARSER(sourced(construct<AccBlockDirective>(
+    first("DATA" >> pure(llvm::acc::Directive::ACCD_data),
+        "HOST_DATA" >> pure(llvm::acc::Directive::ACCD_host_data),
+        "KERNELS" >> pure(llvm::acc::Directive::ACCD_kernels),
+        "PARALLEL" >> pure(llvm::acc::Directive::ACCD_parallel),
+        "SERIAL" >> pure(llvm::acc::Directive::ACCD_serial)))))
+
+// Standalone directives
+TYPE_PARSER(sourced(construct<AccStandaloneDirective>(
+    first("ENTER DATA" >> pure(llvm::acc::Directive::ACCD_enter_data),
+        "EXIT DATA" >> pure(llvm::acc::Directive::ACCD_exit_data),
+        "INIT" >> pure(llvm::acc::Directive::ACCD_init),
+        "SHUTDOWN" >> pure(llvm::acc::Directive::ACCD_shutdown),
+        "SET" >> pure(llvm::acc::Directive::ACCD_set),
+        "UPDATE" >> pure(llvm::acc::Directive::ACCD_update)))))
+
+// Loop directives
+TYPE_PARSER(sourced(construct<AccLoopDirective>(
+    first("LOOP" >> pure(llvm::acc::Directive::ACCD_loop)))))
+
+TYPE_PARSER(construct<AccBeginLoopDirective>(
+    sourced(Parser<AccLoopDirective>{}), Parser<AccClauseList>{}))
+
+TYPE_PARSER(
+    construct<OpenACCLoopConstruct>(sourced(Parser<AccBeginLoopDirective>{})))
+
+// 2.15.1 Routine directive
+TYPE_PARSER(sourced(construct<OpenACCRoutineConstruct>(verbatim("ROUTINE"_tok),
+    maybe(parenthesized(name)), Parser<AccClauseList>{})))
+
+// 2.10 Cache directive
+TYPE_PARSER(sourced(
+    construct<OpenACCCacheConstruct>(sourced(construct<Verbatim>("CACHE"_tok)),
+        parenthesized(Parser<AccObjectListWithModifier>{}))))
+
+// 2.11 Combined constructs
+TYPE_PARSER(startAccLine >> construct<AccEndCombinedDirective>(sourced(
+                                "END"_tok >> Parser<AccCombinedDirective>{})))
+
+TYPE_PARSER(construct<AccBeginCombinedDirective>(
+    sourced(Parser<AccCombinedDirective>{}), Parser<AccClauseList>{}))
+
+TYPE_PARSER(construct<OpenACCCombinedConstruct>(
+    Parser<AccBeginCombinedDirective>{} / endAccLine, block,
+    maybe(Parser<AccEndCombinedDirective>{} / endAccLine)))
+
+// 2.12 Atomic constructs
+TYPE_PARSER(construct<AccEndAtomic>(startAccLine >> "END ATOMIC"_tok))
+
+TYPE_PARSER("ATOMIC" >>
+    construct<AccAtomicRead>(verbatim("READ"_tok) / endAccLine,
+        statement(assignmentStmt), maybe(Parser<AccEndAtomic>{} / endAccLine)))
+
+TYPE_PARSER("ATOMIC" >>
+    construct<AccAtomicWrite>(verbatim("WRITE"_tok) / endAccLine,
+        statement(assignmentStmt), maybe(Parser<AccEndAtomic>{} / endAccLine)))
+
+TYPE_PARSER("ATOMIC" >>
+    construct<AccAtomicUpdate>(maybe(verbatim("UPDATE"_tok)) / endAccLine,
+        statement(assignmentStmt), maybe(Parser<AccEndAtomic>{} / endAccLine)))
+
+TYPE_PARSER("ATOMIC" >>
+    construct<AccAtomicCapture>(verbatim("CAPTURE"_tok) / endAccLine,
+        statement(assignmentStmt), statement(assignmentStmt),
+        Parser<AccEndAtomic>{} / endAccLine))
+
+TYPE_PARSER(construct<OpenACCAtomicConstruct>(Parser<AccAtomicRead>{}) ||
+    construct<OpenACCAtomicConstruct>(Parser<AccAtomicCapture>{}) ||
+    construct<OpenACCAtomicConstruct>(Parser<AccAtomicWrite>{}) ||
+    construct<OpenACCAtomicConstruct>(Parser<AccAtomicUpdate>{}))
+
+// 2.13 Declare constructs
+TYPE_PARSER(sourced(construct<AccDeclarativeDirective>(
+    first("DECLARE" >> pure(llvm::acc::Directive::ACCD_declare)))))
+
+// [Clause, [Clause], ...]
+TYPE_PARSER(sourced(construct<AccClauseList>(
+    many(maybe(","_tok) >> sourced(Parser<AccClause>{})))))
+
+// 2.16.3 Wait directive
+TYPE_PARSER(sourced(construct<OpenACCWaitConstruct>(
+    sourced(construct<Verbatim>("WAIT"_tok)),
+    maybe(parenthesized(Parser<AccWaitArgument>{})), Parser<AccClauseList>{})))
+
+// Block Constructs
+TYPE_PARSER(sourced(construct<AccBeginBlockDirective>(
+    sourced(Parser<AccBlockDirective>{}), Parser<AccClauseList>{})))
+
+TYPE_PARSER(startAccLine >> sourced(construct<AccEndBlockDirective>("END"_tok >>
+                                sourced(Parser<AccBlockDirective>{}))))
+
+TYPE_PARSER(construct<OpenACCBlockConstruct>(
+    Parser<AccBeginBlockDirective>{} / endAccLine, block,
+    Parser<AccEndBlockDirective>{} / endAccLine))
+
+// Standalone constructs
+TYPE_PARSER(construct<OpenACCStandaloneConstruct>(
+    sourced(Parser<AccStandaloneDirective>{}), Parser<AccClauseList>{}))
+
+// Standalone declarative constructs
+TYPE_PARSER(construct<OpenACCStandaloneDeclarativeConstruct>(
+    sourced(Parser<AccDeclarativeDirective>{}), Parser<AccClauseList>{}))
+
+TYPE_PARSER(
+    startAccLine >> sourced(construct<OpenACCDeclarativeConstruct>(
+                        Parser<OpenACCStandaloneDeclarativeConstruct>{})))
+
+// OpenACC constructs
+TYPE_CONTEXT_PARSER("OpenACC construct"_en_US,
+    startAccLine >>
+        first(construct<OpenACCConstruct>(Parser<OpenACCBlockConstruct>{}),
+            construct<OpenACCConstruct>(Parser<OpenACCCombinedConstruct>{}),
+            construct<OpenACCConstruct>(Parser<OpenACCLoopConstruct>{}),
+            construct<OpenACCConstruct>(Parser<OpenACCStandaloneConstruct>{}),
+            construct<OpenACCConstruct>(Parser<OpenACCRoutineConstruct>{}),
+            construct<OpenACCConstruct>(Parser<OpenACCCacheConstruct>{}),
+            construct<OpenACCConstruct>(Parser<OpenACCWaitConstruct>{}),
+            construct<OpenACCConstruct>(Parser<OpenACCAtomicConstruct>{})))
+} // namespace Fortran::parser

diff  --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 41a97ff902d9..a09a5554116f 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -23,10 +23,6 @@ namespace Fortran::parser {
 constexpr auto startOmpLine = skipStuffBeforeStatement >> "!$OMP "_sptok;
 constexpr auto endOmpLine = space >> endOfLine;
 
-template <typename A> constexpr decltype(auto) verbatim(A x) {
-  return sourced(construct<Verbatim>(x));
-}
-
 // OpenMP Clauses
 // 2.15.3.1 DEFAULT (PRIVATE | FIRSTPRIVATE | SHARED | NONE)
 TYPE_PARSER(construct<OmpDefaultClause>(

diff  --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp
index 5e12b5545f0a..d7a7d107878d 100644
--- a/flang/lib/Parser/parsing.cpp
+++ b/flang/lib/Parser/parsing.cpp
@@ -67,6 +67,9 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
   prescanner.set_fixedForm(options.isFixedForm)
       .set_fixedFormColumnLimit(options.fixedFormColumns)
       .AddCompilerDirectiveSentinel("dir$");
+  if (options.features.IsEnabled(LanguageFeature::OpenACC)) {
+    prescanner.AddCompilerDirectiveSentinel("$acc");
+  }
   if (options.features.IsEnabled(LanguageFeature::OpenMP)) {
     prescanner.AddCompilerDirectiveSentinel("$omp");
     prescanner.AddCompilerDirectiveSentinel("$"); // OMP conditional line

diff  --git a/flang/lib/Parser/program-parsers.cpp b/flang/lib/Parser/program-parsers.cpp
index fc2c7c324eb6..9e18c458ea3c 100644
--- a/flang/lib/Parser/program-parsers.cpp
+++ b/flang/lib/Parser/program-parsers.cpp
@@ -60,7 +60,8 @@ TYPE_PARSER(construct<ProgramUnit>(indirect(Parser<Module>{})) ||
 //         [use-stmt]... [import-stmt]... [implicit-part]
 //         [declaration-construct]...
 TYPE_CONTEXT_PARSER("specification part"_en_US,
-    construct<SpecificationPart>(many(openmpDeclarativeConstruct),
+    construct<SpecificationPart>(many(openaccDeclarativeConstruct),
+        many(openmpDeclarativeConstruct),
         many(statement(indirect(Parser<UseStmt>{}))),
         many(unambiguousStatement(indirect(Parser<ImportStmt>{}))),
         implicitPart, many(declarationConstruct)))
@@ -75,10 +76,10 @@ TYPE_CONTEXT_PARSER("specification part"_en_US,
 // are in contexts that impose constraints on the kinds of statements that
 // are allowed, and so we have a variant production for declaration-construct
 // that implements those constraints.
-constexpr auto execPartLookAhead{
-    first(actionStmt >> ok, ompEndLoopDirective >> ok, openmpConstruct >> ok,
-        "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok,
-        "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)};
+constexpr auto execPartLookAhead{first(actionStmt >> ok,
+    ompEndLoopDirective >> ok, openaccConstruct >> ok, openmpConstruct >> ok,
+    "ASSOCIATE ("_tok, "BLOCK"_tok, "SELECT"_tok, "CHANGE TEAM"_sptok,
+    "CRITICAL"_tok, "DO"_tok, "IF ("_tok, "WHERE ("_tok, "FORALL ("_tok)};
 constexpr auto declErrorRecovery{
     stmtErrorRecoveryStart >> !execPartLookAhead >> skipStmtErrorRecovery};
 constexpr auto misplacedSpecificationStmt{Parser<UseStmt>{} >>
@@ -126,7 +127,8 @@ constexpr auto limitedDeclarationConstruct{recovery(
 // specialized error recovery in the event of a spurious executable
 // statement.
 constexpr auto limitedSpecificationPart{inContext("specification part"_en_US,
-    construct<SpecificationPart>(many(openmpDeclarativeConstruct),
+    construct<SpecificationPart>(many(openaccDeclarativeConstruct),
+        many(openmpDeclarativeConstruct),
         many(statement(indirect(Parser<UseStmt>{}))),
         many(unambiguousStatement(indirect(Parser<ImportStmt>{}))),
         implicitPart, many(limitedDeclarationConstruct)))};
@@ -151,6 +153,8 @@ TYPE_CONTEXT_PARSER("specification construct"_en_US,
         construct<SpecificationConstruct>(
             statement(indirect(typeDeclarationStmt))),
         construct<SpecificationConstruct>(indirect(Parser<StructureDef>{})),
+        construct<SpecificationConstruct>(
+            indirect(openaccDeclarativeConstruct)),
         construct<SpecificationConstruct>(indirect(openmpDeclarativeConstruct)),
         construct<SpecificationConstruct>(indirect(compilerDirective))))
 

diff  --git a/flang/lib/Parser/stmt-parser.h b/flang/lib/Parser/stmt-parser.h
index 7dcc1f4620a9..cd1c69beedd4 100644
--- a/flang/lib/Parser/stmt-parser.h
+++ b/flang/lib/Parser/stmt-parser.h
@@ -80,6 +80,7 @@ constexpr auto skipBadLine{SkipPast<'\n'>{} >> construct<ErrorRecovery>()};
 constexpr auto executionPartErrorRecovery{stmtErrorRecoveryStart >>
     !"END"_tok >> !"CONTAINS"_tok >> !"ELSE"_tok >> !"CASE"_tok >>
     !"TYPE IS"_tok >> !"CLASS"_tok >> !"RANK"_tok >>
+    !("!$ACC "_sptok >> "END"_tok) >>
     !("!$OMP "_sptok >> ("END"_tok || "SECTION"_id)) >> skipBadLine};
 
 // END statement error recovery

diff  --git a/flang/lib/Parser/token-parsers.h b/flang/lib/Parser/token-parsers.h
index fe43182e386f..2ad89053fc65 100644
--- a/flang/lib/Parser/token-parsers.h
+++ b/flang/lib/Parser/token-parsers.h
@@ -664,5 +664,9 @@ constexpr auto logicalFALSE{
 constexpr auto rawHollerithLiteral{
     deprecated<LanguageFeature::Hollerith>(HollerithLiteral{})};
 
+template <typename A> constexpr decltype(auto) verbatim(A x) {
+  return sourced(construct<Verbatim>(x));
+}
+
 } // namespace Fortran::parser
 #endif // FORTRAN_PARSER_TOKEN_PARSERS_H_

diff  --git a/flang/lib/Parser/type-parsers.h b/flang/lib/Parser/type-parsers.h
index c7a1bce781ff..a2f38e90db21 100644
--- a/flang/lib/Parser/type-parsers.h
+++ b/flang/lib/Parser/type-parsers.h
@@ -130,6 +130,8 @@ constexpr Parser<EndSubroutineStmt> endSubroutineStmt; // R1537
 constexpr Parser<EntryStmt> entryStmt; // R1541
 constexpr Parser<ContainsStmt> containsStmt; // R1543
 constexpr Parser<CompilerDirective> compilerDirective;
+constexpr Parser<OpenACCConstruct> openaccConstruct;
+constexpr Parser<OpenACCDeclarativeConstruct> openaccDeclarativeConstruct;
 constexpr Parser<OpenMPConstruct> openmpConstruct;
 constexpr Parser<OpenMPDeclarativeConstruct> openmpDeclarativeConstruct;
 constexpr Parser<OmpEndLoopDirective> ompEndLoopDirective;

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 09acaaa37076..99792cbf706f 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1777,6 +1777,375 @@ class UnparseVisitor {
     }
     Walk(std::get<Name>(x.t));
   }
+
+  // OpenACC Directives & Clauses
+  void Unparse(const AccAtomicCapture &x) {
+    BeginOpenACC();
+    Word("!$ACC CAPTURE");
+    Put("\n");
+    EndOpenACC();
+    Walk(std::get<AccAtomicCapture::Stmt1>(x.t));
+    Put("\n");
+    Walk(std::get<AccAtomicCapture::Stmt2>(x.t));
+    BeginOpenACC();
+    Word("!$ACC END ATOMIC\n");
+    EndOpenACC();
+  }
+  void Unparse(const AccAtomicRead &x) {
+    BeginOpenACC();
+    Word("!$ACC ATOMIC READ");
+    Put("\n");
+    EndOpenACC();
+    Walk(std::get<Statement<AssignmentStmt>>(x.t));
+    BeginOpenACC();
+    Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
+    EndOpenACC();
+  }
+  void Unparse(const AccAtomicWrite &x) {
+    BeginOpenACC();
+    Word("!$ACC ATOMIC WRITE");
+    Put("\n");
+    EndOpenACC();
+    Walk(std::get<Statement<AssignmentStmt>>(x.t));
+    BeginOpenACC();
+    Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
+    EndOpenACC();
+  }
+  void Unparse(const AccAtomicUpdate &x) {
+    BeginOpenACC();
+    Word("!$ACC ATOMIC UPDATE");
+    Put("\n");
+    EndOpenACC();
+    Walk(std::get<Statement<AssignmentStmt>>(x.t));
+    BeginOpenACC();
+    Walk(std::get<std::optional<AccEndAtomic>>(x.t), "!$ACC END ATOMIC\n");
+    EndOpenACC();
+  }
+  void Unparse(const llvm::acc::Directive &x) {
+    Word(llvm::acc::getOpenACCDirectiveName(x).str());
+  }
+  void Before(const AccClause::Auto &) { Word("AUTO"); }
+  void Before(const AccClause::Capture &) { Word("CAPTURE"); }
+  void Before(const AccClause::Finalize &) { Word("FINALIZE"); }
+  void Before(const AccClause::IfPresent &) { Word("IF_PRESENT"); }
+  void Before(const AccClause::Independent &) { Word("INDEPENDENT"); }
+  void Before(const AccClause::NoHost &) { Word("NOHOST"); }
+  void Before(const AccClause::Read &) { Word("READ"); }
+  void Before(const AccClause::Seq &) { Word("SEQ"); }
+  void Before(const AccClause::Write &) { Word("WRITE"); }
+  void Before(const AccClause::Unknown &) { Word("UNKNOWN"); }
+  void Unparse(const AccClause::Attach &x) {
+    Word("ATTACH");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Bind &x) {
+    Word("BIND");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Collapse &x) {
+    Word("COLLAPSE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Copy &x) {
+    Word("COPY");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Copyin &x) {
+    Word("COPYIN");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Copyout &x) {
+    Word("COPYOUT");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Create &x) {
+    Word("CREATE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Default &x) {
+    Word("DEFAULT");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Delete &x) {
+    Word("DELETE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Detach &x) {
+    Word("DETACH");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Device &x) {
+    Word("DEVICE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::DevicePtr &x) {
+    Word("DEVICEPTR");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::DeviceResident &x) {
+    Word("DEVICE_RESIDENT");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::FirstPrivate &x) {
+    Word("FIRSTPRIVATE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Host &x) {
+    Word("HOST");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::If &x) {
+    Word("IF");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Link &x) {
+    Word("LINK");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::NumGangs &x) {
+    Word("NUM_GANGS");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::NumWorkers &x) {
+    Word("NUM_WORKERS");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Present &x) {
+    Word("PRESENT");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Private &x) {
+    Word("PRIVATE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Reduction &x) {
+    Word("REDUCTION");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::VectorLength &x) {
+    Word("VECTOR_LENGTH");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Async &x) {
+    Word("ASYNC");
+    Walk("(", x.v, ")");
+  }
+  void Unparse(const AccClause::DefaultAsync &x) {
+    Word("DEFAULT_ASYNC");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::DeviceNum &x) {
+    Word("DEVICE_NUM");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Gang &x) {
+    Word("GANG");
+    Walk("(", x.v, ")");
+  }
+  void Unparse(const AccClause::NoCreate &x) {
+    Word("NO_CREATE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::UseDevice &x) {
+    Word("USE_DEVICE");
+    Put("(");
+    Walk(x.v);
+    Put(")");
+  }
+  void Unparse(const AccClause::Self &x) {
+    Word("SELF");
+    Walk("(", x.v, ")");
+  }
+  void Unparse(const AccClause::Vector &x) {
+    Word("VECTOR");
+    Walk("(", x.v, ")");
+  }
+  void Unparse(const AccClause::Wait &x) {
+    Word("WAIT");
+    Walk("(", x.v, ")");
+  }
+  void Unparse(const AccClause::Worker &x) {
+    Word("WORKER");
+    Walk("(", x.v, ")");
+  }
+  void Unparse(const AccClause::DeviceType &x) {
+    Word("DEVICE_TYPE");
+    Put("(");
+    if (x.v.has_value())
+      Walk(x.v);
+    else
+      Put("*");
+    Put(")");
+  }
+  void Unparse(const AccObjectListWithModifier &x) {
+    Walk(std::get<std::optional<AccDataModifier>>(x.t), ":");
+    Walk(std::get<AccObjectList>(x.t));
+  }
+  void Unparse(const AccDataModifier::Modifier &x) {
+    Word(AccDataModifier::EnumToString(x));
+  }
+  void Unparse(const AccDefaultClause &x) {
+    switch (x.v) {
+    case AccDefaultClause::Arg::None:
+      Put("NONE");
+      break;
+    case AccDefaultClause::Arg::Present:
+      Put("PRESENT");
+      break;
+    }
+  }
+  void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); }
+  void Unparse(const AccGangArgument &x) {
+    Walk("NUM:", std::get<std::optional<ScalarIntExpr>>(x.t));
+    Walk(", STATIC:", std::get<std::optional<AccSizeExpr>>(x.t));
+  }
+  void Unparse(const OpenACCBlockConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ");
+    Walk(std::get<AccBeginBlockDirective>(x.t));
+    Put("\n");
+    EndOpenACC();
+    Walk(std::get<Block>(x.t), "");
+    BeginOpenACC();
+    Word("!$ACC END ");
+    Walk(std::get<AccEndBlockDirective>(x.t));
+    Put("\n");
+    EndOpenACC();
+  }
+  void Unparse(const OpenACCLoopConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ");
+    Walk(std::get<AccBeginLoopDirective>(x.t));
+    Put("\n");
+    EndOpenACC();
+    Walk(std::get<std::optional<DoConstruct>>(x.t));
+  }
+  void Unparse(const AccBeginLoopDirective &x) {
+    Walk(std::get<AccLoopDirective>(x.t));
+    Walk(std::get<AccClauseList>(x.t));
+  }
+  void Unparse(const OpenACCStandaloneConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ");
+    Walk(std::get<AccStandaloneDirective>(x.t));
+    Walk(std::get<AccClauseList>(x.t));
+    Put("\n");
+    EndOpenACC();
+  }
+  void Unparse(const OpenACCStandaloneDeclarativeConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ");
+    Walk(std::get<AccDeclarativeDirective>(x.t));
+    Walk(std::get<AccClauseList>(x.t));
+    Put("\n");
+    EndOpenACC();
+  }
+  void Unparse(const OpenACCCombinedConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ");
+    Walk(std::get<AccBeginCombinedDirective>(x.t));
+    Put("\n");
+    EndOpenACC();
+    Walk(std::get<Block>(x.t), "");
+    BeginOpenACC();
+    Word("!$ACC END ");
+    Walk(std::get<std::optional<AccEndCombinedDirective>>(x.t));
+    Put("\n");
+    EndOpenACC();
+  }
+  void Unparse(const OpenACCRoutineConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ROUTINE");
+    Walk("(", std::get<std::optional<Name>>(x.t), ")");
+    Walk(std::get<AccClauseList>(x.t));
+    Put("\n");
+    EndOpenACC();
+  }
+  void Unparse(const AccObject &x) {
+    std::visit(common::visitors{
+                   [&](const Designator &y) { Walk(y); },
+                   [&](const Name &y) { Put("/"), Walk(y), Put("/"); },
+               },
+        x.u);
+  }
+  void Unparse(const AccObjectList &x) { Walk(x.v, ","); }
+  void Unparse(const AccObjectListWithReduction &x) {
+    Walk(std::get<AccReductionOperator>(x.t));
+    Put(":");
+    Walk(std::get<AccObjectList>(x.t));
+  }
+  void Unparse(const OpenACCCacheConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ");
+    Word("CACHE(");
+    Walk(std::get<AccObjectListWithModifier>(x.t));
+    Put(")");
+    Put("\n");
+    EndOpenACC();
+  }
+  void Unparse(const OpenACCWaitConstruct &x) {
+    BeginOpenACC();
+    Word("!$ACC ");
+    Word("WAIT(");
+    Walk(std::get<std::optional<AccWaitArgument>>(x.t));
+    Walk(std::get<AccClauseList>(x.t));
+    Put(")");
+    Put("\n");
+    EndOpenACC();
+  }
+
   // OpenMP Clauses & Directives
   void Unparse(const OmpObject &x) {
     std::visit(common::visitors{
@@ -2522,6 +2891,8 @@ class UnparseVisitor {
   }
   void BeginOpenMP() { openmpDirective_ = true; }
   void EndOpenMP() { openmpDirective_ = false; }
+  void BeginOpenACC() { openaccDirective_ = true; }
+  void EndOpenACC() { openaccDirective_ = false; }
 
   // Call back to the traversal framework.
   template <typename T> void Walk(const T &x) {
@@ -2591,6 +2962,7 @@ class UnparseVisitor {
   std::set<CharBlock> structureComponents_;
   Encoding encoding_{Encoding::UTF_8};
   bool capitalizeKeywords_{true};
+  bool openaccDirective_{false};
   bool openmpDirective_{false};
   bool backslashEscapes_{false};
   preStatementType *preStatement_{nullptr};
@@ -2599,7 +2971,7 @@ class UnparseVisitor {
 
 void UnparseVisitor::Put(char ch) {
   int sav = indent_;
-  if (openmpDirective_) {
+  if (openmpDirective_ || openaccDirective_) {
     indent_ = 0;
   }
   if (column_ <= 1) {
@@ -2620,13 +2992,16 @@ void UnparseVisitor::Put(char ch) {
     if (openmpDirective_) {
       out_ << "!$OMP&";
       column_ = 8;
+    } else if (openaccDirective_) {
+      out_ << "!$ACC&";
+      column_ = 8;
     } else {
       out_ << '&';
       column_ = indent_ + 3;
     }
   }
   out_ << ch;
-  if (openmpDirective_) {
+  if (openmpDirective_ || openaccDirective_) {
     indent_ = sav;
   }
 }

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 4d70f03dd553..bd566408cd2c 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -6010,7 +6010,8 @@ bool ResolveNamesVisitor::Pre(const parser::SpecificationPart &x) {
   Walk(std::get<1>(x.t));
   Walk(std::get<2>(x.t));
   Walk(std::get<3>(x.t));
-  const std::list<parser::DeclarationConstruct> &decls{std::get<4>(x.t)};
+  Walk(std::get<4>(x.t));
+  const std::list<parser::DeclarationConstruct> &decls{std::get<5>(x.t)};
   for (const auto &decl : decls) {
     if (const auto *spec{
             std::get_if<parser::SpecificationConstruct>(&decl.u)}) {

diff  --git a/flang/test/Semantics/acc-validity.f90 b/flang/test/Semantics/acc-validity.f90
new file mode 100644
index 000000000000..88f62a84d161
--- /dev/null
+++ b/flang/test/Semantics/acc-validity.f90
@@ -0,0 +1,169 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenacc
+
+! Check OpenACC clause validity for the following construct and directive:
+!   2.6.5 Data
+!   2.5.1 Parallel
+!   2.5.2 Kernels
+!   2.5.3 Serial
+!   2.15.1 Routine
+!   2.11 Parallel Loop
+!   2.11 Kernels Loop
+!   2.11 Serial Loop
+
+program openacc_clause_validity
+
+  implicit none
+
+  integer :: i, j
+  integer :: N = 256
+
+  !$acc declare
+  real(8) :: a(256)
+
+  !$acc enter data
+
+  !$acc enter data copyin(zero: i)
+
+  !$acc enter data create(readonly: i)
+
+  !$acc data copyout(readonly: i)
+  !$acc end data
+
+  !$acc enter data copyin(i) copyout(i)
+
+  !$acc data copy(i) if(.true.) if(.true.)
+  !$acc end data
+
+  !$acc exit data
+
+  !$acc host_data
+  !$acc end host_data
+
+  !$acc set
+
+  !$acc data
+  !$acc end data
+
+  !$acc data copyin(i)
+  !$acc end data
+
+  !$acc data copyin(i)
+
+  !$acc end parallel
+
+  !$acc update device(i) device_type(*) async
+
+
+  !$acc update device(i) device_type(*) if(.TRUE.)
+
+  !$acc parallel
+
+  !$acc loop seq independent
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end parallel
+
+  !$acc parallel device_type(*) num_gangs(2)
+  !$acc loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end parallel
+
+  !$acc parallel
+
+  !$acc loop collapse(-1)
+  do i = 1, N
+    do j = 1, N
+      a(i) = 3.14 + j
+    end do
+  end do
+  !$acc end parallel
+
+  !$acc parallel
+
+  !$acc loop device_type(*) private(i)
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end parallel
+
+  !$acc parallel
+
+  !$acc loop gang seq
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end parallel
+
+
+  !$acc parallel device_type(*) if(.TRUE.)
+  !$acc loop
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end parallel
+
+
+  !$acc parallel loop device_type(*) if(.TRUE.)
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end parallel loop
+
+  !$acc kernels device_type(*) async
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end kernels
+
+
+  !$acc kernels device_type(*) if(.TRUE.)
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end kernels
+
+
+  !$acc kernels loop device_type(*) if(.TRUE.)
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end kernels loop
+
+  !$acc serial device_type(*) async
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end serial
+
+
+  !$acc serial device_type(*) if(.TRUE.)
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end serial
+
+
+  !$acc serial loop device_type(*) if(.TRUE.)
+  do i = 1, N
+    a(i) = 3.14
+  end do
+  !$acc end serial loop
+
+ contains
+
+   subroutine sub1(a)
+     real :: a(:)
+
+     !$acc routine
+   end subroutine sub1
+
+   subroutine sub2(a)
+     real :: a(:)
+
+     !$acc routine seq device_type(*) nohost
+   end subroutine sub2
+
+end program openacc_clause_validity
\ No newline at end of file

diff  --git a/flang/tools/f18-parse-demo/CMakeLists.txt b/flang/tools/f18-parse-demo/CMakeLists.txt
index 465873ca00ff..a89e8ae8816c 100644
--- a/flang/tools/f18-parse-demo/CMakeLists.txt
+++ b/flang/tools/f18-parse-demo/CMakeLists.txt
@@ -1,4 +1,5 @@
 set(LLVM_LINK_COMPONENTS
+  FrontendOpenACC
   FrontendOpenMP
   )
 

diff  --git a/flang/tools/f18/CMakeLists.txt b/flang/tools/f18/CMakeLists.txt
index 8738561fe45e..46c38fa43a2e 100644
--- a/flang/tools/f18/CMakeLists.txt
+++ b/flang/tools/f18/CMakeLists.txt
@@ -1,4 +1,5 @@
 set(LLVM_LINK_COMPONENTS
+  FrontendOpenACC
   FrontendOpenMP
   Support
   )
@@ -59,7 +60,7 @@ install(TARGETS f18 DESTINATION bin)
 
 set(FLANG_INTRINSIC_MODULES_DIR ${FLANG_BINARY_DIR}/include/flang)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.sh.in ${CMAKE_BINARY_DIR}/tools/flang/bin/flang @ONLY)
-file(COPY ${CMAKE_BINARY_DIR}/tools/flang/bin/flang DESTINATION ${CMAKE_BINARY_DIR}/bin FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE) 
+file(COPY ${CMAKE_BINARY_DIR}/tools/flang/bin/flang DESTINATION ${CMAKE_BINARY_DIR}/bin FILE_PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE)
 # The flang script to be installed needs a 
diff erent path to the headers.
 set(FLANG_INTRINSIC_MODULES_DIR ${CMAKE_INSTALL_PREFIX}/include/flang)
 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/flang.sh.in ${FLANG_BINARY_DIR}/bin/flang-install.sh @ONLY)

diff  --git a/flang/tools/f18/f18.cpp b/flang/tools/f18/f18.cpp
index 05766a9c6a6d..5f6070a0fe34 100644
--- a/flang/tools/f18/f18.cpp
+++ b/flang/tools/f18/f18.cpp
@@ -468,6 +468,9 @@ int main(int argc, char *const argv[]) {
     } else if (arg == "-Mstandard" || arg == "-std=f95" ||
         arg == "-std=f2003" || arg == "-std=f2008" || arg == "-std=legacy") {
       driver.warnOnNonstandardUsage = true;
+    } else if (arg == "-fopenacc") {
+      options.features.Enable(Fortran::common::LanguageFeature::OpenACC);
+      options.predefinitions.emplace_back("_OPENACC", "201911");
     } else if (arg == "-fopenmp") {
       options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
       options.predefinitions.emplace_back("_OPENMP", "201511");

diff  --git a/llvm/include/llvm/CMakeLists.txt b/llvm/include/llvm/CMakeLists.txt
index 7cf8699aa21e..b46319f24fc8 100644
--- a/llvm/include/llvm/CMakeLists.txt
+++ b/llvm/include/llvm/CMakeLists.txt
@@ -1,6 +1,6 @@
 add_subdirectory(IR)
 add_subdirectory(Support)
-add_subdirectory(Frontend/OpenMP)
+add_subdirectory(Frontend)
 
 # If we're doing an out-of-tree build, copy a module map for generated
 # header files into the build area.

diff  --git a/llvm/include/llvm/Frontend/CMakeLists.txt b/llvm/include/llvm/Frontend/CMakeLists.txt
new file mode 100644
index 000000000000..ea66917b8936
--- /dev/null
+++ b/llvm/include/llvm/Frontend/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_subdirectory(OpenACC)
+add_subdirectory(OpenMP)

diff  --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
index 3c295a1d7c5f..26049ca60db3 100644
--- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
+++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td
@@ -59,6 +59,9 @@ class Clause<string c> {
   // Optional class holding value of the clause in clang AST.
   string clangClass = ?;
 
+  // Optional class holding value of the clause in flang AST.
+  string flangClass = ?;
+
   // Is clause implicit? If clause is set as implicit, the default kind will
   // be return in get<LanguageName>ClauseKind instead of their own kind.
   bit isImplicit = 0;

diff  --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td
new file mode 100644
index 000000000000..0bc0f2481db5
--- /dev/null
+++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td
@@ -0,0 +1,604 @@
+//===-- ACC.td - OpenACC directive definition file ---------*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This is the definition file for OpenACC directives and clauses.
+//
+//===----------------------------------------------------------------------===//
+
+include "llvm/Frontend/Directive/DirectiveBase.td"
+
+//===----------------------------------------------------------------------===//
+// Definition of general OpenACC information
+//===----------------------------------------------------------------------===//
+
+def OpenACC : DirectiveLanguage {
+  let name = "OpenACC";
+  let cppNamespace = "acc"; // final namespace will be llvm::acc
+  let directivePrefix = "ACCD_";
+  let clausePrefix = "ACCC_";
+  let makeEnumAvailableInNamespace = 1;
+  let enableBitmaskEnumInNamespace = 1;
+  let includeHeader = "llvm/Frontend/OpenACC/ACC.h.inc";
+  let clauseEnumSetClass = "AccClauseSet";
+}
+
+//===----------------------------------------------------------------------===//
+// Definition of OpenACC clauses
+//===----------------------------------------------------------------------===//
+
+// 2.9.6
+def ACCC_Auto : Clause<"auto"> {}
+
+// 2.16.1
+def ACCC_Async : Clause<"async"> {
+  let flangClass = "std::optional<ScalarIntExpr>";
+}
+
+// 2.7.11
+def ACCC_Attach : Clause<"attach"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.15.1
+def ACCC_Bind : Clause<"bind"> {
+  let flangClass = "Name";
+}
+
+// 2.12
+def ACCC_Capture : Clause<"capture"> {
+}
+
+// 2.9.1
+def ACCC_Collapse : Clause<"collapse"> {
+  let flangClass = "ScalarIntConstantExpr";
+}
+
+// 2.7.5
+def ACCC_Copy : Clause<"copy"> {
+  let flangClass = "AccObjectList";
+}
+// 2.7.6
+def ACCC_Copyin : Clause<"copyin"> {
+  let flangClass = "AccObjectListWithModifier";
+}
+
+// 2.7.7
+def ACCC_Copyout : Clause<"copyout"> {
+  let flangClass = "AccObjectListWithModifier";
+}
+
+// 2.7.8
+def ACCC_Create : Clause<"create"> {
+  let flangClass = "AccObjectListWithModifier";
+}
+
+// 2.5.14
+def ACCC_Default : Clause<"default"> {
+  let flangClass = "AccDefaultClause";
+}
+
+// 2.4.12
+def ACCC_DefaultAsync : Clause<"default_async"> {
+  let flangClass = "ScalarIntExpr";
+}
+
+// 2.7.10
+def ACCC_Delete : Clause<"delete"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.7.12
+def ACCC_Detach : Clause<"detach"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.14.4
+def ACCC_Device : Clause<"device"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.14.1
+def ACCC_DeviceNum : Clause<"devicenum">  {
+  let flangClass = "ScalarIntConstantExpr";
+}
+
+// 2.7.3
+def ACCC_DevicePtr : Clause<"deviceptr"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.13
+def ACCC_DeviceResident : Clause<"device_resident"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.4
+def ACCC_DeviceType : Clause<"device_type"> {
+  // (DeviceType, "*"
+  let flangClass = "std::optional<std::list<Name>>";
+}
+
+// 2.6.6
+def ACCC_Finalize : Clause<"finalize"> {}
+
+// 2.5.12
+def ACCC_FirstPrivate : Clause<"firstprivate"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.9.2
+def ACCC_Gang : Clause<"gang"> {
+  let flangClass = "std::optional<AccGangArgument>";
+}
+
+// 2.14.4
+def ACCC_Host : Clause<"host"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.5.4
+def ACCC_If : Clause <"if"> {
+  let flangClass = "ScalarLogicalExpr";
+}
+
+// 2.14.4
+def ACCC_IfPresent : Clause<"if_present"> {}
+
+// 2.9.9
+def ACCC_Independent : Clause<"independent"> {}
+
+// 2.13
+def ACCC_Link : Clause<"link"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.7.9
+def ACCC_NoCreate : Clause<"no_create"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.15.1
+def ACCC_NoHost : Clause<"nohost"> {}
+
+// 2.5.8
+def ACCC_NumGangs : Clause<"num_gangs"> {
+  let flangClass = "ScalarIntExpr";
+}
+
+// 2.5.9
+def ACCC_NumWorkers : Clause<"num_workers"> {
+  let flangClass = "ScalarIntExpr";
+}
+
+// 2.7.4
+def ACCC_Present : Clause<"present"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.5.11
+def ACCC_Private : Clause<"private"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.9.7
+def ACCC_Tile : Clause <"tile"> {
+  let flangClass = "AccSizeExprList";
+}
+
+// 2.8.1
+def ACCC_UseDevice : Clause <"use_device"> {
+  let flangClass = "AccObjectList";
+}
+
+// 2.12
+def ACCC_Read : Clause<"read"> {}
+
+// 2.5.13
+def ACCC_Reduction : Clause<"reduction"> {
+  let flangClass = "AccObjectListWithReduction";
+}
+
+// 2.5.5
+def ACCC_Self : Clause<"self"> {
+  let flangClass = "std::optional<ScalarLogicalExpr>";
+}
+
+// 2.9.5
+def ACCC_Seq : Clause<"seq"> {}
+
+// 2.9.4
+def ACCC_Vector : Clause<"vector"> {
+  let flangClass = "std::optional<ScalarIntExpr>";
+}
+
+// 2.5.10
+def ACCC_VectorLength : Clause<"vector_length"> {
+  let flangClass = "ScalarIntExpr";
+}
+
+// 2.16.2
+def ACCC_Wait : Clause<"wait"> {
+  let flangClass = "std::optional<AccWaitArgument>";
+}
+
+// 2.9.3
+def ACCC_Worker: Clause<"worker"> {
+  let flangClass = "std::optional<ScalarIntExpr>";
+}
+
+// 2.12
+def ACCC_Write : Clause<"write"> {}
+
+def ACCC_Unknown : Clause<"unknown"> {
+  let isDefault = 1;
+}
+
+//===----------------------------------------------------------------------===//
+// Definition of OpenACC directives
+//===----------------------------------------------------------------------===//
+
+// 2.12
+def ACC_Atomic : Directive<"atomic"> {}
+
+// 2.6.5
+def ACC_Data : Directive<"data"> {
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_If>
+  ];
+  let requiredClauses = [
+    VersionedClause<ACCC_Attach>,
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_Default>,
+    VersionedClause<ACCC_DevicePtr>,
+    VersionedClause<ACCC_NoCreate>,
+    VersionedClause<ACCC_Present>
+  ];
+}
+
+// 2.13
+def ACC_Declare : Directive<"declare"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_Present>,
+    VersionedClause<ACCC_DevicePtr>,
+    VersionedClause<ACCC_DeviceResident>,
+    VersionedClause<ACCC_Link>
+  ];
+}
+
+// 2.5.2
+def ACC_Kernels : Directive<"kernels"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Attach>,
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_NoCreate>,
+    VersionedClause<ACCC_Present>,
+    VersionedClause<ACCC_DevicePtr>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_Default>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_NumGangs>,
+    VersionedClause<ACCC_NumWorkers>,
+    VersionedClause<ACCC_Self>,
+    VersionedClause<ACCC_VectorLength>,
+    VersionedClause<ACCC_Wait>
+  ];
+}
+
+// 2.5.1
+def ACC_Parallel : Directive<"parallel"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Attach>,
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_DevicePtr>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_NoCreate>,
+    VersionedClause<ACCC_Present>,
+    VersionedClause<ACCC_Private>,
+    VersionedClause<ACCC_FirstPrivate>,
+    VersionedClause<ACCC_Wait>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_Default>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_NumGangs>,
+    VersionedClause<ACCC_NumWorkers>,
+    VersionedClause<ACCC_Reduction>,
+    VersionedClause<ACCC_Self>,
+    VersionedClause<ACCC_VectorLength>
+  ];
+}
+
+// 2.5.3
+def ACC_Serial : Directive<"serial"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Attach>,
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_DevicePtr>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_FirstPrivate>,
+    VersionedClause<ACCC_NoCreate>,
+    VersionedClause<ACCC_Present>,
+    VersionedClause<ACCC_Private>,
+    VersionedClause<ACCC_Wait>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_Default>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_Reduction>,
+    VersionedClause<ACCC_Self>
+  ];
+}
+
+// 2.9
+def ACC_Loop : Directive<"loop"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_Private>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Collapse>,
+    VersionedClause<ACCC_Gang>,
+    VersionedClause<ACCC_Reduction>,
+    VersionedClause<ACCC_Tile>,
+    VersionedClause<ACCC_Vector>,
+    VersionedClause<ACCC_Worker>
+  ];
+  let allowedExclusiveClauses = [
+    VersionedClause<ACCC_Auto>,
+    VersionedClause<ACCC_Independent>,
+    VersionedClause<ACCC_Seq>
+  ];
+}
+
+// 2.10
+def ACC_Cache : Directive<"cache"> {}
+
+// 2.14.1
+def ACC_Init : Directive<"init"> {
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_DeviceNum>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_If>
+  ];
+}
+
+// 2.15.1
+def ACC_Routine : Directive<"routine"> {
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Bind>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_NoHost>
+  ];
+  let requiredClauses = [
+    VersionedClause<ACCC_Gang>,
+    VersionedClause<ACCC_Seq>,
+    VersionedClause<ACCC_Vector>,
+    VersionedClause<ACCC_Worker>
+  ];
+}
+
+// 2.14.3
+def ACC_Set : Directive<"set"> {
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_If>
+  ];
+  let requiredClauses = [
+    VersionedClause<ACCC_DefaultAsync>,
+    VersionedClause<ACCC_DeviceNum>,
+    VersionedClause<ACCC_DeviceType>
+  ];
+}
+
+// 2.14.2
+def ACC_Shutdown : Directive<"shutdown"> {
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_DeviceNum>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_If>
+  ];
+}
+
+// 2.14.4
+def ACC_Update : Directive<"update"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_Wait>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_IfPresent>
+  ];
+  let requiredClauses = [
+    VersionedClause<ACCC_Device>,
+    VersionedClause<ACCC_Host>,
+    VersionedClause<ACCC_Self>
+  ];
+}
+
+// 2.16.3
+def ACC_Wait : Directive<"wait"> {
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_If>
+  ];
+}
+
+// 2.14.6
+def ACC_EnterData : Directive<"enter data"> {
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_Wait>
+  ];
+  let requiredClauses = [
+    VersionedClause<ACCC_Attach>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_Copyin>
+  ];
+}
+
+// 2.14.7
+def ACC_ExitData : Directive<"exit data"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_Wait>,
+    VersionedClause<ACCC_Finalize>
+  ];
+  let requiredClauses = [
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Delete>,
+    VersionedClause<ACCC_Detach>
+  ];
+}
+def ACC_HostData : Directive<"host_data"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_IfPresent>
+  ];
+  let requiredClauses = [
+    VersionedClause<ACCC_UseDevice>
+  ];
+}
+
+// 2.11
+def ACC_KernelsLoop : Directive<"kernels loop"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_NoCreate>,
+    VersionedClause<ACCC_Present>,
+    VersionedClause<ACCC_Private>,
+    VersionedClause<ACCC_DevicePtr>,
+    VersionedClause<ACCC_Attach>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_Collapse>,
+    VersionedClause<ACCC_Default>,
+    VersionedClause<ACCC_Gang>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_Independent>,
+    VersionedClause<ACCC_NumGangs>,
+    VersionedClause<ACCC_NumWorkers>,
+    VersionedClause<ACCC_Reduction>,
+    VersionedClause<ACCC_Self>,
+    VersionedClause<ACCC_Tile>,
+    VersionedClause<ACCC_Vector>,
+    VersionedClause<ACCC_VectorLength>,
+    VersionedClause<ACCC_Wait>,
+    VersionedClause<ACCC_Worker>
+  ];
+  let allowedExclusiveClauses = [
+    VersionedClause<ACCC_Auto>,
+    VersionedClause<ACCC_Independent>,
+    VersionedClause<ACCC_Seq>
+  ];
+}
+
+// 2.11
+def ACC_ParallelLoop : Directive<"parallel loop"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Attach>,
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_DevicePtr>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_FirstPrivate>,
+    VersionedClause<ACCC_NoCreate>,
+    VersionedClause<ACCC_Present>,
+    VersionedClause<ACCC_Private>,
+    VersionedClause<ACCC_Tile>,
+    VersionedClause<ACCC_Wait>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_Collapse>,
+    VersionedClause<ACCC_Default>,
+    VersionedClause<ACCC_Gang>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_NumGangs>,
+    VersionedClause<ACCC_NumWorkers>,
+    VersionedClause<ACCC_Reduction>,
+    VersionedClause<ACCC_Self>,
+    VersionedClause<ACCC_Vector>,
+    VersionedClause<ACCC_VectorLength>,
+    VersionedClause<ACCC_Worker>
+  ];
+  let allowedExclusiveClauses = [
+    VersionedClause<ACCC_Auto>,
+    VersionedClause<ACCC_Independent>,
+    VersionedClause<ACCC_Seq>
+  ];
+}
+
+// 2.11
+def ACC_SerialLoop : Directive<"serial loop"> {
+  let allowedClauses = [
+    VersionedClause<ACCC_Attach>,
+    VersionedClause<ACCC_Copy>,
+    VersionedClause<ACCC_Copyin>,
+    VersionedClause<ACCC_Copyout>,
+    VersionedClause<ACCC_Create>,
+    VersionedClause<ACCC_DevicePtr>,
+    VersionedClause<ACCC_DeviceType>,
+    VersionedClause<ACCC_FirstPrivate>,
+    VersionedClause<ACCC_NoCreate>,
+    VersionedClause<ACCC_Present>,
+    VersionedClause<ACCC_Private>,
+    VersionedClause<ACCC_Wait>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<ACCC_Async>,
+    VersionedClause<ACCC_Collapse>,
+    VersionedClause<ACCC_Default>,
+    VersionedClause<ACCC_Gang>,
+    VersionedClause<ACCC_If>,
+    VersionedClause<ACCC_Reduction>,
+    VersionedClause<ACCC_Self>,
+    VersionedClause<ACCC_Tile>,
+    VersionedClause<ACCC_Vector>,
+    VersionedClause<ACCC_Worker>
+  ];
+  let allowedExclusiveClauses = [
+    VersionedClause<ACCC_Auto>,
+    VersionedClause<ACCC_Independent>,
+    VersionedClause<ACCC_Seq>
+  ];
+}
+
+def ACC_Unknown : Directive<"unknown"> {
+  let isDefault = 1;
+}
\ No newline at end of file

diff  --git a/llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt b/llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt
new file mode 100644
index 000000000000..82cc7cfaccc9
--- /dev/null
+++ b/llvm/include/llvm/Frontend/OpenACC/CMakeLists.txt
@@ -0,0 +1,4 @@
+set(LLVM_TARGET_DEFINITIONS ACC.td)
+tablegen(LLVM ACC.h.inc --gen-directive-decl)
+tablegen(LLVM ACC.cpp.inc --gen-directive-impl)
+add_public_tablegen_target(acc_gen)

diff  --git a/llvm/lib/Frontend/CMakeLists.txt b/llvm/lib/Frontend/CMakeLists.txt
index 9730c8414edf..ea66917b8936 100644
--- a/llvm/lib/Frontend/CMakeLists.txt
+++ b/llvm/lib/Frontend/CMakeLists.txt
@@ -1 +1,2 @@
+add_subdirectory(OpenACC)
 add_subdirectory(OpenMP)

diff  --git a/llvm/lib/Frontend/OpenACC/CMakeLists.txt b/llvm/lib/Frontend/OpenACC/CMakeLists.txt
new file mode 100644
index 000000000000..ba340ab9c561
--- /dev/null
+++ b/llvm/lib/Frontend/OpenACC/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(LLVM_TARGET_DEFINITIONS ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend/OpenACC/ACC.td)
+tablegen(LLVM ACC.cpp --gen-directive-impl)
+add_public_tablegen_target(acc_cpp)
+
+add_llvm_component_library(LLVMFrontendOpenACC
+  ACC.cpp # Generated by tablegen above
+
+  ADDITIONAL_HEADER_DIRS
+  ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend
+  ${LLVM_MAIN_INCLUDE_DIR}/llvm/Frontend/OpenACC
+
+  DEPENDS
+  acc_gen
+  acc_cpp
+)
+
+target_link_libraries(LLVMFrontendOpenACC LLVMSupport)
+

diff  --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td
index b293196d4d55..49df4e67b53d 100644
--- a/llvm/test/TableGen/directive1.td
+++ b/llvm/test/TableGen/directive1.td
@@ -75,6 +75,7 @@ def TDL_DirA : Directive<"dira"> {
 
 // IMPL:       #include "llvm/ADT/StringRef.h"
 // IMPL-NEXT:  #include "llvm/ADT/StringSwitch.h"
+// IMPL-NEXT:  #include "llvm/Support/ErrorHandling.h"
 // IMPL-EMPTY:
 // IMPL-NEXT:  using namespace llvm;
 // IMPL-NEXT:  using namespace tdl;

diff  --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td
index 517c79d45798..e585e11496ef 100644
--- a/llvm/test/TableGen/directive2.td
+++ b/llvm/test/TableGen/directive2.td
@@ -68,6 +68,7 @@ def TDL_DirA : Directive<"dira"> {
 // IMPL-EMPTY:
 // IMPL-NEXT:  #include "llvm/ADT/StringRef.h"
 // IMPL-NEXT:  #include "llvm/ADT/StringSwitch.h"
+// IMPL-NEXT:  #include "llvm/Support/ErrorHandling.h"
 // IMPL-EMPTY:
 // IMPL-NEXT:  using namespace llvm;
 // IMPL-NEXT:  using namespace tdl;

diff  --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp
index ebcd6873205e..2061ff1fdd1a 100644
--- a/llvm/utils/TableGen/DirectiveEmitter.cpp
+++ b/llvm/utils/TableGen/DirectiveEmitter.cpp
@@ -492,6 +492,7 @@ void EmitDirectivesImpl(RecordKeeper &Records, raw_ostream &OS) {
 
   OS << "#include \"llvm/ADT/StringRef.h\"\n";
   OS << "#include \"llvm/ADT/StringSwitch.h\"\n";
+  OS << "#include \"llvm/Support/ErrorHandling.h\"\n";
   OS << "\n";
   OS << "using namespace llvm;\n";
   llvm::SmallVector<StringRef, 2> Namespaces;


        


More information about the llvm-commits mailing list