Skip to content

Commit 132d4f3

Browse files
Correctly handle unroll directives that disable unrolling
1 parent 6807164 commit 132d4f3

File tree

3 files changed

+83
-19
lines changed

3 files changed

+83
-19
lines changed

flang/docs/Directives.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,10 @@ A list of non-standard directives supported by Flang
4545
## Introduction
4646
Directives are commonly used in Fortran programs to specify additional actions
4747
to be performed by the compiler. The directives are always specified with the
48-
`!dir$` or `cdir$` prefix.
48+
`!dir$` or `cdir$` prefix.
4949

5050
## Loop Directives
51+
5152
Some directives are associated with the following construct, for example loop
5253
directives. Directives on loops are used to specify additional transformation to
5354
be performed by the compiler like enabling vectorisation, unrolling, interchange
@@ -57,6 +58,15 @@ Currently loop directives are not accepted in the presence of OpenMP or OpenACC
5758
constructs on the loop. This should be implemented as it is used in some
5859
applications.
5960

61+
### Unrolling Directive `!dir$ unroll [n]`
62+
63+
This directive specifies that the compiler ought to unroll the immediately
64+
folling loop `n` times. When `n` is `0` or `1`, the loop should not be unrolled
65+
at all. When `n` is `2` or greater, the loop should be unrolled exactly `n`
66+
times if possible. When `n` is omitted, the compiler should attempt to fully
67+
unroll the loop. Some compilers accept an optional `=` before the `n` when `n`
68+
is present in the directive. Flang does not.
69+
6070
### Array Expressions
6171
It is to be decided whether loop directives should also be able to be associated
6272
with array expressions.

flang/lib/Lower/Bridge.cpp

Lines changed: 33 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include "flang/Semantics/tools.h"
6464
#include "flang/Support/Version.h"
6565
#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
66+
#include "mlir/IR/BuiltinAttributes.h"
6667
#include "mlir/IR/Matchers.h"
6768
#include "mlir/IR/PatternMatch.h"
6869
#include "mlir/Parser/Parser.h"
@@ -2170,32 +2171,52 @@ class FirConverter : public Fortran::lower::AbstractConverter {
21702171
return builder->createIntegerConstant(loc, controlType, 1); // step
21712172
}
21722173

2174+
// For unroll directives without a value, force full unrolling.
2175+
// For unroll directives with a value, if the value is greater than 1,
2176+
// force unrolling with the given factor. Otherwise, disable unrolling.
2177+
mlir::LLVM::LoopUnrollAttr
2178+
genLoopUnrollAttr(std::optional<std::uint64_t> directiveArg) {
2179+
mlir::BoolAttr falseAttr = mlir::BoolAttr::get(builder->getContext(), false);
2180+
mlir::BoolAttr trueAttr = mlir::BoolAttr::get(builder->getContext(), true);
2181+
mlir::IntegerAttr countAttr;
2182+
mlir::BoolAttr fullUnrollAttr;
2183+
bool shouldUnroll = true;
2184+
if (directiveArg.has_value()) {
2185+
auto unrollingFactor = directiveArg.value();
2186+
if (unrollingFactor == 0 || unrollingFactor == 1) {
2187+
shouldUnroll = false;
2188+
} else {
2189+
countAttr = builder->getIntegerAttr(builder->getI64Type(), unrollingFactor);
2190+
}
2191+
} else {
2192+
fullUnrollAttr = trueAttr;
2193+
}
2194+
2195+
mlir::BoolAttr disableAttr = shouldUnroll ? falseAttr : trueAttr;
2196+
return mlir::LLVM::LoopUnrollAttr::get(
2197+
builder->getContext(), /*disable=*/disableAttr, /*count=*/countAttr, {},
2198+
/*full=*/fullUnrollAttr, {}, {}, {});
2199+
}
2200+
21732201
void addLoopAnnotationAttr(
21742202
IncrementLoopInfo &info,
21752203
llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
2176-
mlir::BoolAttr f = mlir::BoolAttr::get(builder->getContext(), false);
2177-
mlir::BoolAttr t = mlir::BoolAttr::get(builder->getContext(), true);
21782204
mlir::LLVM::LoopVectorizeAttr va;
21792205
mlir::LLVM::LoopUnrollAttr ua;
21802206
bool has_attrs = false;
21812207
for (const auto *dir : dirs) {
21822208
Fortran::common::visit(
21832209
Fortran::common::visitors{
21842210
[&](const Fortran::parser::CompilerDirective::VectorAlways &) {
2211+
mlir::BoolAttr falseAttr =
2212+
mlir::BoolAttr::get(builder->getContext(), false);
21852213
va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
2186-
/*disable=*/f, {}, {},
2187-
{}, {}, {}, {});
2214+
/*disable=*/falseAttr,
2215+
{}, {}, {}, {}, {}, {});
21882216
has_attrs = true;
21892217
},
21902218
[&](const Fortran::parser::CompilerDirective::Unroll &u) {
2191-
mlir::IntegerAttr countAttr;
2192-
if (u.v.has_value()) {
2193-
countAttr = builder->getIntegerAttr(builder->getI64Type(),
2194-
u.v.value());
2195-
}
2196-
ua = mlir::LLVM::LoopUnrollAttr::get(
2197-
builder->getContext(), /*disable=*/f, /*count*/ countAttr,
2198-
{}, /*full*/ u.v.has_value() ? f : t, {}, {}, {});
2219+
ua = genLoopUnrollAttr(u.v);
21992220
has_attrs = true;
22002221
},
22012222
[&](const auto &) {}},

flang/test/Integration/unroll.f90

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,47 @@
33
! CHECK-LABEL: unroll_dir
44
subroutine unroll_dir
55
integer :: a(10)
6-
!dir$ unroll
7-
! CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[ANNOTATION:.*]]
6+
!dir$ unroll
7+
! CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[UNROLL_ENABLE_FULL_ANNO:.*]]
88
do i=1,10
9-
a(i)=i
9+
a(i)=i
1010
end do
1111
end subroutine unroll_dir
1212

13-
! CHECK: ![[ANNOTATION]] = distinct !{![[ANNOTATION]], ![[UNROLL:.*]], ![[UNROLL_FULL:.*]]}
14-
! CHECK: ![[UNROLL]] = !{!"llvm.loop.unroll.enable"}
15-
! CHECK: ![[UNROLL_FULL]] = !{!"llvm.loop.unroll.full"}
13+
! CHECK-LABEL: unroll_dir_0
14+
subroutine unroll_dir_0
15+
integer :: a(10)
16+
!dir$ unroll 0
17+
! CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[UNROLL_DISABLE:.*]]
18+
do i=1,10
19+
a(i)=i
20+
end do
21+
end subroutine unroll_dir_0
22+
23+
! CHECK-LABEL: unroll_dir_1
24+
subroutine unroll_dir_1
25+
integer :: a(10)
26+
!dir$ unroll 1
27+
! CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[UNROLL_DISABLE_ANNO:.*]]
28+
do i=1,10
29+
a(i)=i
30+
end do
31+
end subroutine unroll_dir_1
32+
33+
! CHECK-LABEL: unroll_dir_2
34+
subroutine unroll_dir_2
35+
integer :: a(10)
36+
!dir$ unroll 2
37+
! CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[UNROLL_ENABLE_COUNT_2:.*]]
38+
do i=1,10
39+
a(i)=i
40+
end do
41+
end subroutine unroll_dir_2
1642

43+
! CHECK: ![[UNROLL_ENABLE_FULL_ANNO]] = distinct !{![[UNROLL_ENABLE_FULL_ANNO]], ![[UNROLL_ENABLE:.*]], ![[UNROLL_FULL:.*]]}
44+
! CHECK: ![[UNROLL_ENABLE:.*]] = !{!"llvm.loop.unroll.enable"}
45+
! CHECK: ![[UNROLL_FULL:.*]] = !{!"llvm.loop.unroll.full"}
46+
! CHECK: ![[UNROLL_DISABLE_ANNO]] = distinct !{![[UNROLL_DISABLE_ANNO]], ![[UNROLL_DISABLE:.*]]}
47+
! CHECK: ![[UNROLL_DISABLE]] = !{!"llvm.loop.unroll.disable"}
48+
! CHECK: ![[UNROLL_ENABLE_COUNT_2]] = distinct !{![[UNROLL_ENABLE_COUNT_2]], ![[UNROLL_ENABLE]], ![[UNROLL_COUNT_2:.*]]}
49+
! CHECK: ![[UNROLL_COUNT_2]] = !{!"llvm.loop.unroll.count", i32 2}

0 commit comments

Comments
 (0)