Skip to content

Commit 5ccf8c9

Browse files
authored
[flang] implement VECTOR VECTORLENGTH directive (#170114)
This should match exactly the llvm attributes generated by classic flang.
1 parent 114ca65 commit 5ccf8c9

File tree

10 files changed

+183
-8
lines changed

10 files changed

+183
-8
lines changed

flang/docs/Directives.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,15 @@ A list of non-standard directives supported by Flang
5757
* `!dir$ vector always` forces vectorization on the following loop regardless
5858
of cost model decisions. The loop must still be vectorizable.
5959
[This directive currently only works on plain do loops without labels].
60+
* `!dir$ vector vectorlength({fixed|scalable|<num>|<num>,fixed|<num>,scalable})`
61+
specifies a hint to the compiler about the desired vectorization factor. If
62+
`fixed` is used, the compiler should prefer fixed-width vectorization.
63+
Scalable vectorization instructions may still be used with a fixed-width
64+
predicate. If `scalable` is used the compiler should prefer scalable
65+
vectorization, though it can choose to use fixed length vectorization or not
66+
at all. `<num>` means that the compiler should consider using this specific
67+
vectorization factor, which should be an integer literal. This directive
68+
currently has the same limitations as `!dir$ vector always`.
6069
* `!dir$ unroll [n]` specifies that the compiler ought to unroll the immediately
6170
following loop `n` times. When `n` is `0` or `1`, the loop should not be unrolled
6271
at all. When `n` is `2` or greater, the loop should be unrolled exactly `n`

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,8 @@ class ParseTreeDumper {
229229
NODE(CompilerDirective, NoInline)
230230
NODE(CompilerDirective, Unrecognized)
231231
NODE(CompilerDirective, VectorAlways)
232+
NODE_ENUM(CompilerDirective::VectorLength, VectorLength::Kind)
233+
NODE(CompilerDirective, VectorLength)
232234
NODE(CompilerDirective, Unroll)
233235
NODE(CompilerDirective, UnrollAndJam)
234236
NODE(CompilerDirective, NoVector)

flang/include/flang/Parser/parse-tree.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,12 @@ struct CompilerDirective {
33843384
std::tuple<common::Indirection<Designator>, uint64_t> t;
33853385
};
33863386
EMPTY_CLASS(VectorAlways);
3387+
struct VectorLength {
3388+
TUPLE_CLASS_BOILERPLATE(VectorLength);
3389+
ENUM_CLASS(Kind, Auto, Fixed, Scalable);
3390+
3391+
std::tuple<std::uint64_t, Kind> t;
3392+
};
33873393
struct NameValue {
33883394
TUPLE_CLASS_BOILERPLATE(NameValue);
33893395
std::tuple<Name, std::optional<std::uint64_t>> t;
@@ -3408,9 +3414,9 @@ struct CompilerDirective {
34083414
EMPTY_CLASS(Unrecognized);
34093415
CharBlock source;
34103416
std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
3411-
VectorAlways, std::list<NameValue>, Unroll, UnrollAndJam, Unrecognized,
3412-
NoVector, NoUnroll, NoUnrollAndJam, ForceInline, Inline, NoInline,
3413-
Prefetch, IVDep>
3417+
VectorAlways, VectorLength, std::list<NameValue>, Unroll, UnrollAndJam,
3418+
Unrecognized, NoVector, NoUnroll, NoUnrollAndJam, ForceInline, Inline,
3419+
NoInline, Prefetch, IVDep>
34143420
u;
34153421
};
34163422

flang/lib/Lower/Bridge.cpp

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2584,19 +2584,25 @@ class FirConverter : public Fortran::lower::AbstractConverter {
25842584

25852585
// Enabling loop vectorization attribute.
25862586
mlir::LLVM::LoopVectorizeAttr
2587-
genLoopVectorizeAttr(mlir::BoolAttr disableAttr) {
2587+
genLoopVectorizeAttr(mlir::BoolAttr disableAttr,
2588+
mlir::BoolAttr scalableEnable,
2589+
mlir::IntegerAttr vectorWidth) {
25882590
mlir::LLVM::LoopVectorizeAttr va;
25892591
if (disableAttr)
2590-
va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
2591-
/*disable=*/disableAttr, {}, {},
2592-
{}, {}, {}, {});
2592+
va = mlir::LLVM::LoopVectorizeAttr::get(
2593+
builder->getContext(),
2594+
/*disable=*/disableAttr, /*predicate=*/{},
2595+
/*scalableEnable=*/scalableEnable,
2596+
/*vectorWidth=*/vectorWidth, {}, {}, {});
25932597
return va;
25942598
}
25952599

25962600
void addLoopAnnotationAttr(
25972601
IncrementLoopInfo &info,
25982602
llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
25992603
mlir::BoolAttr disableVecAttr;
2604+
mlir::BoolAttr scalableEnable;
2605+
mlir::IntegerAttr vectorWidth;
26002606
mlir::LLVM::LoopUnrollAttr ua;
26012607
mlir::LLVM::LoopUnrollAndJamAttr uja;
26022608
llvm::SmallVector<mlir::LLVM::AccessGroupAttr> aga;
@@ -2609,6 +2615,30 @@ class FirConverter : public Fortran::lower::AbstractConverter {
26092615
mlir::BoolAttr::get(builder->getContext(), false);
26102616
has_attrs = true;
26112617
},
2618+
[&](const Fortran::parser::CompilerDirective::VectorLength &vl) {
2619+
using Kind =
2620+
Fortran::parser::CompilerDirective::VectorLength::Kind;
2621+
Kind kind = std::get<Kind>(vl.t);
2622+
uint64_t length = std::get<uint64_t>(vl.t);
2623+
disableVecAttr =
2624+
mlir::BoolAttr::get(builder->getContext(), false);
2625+
if (length != 0)
2626+
vectorWidth =
2627+
builder->getIntegerAttr(builder->getI64Type(), length);
2628+
switch (kind) {
2629+
case Kind::Scalable:
2630+
scalableEnable =
2631+
mlir::BoolAttr::get(builder->getContext(), true);
2632+
break;
2633+
case Kind::Fixed:
2634+
scalableEnable =
2635+
mlir::BoolAttr::get(builder->getContext(), false);
2636+
break;
2637+
case Kind::Auto:
2638+
break;
2639+
}
2640+
has_attrs = true;
2641+
},
26122642
[&](const Fortran::parser::CompilerDirective::Unroll &u) {
26132643
ua = genLoopUnrollAttr(u.v);
26142644
has_attrs = true;
@@ -2640,7 +2670,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
26402670
[&](const auto &) {}},
26412671
dir->u);
26422672
}
2643-
mlir::LLVM::LoopVectorizeAttr va = genLoopVectorizeAttr(disableVecAttr);
2673+
mlir::LLVM::LoopVectorizeAttr va =
2674+
genLoopVectorizeAttr(disableVecAttr, scalableEnable, vectorWidth);
26442675
mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get(
26452676
builder->getContext(), {}, /*vectorize=*/va, {}, /*unroll*/ ua,
26462677
/*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {},
@@ -3347,6 +3378,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
33473378
[&](const Fortran::parser::CompilerDirective::VectorAlways &) {
33483379
attachDirectiveToLoop(dir, &eval);
33493380
},
3381+
[&](const Fortran::parser::CompilerDirective::VectorLength &) {
3382+
attachDirectiveToLoop(dir, &eval);
3383+
},
33503384
[&](const Fortran::parser::CompilerDirective::Unroll &) {
33513385
attachDirectiveToLoop(dir, &eval);
33523386
},

flang/lib/Parser/Fortran-parsers.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,7 @@ TYPE_PARSER(construct<StatOrErrmsg>("STAT =" >> statVariable) ||
12951295
// Directives, extensions, and deprecated statements
12961296
// !DIR$ IGNORE_TKR [ [(tkrdmac...)] name ]...
12971297
// !DIR$ LOOP COUNT (n1[, n2]...)
1298+
// !DIR$ VECTOR VECTORLENGTH ({FIXED|SCALABLE|<num>|<num>,FIXED|<num>,SCALABLE})
12981299
// !DIR$ name[=value] [, name[=value]]...
12991300
// !DIR$ UNROLL [n]
13001301
// !DIR$ PREFETCH designator[, designator]...
@@ -1311,6 +1312,15 @@ constexpr auto assumeAligned{"ASSUME_ALIGNED" >>
13111312
indirect(designator), ":"_tok >> digitString64))};
13121313
constexpr auto vectorAlways{
13131314
"VECTOR ALWAYS" >> construct<CompilerDirective::VectorAlways>()};
1315+
constexpr auto vectorLengthKind{
1316+
"FIXED" >> pure(CompilerDirective::VectorLength::Kind::Fixed) ||
1317+
"SCALABLE" >> pure(CompilerDirective::VectorLength::Kind::Scalable)};
1318+
constexpr auto vectorLength{"VECTOR VECTORLENGTH" >>
1319+
parenthesized(construct<CompilerDirective::VectorLength>(
1320+
digitString64, ","_tok >> vectorLengthKind) ||
1321+
construct<CompilerDirective::VectorLength>(pure(0), vectorLengthKind) ||
1322+
construct<CompilerDirective::VectorLength>(
1323+
digitString64, pure(CompilerDirective::VectorLength::Kind::Auto)))};
13141324
constexpr auto unroll{
13151325
"UNROLL" >> construct<CompilerDirective::Unroll>(maybe(digitString64))};
13161326
constexpr auto prefetch{"PREFETCH" >>
@@ -1332,6 +1342,7 @@ TYPE_PARSER(beginDirective >> "DIR$ "_tok >>
13321342
construct<CompilerDirective>(loopCount) ||
13331343
construct<CompilerDirective>(assumeAligned) ||
13341344
construct<CompilerDirective>(vectorAlways) ||
1345+
construct<CompilerDirective>(vectorLength) ||
13351346
construct<CompilerDirective>(unrollAndJam) ||
13361347
construct<CompilerDirective>(unroll) ||
13371348
construct<CompilerDirective>(prefetch) ||

flang/lib/Parser/unparse.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,25 @@ class UnparseVisitor {
18481848
[&](const CompilerDirective::VectorAlways &valways) {
18491849
Word("!DIR$ VECTOR ALWAYS");
18501850
},
1851+
[&](const CompilerDirective::VectorLength &vlength) {
1852+
using Kind = CompilerDirective::VectorLength::Kind;
1853+
std::uint64_t length = std::get<std::uint64_t>(vlength.t);
1854+
Kind kind = std::get<Kind>(vlength.t);
1855+
1856+
Word("!DIR$ VECTOR VECTORLENGTH (");
1857+
// || kind == Kind::Auto handles the case of VECTORLENGTH(0) so we
1858+
// don't print nothing
1859+
if (length != 0 || kind == Kind::Auto) {
1860+
Walk(length);
1861+
}
1862+
if (length != 0 && kind != Kind::Auto) {
1863+
Word(", ");
1864+
}
1865+
if (kind != Kind::Auto) {
1866+
Word(CompilerDirective::VectorLength::EnumToString(kind));
1867+
}
1868+
Word(")");
1869+
},
18511870
[&](const std::list<CompilerDirective::NameValue> &names) {
18521871
Walk("!DIR$ ", names, " ");
18531872
},

flang/lib/Semantics/canonicalize-directives.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ bool CanonicalizeDirectives(
5656
static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
5757
return std::holds_alternative<parser::CompilerDirective::VectorAlways>(
5858
dir.u) ||
59+
std::holds_alternative<parser::CompilerDirective::VectorLength>(dir.u) ||
5960
std::holds_alternative<parser::CompilerDirective::Unroll>(dir.u) ||
6061
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(dir.u) ||
6162
std::holds_alternative<parser::CompilerDirective::NoVector>(dir.u) ||
@@ -121,6 +122,9 @@ void CanonicalizationOfDirectives::Post(parser::Block &block) {
121122
common::visitors{[&](parser::CompilerDirective::VectorAlways &) {
122123
CheckLoopDirective(*dir, block, it);
123124
},
125+
[&](parser::CompilerDirective::VectorLength &) {
126+
CheckLoopDirective(*dir, block, it);
127+
},
124128
[&](parser::CompilerDirective::Unroll &) {
125129
CheckLoopDirective(*dir, block, it);
126130
},

flang/lib/Semantics/resolve-names.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10075,6 +10075,7 @@ void ResolveNamesVisitor::Post(const parser::AssignedGotoStmt &x) {
1007510075

1007610076
void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
1007710077
if (std::holds_alternative<parser::CompilerDirective::VectorAlways>(x.u) ||
10078+
std::holds_alternative<parser::CompilerDirective::VectorLength>(x.u) ||
1007810079
std::holds_alternative<parser::CompilerDirective::Unroll>(x.u) ||
1007910080
std::holds_alternative<parser::CompilerDirective::UnrollAndJam>(x.u) ||
1008010081
std::holds_alternative<parser::CompilerDirective::NoVector>(x.u) ||

flang/test/Lower/vectorlength.f90

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s
2+
3+
! CHECK: #[[FIXED:.*]] = #llvm.loop_vectorize<disable = false, scalableEnable = false>
4+
! CHECK: #[[SCALABLE:.*]] = #llvm.loop_vectorize<disable = false, scalableEnable = true>
5+
! CHECK: #[[WIDTH2:.*]] = #llvm.loop_vectorize<disable = false, width = 2 : i64>
6+
! CHECK: #[[FIXED_WIDTH2:.*]] = #llvm.loop_vectorize<disable = false, scalableEnable = false, width = 2 : i64>
7+
! CHECK: #[[SCALABLE_WIDTH2:.*]] = #llvm.loop_vectorize<disable = false, scalableEnable = true, width = 2 : i64>
8+
! CHECK: #[[FIXED_TAG:.*]] = #llvm.loop_annotation<vectorize = #[[FIXED]]>
9+
! CHECK: #[[SCALABLE_TAG:.*]] = #llvm.loop_annotation<vectorize = #[[SCALABLE]]>
10+
! CHECK: #[[WIDTH2_TAG:.*]] = #llvm.loop_annotation<vectorize = #[[WIDTH2]]>
11+
! CHECK: #[[FIXED_WIDTH2_TAG:.*]] = #llvm.loop_annotation<vectorize = #[[FIXED_WIDTH2]]>
12+
! CHECK: #[[SCALABLE_WIDTH2_TAG:.*]] = #llvm.loop_annotation<vectorize = #[[SCALABLE_WIDTH2]]>
13+
14+
! CHECK-LABEL: func.func @_QPfixed(
15+
subroutine fixed(a, b, m)
16+
integer :: i, m, a(m), b(m)
17+
18+
!dir$ vector vectorlength(fixed)
19+
! CHECK: fir.do_loop {{.*}} attributes {loopAnnotation = #[[FIXED_TAG]]}
20+
do i = 1, m
21+
b(i) = a(i) + 1
22+
end do
23+
end subroutine
24+
25+
! CHECK-LABEL: func.func @_QPscalable(
26+
subroutine scalable(a, b, m)
27+
integer :: i, m, a(m), b(m)
28+
29+
!dir$ vector vectorlength(scalable)
30+
! CHECK: fir.do_loop {{.*}} attributes {loopAnnotation = #[[SCALABLE_TAG]]}
31+
do i = 1, m
32+
b(i) = a(i) + 1
33+
end do
34+
end subroutine
35+
36+
! CHECK-LABEL: func.func @_QPlen2(
37+
subroutine len2(a, b, m)
38+
integer :: i, m, a(m), b(m)
39+
40+
!dir$ vector vectorlength(2)
41+
! CHECK: fir.do_loop {{.*}} attributes {loopAnnotation = #[[WIDTH2_TAG]]}
42+
do i = 1, m
43+
b(i) = a(i) + 1
44+
end do
45+
end subroutine
46+
47+
! CHECK-LABEL: func.func @_QPlen2fixed(
48+
subroutine len2fixed(a, b, m)
49+
integer :: i, m, a(m), b(m)
50+
51+
!dir$ vector vectorlength(2,fixed)
52+
! CHECK: fir.do_loop {{.*}} attributes {loopAnnotation = #[[FIXED_WIDTH2_TAG]]}
53+
do i = 1, m
54+
b(i) = a(i) + 1
55+
end do
56+
end subroutine
57+
58+
! CHECK-LABEL: func.func @_QPlen2scalable(
59+
subroutine len2scalable(a, b, m)
60+
integer :: i, m, a(m), b(m)
61+
62+
!dir$ vector vectorlength(2,scalable)
63+
! CHECK: fir.do_loop {{.*}} attributes {loopAnnotation = #[[SCALABLE_WIDTH2_TAG]]}
64+
do i = 1, m
65+
b(i) = a(i) + 1
66+
end do
67+
end subroutine

flang/test/Parser/compiler-directives.f90

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,28 @@ subroutine vector_always
3636
enddo
3737
end subroutine
3838

39+
subroutine vector_vectorlength
40+
!dir$ vector vectorlength(fixed)
41+
! CHECK: !DIR$ VECTOR VECTORLENGTH (FIXED)
42+
do i=1,10
43+
enddo
44+
45+
!dir$ vector vectorlength(scalable)
46+
! CHECK: !DIR$ VECTOR VECTORLENGTH (SCALABLE)
47+
do i=1,10
48+
enddo
49+
50+
!dir$ vector vectorlength(8,scalable)
51+
! CHECK: !DIR$ VECTOR VECTORLENGTH (8, SCALABLE)
52+
do i=1,10
53+
enddo
54+
55+
!dir$ vector vectorlength(4)
56+
! CHECK: !DIR$ VECTOR VECTORLENGTH (4)
57+
do i=1,10
58+
enddo
59+
end subroutine
60+
3961
subroutine unroll
4062
!dir$ unroll
4163
! CHECK: !DIR$ UNROLL

0 commit comments

Comments
 (0)