[flang-commits] [flang] f5e80c9 - [Flang] Add SIMD Compiler Directive (#192969)

via flang-commits flang-commits at lists.llvm.org
Wed Apr 22 06:54:42 PDT 2026


Author: Jack Styles
Date: 2026-04-22T14:54:37+01:00
New Revision: f5e80c985804783a06f066c84985c6eaab0957aa

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

LOG: [Flang] Add SIMD Compiler Directive (#192969)

Similar to #192674, this adds support for the SIMD Compiler Directive,
previously supported by legacy Fortran frontends such as classic-flang.
This operates in the same way as `VECTORALWAYS`, marking a DO loop to be
vectorised by the LLVM Backend.

The missing support was highlighted while building an opensource
benchmark, as build warnings were indicating that this compiler
directive was being ignored.

Added: 
    flang/test/Lower/simd-directive.f90
    flang/test/Parser/simd-directive.f90
    flang/test/Semantics/simd-directive01.f90

Modified: 
    flang/docs/Directives.md
    flang/include/flang/Parser/dump-parse-tree.h
    flang/include/flang/Parser/parse-tree.h
    flang/lib/Lower/Bridge.cpp
    flang/lib/Parser/Fortran-parsers.cpp
    flang/lib/Parser/unparse.cpp
    flang/lib/Semantics/canonicalize-directives.cpp
    flang/lib/Semantics/resolve-names.cpp

Removed: 
    


################################################################################
diff  --git a/flang/docs/Directives.md b/flang/docs/Directives.md
index 1654a9b2623f2..1ee263e833a7b 100644
--- a/flang/docs/Directives.md
+++ b/flang/docs/Directives.md
@@ -67,6 +67,9 @@ A list of non-standard directives supported by Flang
 * `!dir$ vector always` forces vectorization on the following loop regardless
   of cost model decisions. The loop must still be vectorizable.
   [This directive currently only works on plain do loops without labels].
+* `!dir$ simd` works the same as `vector always` above, but provides an alternative
+  spelling and support for projects which would have used the classic-flang frontend
+  previously.
 * `!dir$ vector vectorlength({fixed|scalable|<num>|<num>,fixed|<num>,scalable})`
   specifies a hint to the compiler about the desired vectorization factor. If
   `fixed` is used, the compiler should prefer fixed-width vectorization.

diff  --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h
index eefab487413da..3002edc0fc5de 100644
--- a/flang/include/flang/Parser/dump-parse-tree.h
+++ b/flang/include/flang/Parser/dump-parse-tree.h
@@ -239,6 +239,7 @@ class ParseTreeDumper {
   NODE(CompilerDirective, NoUnroll)
   NODE(CompilerDirective, NoUnrollAndJam)
   NODE(CompilerDirective, Prefetch)
+  NODE(CompilerDirective, Simd)
   NODE(parser, ComplexLiteralConstant)
   NODE(parser, ComplexPart)
   NODE(parser, ComponentArraySpec)

diff  --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 960ebbcc99efb..dde83e0c71d7c 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3345,6 +3345,7 @@ struct StmtFunctionStmt {
 // !DIR$ INLINE
 // !DIR$ NOINLINE
 // !DIR$ IVDEP
+// !DIR$ SIMD
 // !DIR$ <anything else>
 struct CompilerDirective {
   UNION_CLASS_BOILERPLATE(CompilerDirective);
@@ -3387,12 +3388,13 @@ struct CompilerDirective {
   EMPTY_CLASS(Inline);
   EMPTY_CLASS(NoInline);
   EMPTY_CLASS(IVDep);
+  EMPTY_CLASS(Simd);
   EMPTY_CLASS(Unrecognized);
   CharBlock source;
   std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
       VectorAlways, VectorLength, std::list<NameValue>, Unroll, UnrollAndJam,
       Unrecognized, NoVector, NoUnroll, NoUnrollAndJam, ForceInline, Inline,
-      NoInline, Prefetch, IVDep>
+      NoInline, Prefetch, IVDep, Simd>
       u;
 };
 

diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 655edc8ffa7b3..23bcc077f865b 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2869,6 +2869,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
                     mlir::LLVM::AccessGroupAttr::get(builder->getContext()));
                 has_attrs = true;
               },
+              [&](const Fortran::parser::CompilerDirective::Simd &simd) {
+                disableVecAttr =
+                    mlir::BoolAttr::get(builder->getContext(), false);
+                has_attrs = true;
+              },
               [&](const auto &) {}},
           dir->u);
     }
@@ -3630,6 +3635,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
             [&](const Fortran::parser::CompilerDirective::IVDep &) {
               attachDirectiveToLoop(dir, &eval);
             },
+            [&](const Fortran::parser::CompilerDirective::Simd &) {
+              attachDirectiveToLoop(dir, &eval);
+            },
             [&](const auto &) {}},
         dir.u);
   }

diff  --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp
index b67475074217c..3ad5f0b995219 100644
--- a/flang/lib/Parser/Fortran-parsers.cpp
+++ b/flang/lib/Parser/Fortran-parsers.cpp
@@ -1341,6 +1341,7 @@ constexpr auto noinlineDir{
     "NOINLINE" >> construct<CompilerDirective::NoInline>()};
 constexpr auto inlineDir{"INLINE" >> construct<CompilerDirective::Inline>()};
 constexpr auto ivdep{"IVDEP" >> construct<CompilerDirective::IVDep>()};
+constexpr auto simd{"SIMD" >> construct<CompilerDirective::Simd>()};
 TYPE_PARSER(beginDirective >> some(letter) >> "$ "_tok >>
     sourced((construct<CompilerDirective>(ignore_tkr) ||
                 construct<CompilerDirective>(loopCount) ||
@@ -1356,6 +1357,7 @@ TYPE_PARSER(beginDirective >> some(letter) >> "$ "_tok >>
                 construct<CompilerDirective>(noinlineDir) ||
                 construct<CompilerDirective>(forceinlineDir) ||
                 construct<CompilerDirective>(inlineDir) ||
+                construct<CompilerDirective>(simd) ||
                 construct<CompilerDirective>(ivdep) ||
                 construct<CompilerDirective>(
                     many(construct<CompilerDirective::NameValue>(

diff  --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 5ddd0cfc3a1ef..48a49433d78d0 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -1886,6 +1886,7 @@ class UnparseVisitor {
               Word("!DIR$ NOINLINE");
             },
             [&](const CompilerDirective::IVDep &) { Word("!DIR$ IVDEP"); },
+            [&](const CompilerDirective::Simd &) { Word("!DIR$ SIMD"); },
             [&](const CompilerDirective::Unrecognized &) {
               Word("!DIR$ ");
               Word(x.source.ToString());

diff  --git a/flang/lib/Semantics/canonicalize-directives.cpp b/flang/lib/Semantics/canonicalize-directives.cpp
index f32a3d34c6572..b69d3499ebc53 100644
--- a/flang/lib/Semantics/canonicalize-directives.cpp
+++ b/flang/lib/Semantics/canonicalize-directives.cpp
@@ -66,7 +66,8 @@ static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
       std::holds_alternative<parser::CompilerDirective::ForceInline>(dir.u) ||
       std::holds_alternative<parser::CompilerDirective::Inline>(dir.u) ||
       std::holds_alternative<parser::CompilerDirective::NoInline>(dir.u) ||
-      std::holds_alternative<parser::CompilerDirective::IVDep>(dir.u);
+      std::holds_alternative<parser::CompilerDirective::IVDep>(dir.u) ||
+      std::holds_alternative<parser::CompilerDirective::Simd>(dir.u);
 }
 
 void CanonicalizationOfDirectives::Post(parser::SpecificationPart &spec) {
@@ -143,6 +144,9 @@ void CanonicalizationOfDirectives::Post(parser::Block &block) {
               [&](parser::CompilerDirective::IVDep &) {
                 CheckLoopDirective(*dir, block, it);
               },
+              [&](parser::CompilerDirective::Simd &) {
+                CheckLoopDirective(*dir, block, it);
+              },
               [&](auto &) {}},
           dir->u);
     }

diff  --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 0b8a850f8e4e2..f39650da81053 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10402,7 +10402,8 @@ void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
       std::holds_alternative<parser::CompilerDirective::Inline>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::Prefetch>(x.u) ||
       std::holds_alternative<parser::CompilerDirective::NoInline>(x.u) ||
-      std::holds_alternative<parser::CompilerDirective::IVDep>(x.u)) {
+      std::holds_alternative<parser::CompilerDirective::IVDep>(x.u) ||
+      std::holds_alternative<parser::CompilerDirective::Simd>(x.u)) {
     return;
   }
   if (const auto *tkr{

diff  --git a/flang/test/Lower/simd-directive.f90 b/flang/test/Lower/simd-directive.f90
new file mode 100644
index 0000000000000..3aa159c613831
--- /dev/null
+++ b/flang/test/Lower/simd-directive.f90
@@ -0,0 +1,17 @@
+! Test lowering of SIMD directive to ensure that correct cectorisation flags are
+! applied to the do loops
+
+! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
+
+subroutine test1()
+  integer :: i
+
+  !DIR$ SIMD
+  do i = 1, 10
+  end do
+end subroutine
+
+! CHECK: #[[loop_vec:.*]] = #llvm.loop_vectorize<disable = false>
+! CHECK: #[[loop_annotate:.*]] = #llvm.loop_annotation<vectorize = #[[loop_vec]]>
+
+! CHECK :%[[.*]] = fir.do_loop %[[.*]] = %[[.*]] to %[[.*]] step %[[.*]] iter_args(%arg1 = %[[.*]]) -> (i32) attributes {loopAnnotation = #[[loop_annontate]]} {

diff  --git a/flang/test/Parser/simd-directive.f90 b/flang/test/Parser/simd-directive.f90
new file mode 100644
index 0000000000000..f1c27fb38b7c4
--- /dev/null
+++ b/flang/test/Parser/simd-directive.f90
@@ -0,0 +1,72 @@
+! Test parsing and unparsing of SIMD Directive
+
+! RUN: %flang_fc1 -fdebug-dump-parse-tree %s -o - | FileCheck %s --check-prefix="PARSE-TREE"
+! RUN: %flang_fc1 -fdebug-unparse %s -o - | FileCheck %s --check-prefix="UNPARSE"
+
+subroutine test()
+  integer :: i, n, sum
+  n = 10
+  sum = 0
+
+  !DIR$ SIMD
+  do i = 1, n
+    sum = sum + i
+  end do
+end subroutine
+
+! UNPARSE: SUBROUTINE test
+! UNPARSE:  INTEGER i, n, sum
+! UNPARSE:   n=10_4
+! UNPARSE:   sum=0_4
+! UNPARSE:  !DIR$ SIMD
+! UNPARSE:  DO i=1_4,n
+! UNPARSE:    sum=sum+i
+! UNPARSE:  END DO
+! UNPARSE: END SUBROUTINE
+
+! PARSE-TREE: ======================== Flang: parse tree dump ========================
+! PARSE-TREE: Program -> ProgramUnit -> SubroutineSubprogram
+! PARSE-TREE: | SubroutineStmt
+! PARSE-TREE: | | Name = 'test'
+! PARSE-TREE: | SpecificationPart
+! PARSE-TREE: | | ImplicitPart -> 
+! PARSE-TREE: | | DeclarationConstruct -> SpecificationConstruct -> TypeDeclarationStmt
+! PARSE-TREE: | | | DeclarationTypeSpec -> IntrinsicTypeSpec -> IntegerTypeSpec -> 
+! PARSE-TREE: | | | EntityDecl
+! PARSE-TREE: | | | | Name = 'i'
+! PARSE-TREE: | | | EntityDecl
+! PARSE-TREE: | | | | Name = 'n'
+! PARSE-TREE: | | | EntityDecl
+! PARSE-TREE: | | | | Name = 'sum'
+! PARSE-TREE: | ExecutionPart -> Block
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'n=10_4'
+! PARSE-TREE: | | | Variable = 'n'
+! PARSE-TREE: | | | | Designator -> DataRef -> Name = 'n'
+! PARSE-TREE: | | | Expr = '10_4'
+! PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '10'
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'sum=0_4'
+! PARSE-TREE: | | | Variable = 'sum'
+! PARSE-TREE: | | | | Designator -> DataRef -> Name = 'sum'
+! PARSE-TREE: | | | Expr = '0_4'
+! PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '0'
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> CompilerDirective -> Simd
+! PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> DoConstruct
+! PARSE-TREE: | | | NonLabelDoStmt
+! PARSE-TREE: | | | | LoopControl -> LoopBounds
+! PARSE-TREE: | | | | | Scalar -> Name = 'i'
+! PARSE-TREE: | | | | | Scalar -> Expr = '1_4'
+! PARSE-TREE: | | | | | | LiteralConstant -> IntLiteralConstant = '1'
+! PARSE-TREE: | | | | | Scalar -> Expr = 'n'
+! PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'n'
+! PARSE-TREE: | | | Block
+! PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'sum=sum+i'
+! PARSE-TREE: | | | | | Variable = 'sum'
+! PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'sum'
+! PARSE-TREE: | | | | | Expr = 'sum+i'
+! PARSE-TREE: | | | | | | Add
+! PARSE-TREE: | | | | | | | Expr = 'sum'
+! PARSE-TREE: | | | | | | | | Designator -> DataRef -> Name = 'sum'
+! PARSE-TREE: | | | | | | | Expr = 'i'
+! PARSE-TREE: | | | | | | | | Designator -> DataRef -> Name = 'i'
+! PARSE-TREE: | | | EndDoStmt -> 
+! PARSE-TREE: | EndSubroutineStmt ->

diff  --git a/flang/test/Semantics/simd-directive01.f90 b/flang/test/Semantics/simd-directive01.f90
new file mode 100644
index 0000000000000..2f33654d23ea5
--- /dev/null
+++ b/flang/test/Semantics/simd-directive01.f90
@@ -0,0 +1,9 @@
+! Check that appropriate errors are given when the SIMD Directive is used
+! with no DO loop following
+
+! RUN: %python %S/test_errors.py %s %flang -Werror
+
+subroutine test()
+!WARNING: A DO loop must follow the SIMD directive
+  !DIR$ SIMD
+end subroutine


        


More information about the flang-commits mailing list