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

via flang-commits flang-commits at lists.llvm.org
Mon Apr 20 06:27:32 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-parser

Author: Jack Styles (Stylie777)

<details>
<summary>Changes</summary>

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.

---
Full diff: https://github.com/llvm/llvm-project/pull/192969.diff


11 Files Affected:

- (modified) flang/docs/Directives.md (+3) 
- (modified) flang/include/flang/Parser/dump-parse-tree.h (+1) 
- (modified) flang/include/flang/Parser/parse-tree.h (+3-1) 
- (modified) flang/lib/Lower/Bridge.cpp (+8) 
- (modified) flang/lib/Parser/Fortran-parsers.cpp (+2) 
- (modified) flang/lib/Parser/unparse.cpp (+1) 
- (modified) flang/lib/Semantics/canonicalize-directives.cpp (+5-1) 
- (modified) flang/lib/Semantics/resolve-names.cpp (+2-1) 
- (added) flang/test/Lower/simd-directive.f90 (+17) 
- (added) flang/test/Parser/simd-directive.f90 (+72) 
- (added) flang/test/Semantics/simd-directive01.f90 (+9) 


``````````diff
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 28c82a6ca99ce..a6ba4d82aa8bd 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2825,6 +2825,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);
     }
@@ -3586,6 +3591,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 e1c1167af1604..c0e726ae4b5b4 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -10279,7 +10279,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..a89d6b31937b6
--- /dev/null
+++ b/flang/test/Lower/simd-directive.f90
@@ -0,0 +1,17 @@
+! Test Flang lowering of SIMD Directive to ensure the correct Vectorisation 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..fbc3591476c2d
--- /dev/null
+++ b/flang/test/Parser/simd-directive.f90
@@ -0,0 +1,72 @@
+! Test parsing an unparsing of SIMD Directibe
+
+! 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

``````````

</details>


https://github.com/llvm/llvm-project/pull/192969


More information about the flang-commits mailing list