[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.
This commit is contained in:
parent
a623bd9135
commit
f5e80c9858
11 changed files with 123 additions and 3 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ public:
|
|||
NODE(CompilerDirective, NoUnroll)
|
||||
NODE(CompilerDirective, NoUnrollAndJam)
|
||||
NODE(CompilerDirective, Prefetch)
|
||||
NODE(CompilerDirective, Simd)
|
||||
NODE(parser, ComplexLiteralConstant)
|
||||
NODE(parser, ComplexPart)
|
||||
NODE(parser, ComponentArraySpec)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -2869,6 +2869,11 @@ private:
|
|||
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 @@ private:
|
|||
[&](const Fortran::parser::CompilerDirective::IVDep &) {
|
||||
attachDirectiveToLoop(dir, &eval);
|
||||
},
|
||||
[&](const Fortran::parser::CompilerDirective::Simd &) {
|
||||
attachDirectiveToLoop(dir, &eval);
|
||||
},
|
||||
[&](const auto &) {}},
|
||||
dir.u);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>(
|
||||
|
|
|
|||
|
|
@ -1886,6 +1886,7 @@ public:
|
|||
Word("!DIR$ NOINLINE");
|
||||
},
|
||||
[&](const CompilerDirective::IVDep &) { Word("!DIR$ IVDEP"); },
|
||||
[&](const CompilerDirective::Simd &) { Word("!DIR$ SIMD"); },
|
||||
[&](const CompilerDirective::Unrecognized &) {
|
||||
Word("!DIR$ ");
|
||||
Word(x.source.ToString());
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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{
|
||||
|
|
|
|||
17
flang/test/Lower/simd-directive.f90
Normal file
17
flang/test/Lower/simd-directive.f90
Normal file
|
|
@ -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]]} {
|
||||
72
flang/test/Parser/simd-directive.f90
Normal file
72
flang/test/Parser/simd-directive.f90
Normal file
|
|
@ -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 ->
|
||||
9
flang/test/Semantics/simd-directive01.f90
Normal file
9
flang/test/Semantics/simd-directive01.f90
Normal file
|
|
@ -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
|
||||
Loading…
Reference in a new issue