[flang-commits] [flang] [Flang] Add SIMD Compiler Directive (PR #192969)
Jack Styles via flang-commits
flang-commits at lists.llvm.org
Mon Apr 20 06:29:28 PDT 2026
https://github.com/Stylie777 updated https://github.com/llvm/llvm-project/pull/192969
>From 7670f5d1b91472a6d83a59d943a432b44e0923bf Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Wed, 1 Apr 2026 16:34:53 +0100
Subject: [PATCH 1/2] [Flang] Add `SIMD` Compiler Directive
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.
---
flang/docs/Directives.md | 3 +
flang/include/flang/Parser/dump-parse-tree.h | 1 +
flang/include/flang/Parser/parse-tree.h | 4 +-
flang/lib/Lower/Bridge.cpp | 8 +++
flang/lib/Parser/Fortran-parsers.cpp | 2 +
flang/lib/Parser/unparse.cpp | 1 +
.../lib/Semantics/canonicalize-directives.cpp | 6 +-
flang/lib/Semantics/resolve-names.cpp | 3 +-
flang/test/Lower/simd-directive.f90 | 17 +++++
flang/test/Parser/simd-directive.f90 | 72 +++++++++++++++++++
flang/test/Semantics/simd-directive01.f90 | 9 +++
11 files changed, 123 insertions(+), 3 deletions(-)
create mode 100644 flang/test/Lower/simd-directive.f90
create mode 100644 flang/test/Parser/simd-directive.f90
create mode 100644 flang/test/Semantics/simd-directive01.f90
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
>From 75f8c5b56e8f37db72a41032688a4aeaa0c5c5df Mon Sep 17 00:00:00 2001
From: Jack Styles <jack.styles at arm.com>
Date: Mon, 20 Apr 2026 14:28:33 +0100
Subject: [PATCH 2/2] format
---
flang/lib/Lower/Bridge.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index a6ba4d82aa8bd..60ae5f73f6e50 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -3591,7 +3591,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
[&](const Fortran::parser::CompilerDirective::IVDep &) {
attachDirectiveToLoop(dir, &eval);
},
- [&] (const Fortran::parser::CompilerDirective::Simd &) {
+ [&](const Fortran::parser::CompilerDirective::Simd &) {
attachDirectiveToLoop(dir, &eval);
},
[&](const auto &) {}},
More information about the flang-commits
mailing list