[flang-commits] [flang] [Flang] Add SIMD Compiler Directive (PR #192969)
via flang-commits
flang-commits at lists.llvm.org
Mon Apr 20 06:27:31 PDT 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-fir-hlfir
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