Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ class ParseTreeDumper {
NODE(CompilerDirective, NameValue)
NODE(CompilerDirective, Unrecognized)
NODE(CompilerDirective, VectorAlways)
NODE(CompilerDirective, Unroll)
NODE(parser, ComplexLiteralConstant)
NODE(parser, ComplexPart)
NODE(parser, ComponentArraySpec)
Expand Down
5 changes: 4 additions & 1 deletion flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3368,10 +3368,13 @@ struct CompilerDirective {
TUPLE_CLASS_BOILERPLATE(NameValue);
std::tuple<Name, std::optional<std::uint64_t>> t;
};
struct Unroll {
WRAPPER_CLASS_BOILERPLATE(Unroll, std::optional<std::uint64_t>);
};
EMPTY_CLASS(Unrecognized);
CharBlock source;
std::variant<std::list<IgnoreTKR>, LoopCount, std::list<AssumeAligned>,
VectorAlways, std::list<NameValue>, Unrecognized>
VectorAlways, std::list<NameValue>, Unroll, Unrecognized>
u;
};

Expand Down
52 changes: 38 additions & 14 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2153,14 +2153,42 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return builder->createIntegerConstant(loc, controlType, 1); // step
}

void addLoopAnnotationAttr(IncrementLoopInfo &info) {
void addLoopAnnotationAttr(
IncrementLoopInfo &info,
llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) {
mlir::BoolAttr f = mlir::BoolAttr::get(builder->getContext(), false);
mlir::LLVM::LoopVectorizeAttr va = mlir::LLVM::LoopVectorizeAttr::get(
builder->getContext(), /*disable=*/f, {}, {}, {}, {}, {}, {});
mlir::BoolAttr t = mlir::BoolAttr::get(builder->getContext(), true);
mlir::LLVM::LoopVectorizeAttr va;
mlir::LLVM::LoopUnrollAttr ua;
bool has_attrs = false;
for (const auto *dir : dirs) {
Fortran::common::visit(
Fortran::common::visitors{
[&](const Fortran::parser::CompilerDirective::VectorAlways &) {
va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(),
/*disable=*/f, {}, {},
{}, {}, {}, {});
has_attrs = true;
},
[&](const Fortran::parser::CompilerDirective::Unroll &u) {
mlir::IntegerAttr countAttr;
if (u.v.has_value()) {
countAttr = builder->getIntegerAttr(builder->getI64Type(),
u.v.value());
}
ua = mlir::LLVM::LoopUnrollAttr::get(
builder->getContext(), /*disable=*/f, /*count*/ countAttr,
{}, /*full*/ u.v.has_value() ? f : t, {}, {}, {});
has_attrs = true;
},
[&](const auto &) {}},
dir->u);
}
mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get(
builder->getContext(), {}, /*vectorize=*/va, {}, {}, {}, {}, {}, {}, {},
{}, {}, {}, {}, {}, {});
info.doLoop.setLoopAnnotationAttr(la);
builder->getContext(), {}, /*vectorize=*/va, {}, /*unroll*/ ua, {}, {},
{}, {}, {}, {}, {}, {}, {}, {}, {});
if (has_attrs)
info.doLoop.setLoopAnnotationAttr(la);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I think you can just always add the la to the loop, regardless of if there were any attrs; if la is full of empty attrs it will just not do anything. So I don't think we need the has_attrs variable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @DavidTruby , thanks for your feedback! About your question, I added the has_attrs because having moved your loop into this function, if dirs is empty, it will return an empty LoopAnnotationAttr and the attribute {loopAnnotation = #llvm.loop_annotation<>} will be put in the IR on all loops having no attached directives and many Flang tests will fail.

}

/// Generate FIR to begin a structured or unstructured increment loop nest.
Expand Down Expand Up @@ -2259,14 +2287,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
if (info.hasLocalitySpecs())
handleLocalitySpecs(info);

for (const auto *dir : dirs) {
Fortran::common::visit(
Fortran::common::visitors{
[&](const Fortran::parser::CompilerDirective::VectorAlways
&d) { addLoopAnnotationAttr(info); },
[&](const auto &) {}},
dir->u);
}
addLoopAnnotationAttr(info, dirs);
continue;
}

Expand Down Expand Up @@ -2818,6 +2839,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
[&](const Fortran::parser::CompilerDirective::VectorAlways &) {
attachDirectiveToLoop(dir, &eval);
},
[&](const Fortran::parser::CompilerDirective::Unroll &) {
attachDirectiveToLoop(dir, &eval);
},
[&](const auto &) {}},
dir.u);
}
Expand Down
4 changes: 4 additions & 0 deletions flang/lib/Parser/Fortran-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1293,6 +1293,7 @@ TYPE_PARSER(construct<StatOrErrmsg>("STAT =" >> statVariable) ||
// !DIR$ IGNORE_TKR [ [(tkrdmac...)] name ]...
// !DIR$ LOOP COUNT (n1[, n2]...)
// !DIR$ name[=value] [, name[=value]]...
// !DIR$ UNROLL [n]
// !DIR$ <anything else>
constexpr auto ignore_tkr{
"IGNORE_TKR" >> optionalList(construct<CompilerDirective::IgnoreTKR>(
Expand All @@ -1305,11 +1306,14 @@ constexpr auto assumeAligned{"ASSUME_ALIGNED" >>
indirect(designator), ":"_tok >> digitString64))};
constexpr auto vectorAlways{
"VECTOR ALWAYS" >> construct<CompilerDirective::VectorAlways>()};
constexpr auto unroll{
"UNROLL" >> construct<CompilerDirective::Unroll>(maybe(digitString64))};
TYPE_PARSER(beginDirective >> "DIR$ "_tok >>
sourced((construct<CompilerDirective>(ignore_tkr) ||
construct<CompilerDirective>(loopCount) ||
construct<CompilerDirective>(assumeAligned) ||
construct<CompilerDirective>(vectorAlways) ||
construct<CompilerDirective>(unroll) ||
construct<CompilerDirective>(
many(construct<CompilerDirective::NameValue>(
name, maybe(("="_tok || ":"_tok) >> digitString64))))) /
Expand Down
4 changes: 4 additions & 0 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1847,6 +1847,10 @@ class UnparseVisitor {
[&](const std::list<CompilerDirective::NameValue> &names) {
Walk("!DIR$ ", names, " ");
},
[&](const CompilerDirective::Unroll &unroll) {
Word("!DIR$ UNROLL");
Walk(" ", unroll.v);
},
[&](const CompilerDirective::Unrecognized &) {
Word("!DIR$ ");
Word(x.source.ToString());
Expand Down
7 changes: 6 additions & 1 deletion flang/lib/Semantics/canonicalize-directives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ bool CanonicalizeDirectives(
}

static bool IsExecutionDirective(const parser::CompilerDirective &dir) {
return std::holds_alternative<parser::CompilerDirective::VectorAlways>(dir.u);
return std::holds_alternative<parser::CompilerDirective::VectorAlways>(
dir.u) ||
std::holds_alternative<parser::CompilerDirective::Unroll>(dir.u);
}

void CanonicalizationOfDirectives::Post(parser::SpecificationPart &spec) {
Expand Down Expand Up @@ -110,6 +112,9 @@ void CanonicalizationOfDirectives::Post(parser::Block &block) {
common::visitors{[&](parser::CompilerDirective::VectorAlways &) {
CheckLoopDirective(*dir, block, it);
},
[&](parser::CompilerDirective::Unroll &) {
CheckLoopDirective(*dir, block, it);
},
[&](auto &) {}},
dir->u);
}
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Semantics/resolve-names.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9245,7 +9245,8 @@ void ResolveNamesVisitor::Post(const parser::AssignedGotoStmt &x) {
}

void ResolveNamesVisitor::Post(const parser::CompilerDirective &x) {
if (std::holds_alternative<parser::CompilerDirective::VectorAlways>(x.u)) {
if (std::holds_alternative<parser::CompilerDirective::VectorAlways>(x.u) ||
std::holds_alternative<parser::CompilerDirective::Unroll>(x.u)) {
return;
}
if (const auto *tkr{
Expand Down
16 changes: 16 additions & 0 deletions flang/test/Integration/unroll.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
! RUN: %flang_fc1 -emit-llvm -o - %s | FileCheck %s

! CHECK-LABEL: unroll_dir
subroutine unroll_dir
integer :: a(10)
!dir$ unroll
! CHECK: br i1 {{.*}}, label {{.*}}, label {{.*}}, !llvm.loop ![[ANNOTATION:.*]]
do i=1,10
a(i)=i
end do
end subroutine unroll_dir

! CHECK: ![[ANNOTATION]] = distinct !{![[ANNOTATION]], ![[UNROLL:.*]], ![[UNROLL_FULL:.*]]}
! CHECK: ![[UNROLL]] = !{!"llvm.loop.unroll.enable"}
! CHECK: ![[UNROLL_FULL]] = !{!"llvm.loop.unroll.full"}

27 changes: 27 additions & 0 deletions flang/test/Lower/unroll.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
! RUN: %flang_fc1 -emit-hlfir -o - %s | FileCheck %s

! CHECK: #loop_unroll = #llvm.loop_unroll<disable = false, full = true>
! CHECK: #loop_annotation = #llvm.loop_annotation<unroll = #loop_unroll>

! CHECK-LABEL: unroll_dir
subroutine unroll_dir
integer :: a(10)
!dir$ unroll
!CHECK: fir.do_loop {{.*}} attributes {loopAnnotation = #loop_annotation}
do i=1,10
a(i)=i
end do
end subroutine unroll_dir


! CHECK-LABEL: intermediate_directive
subroutine intermediate_directive
integer :: a(10)
!dir$ unroll
!dir$ unknown
!CHECK: fir.do_loop {{.*}} attributes {loopAnnotation = #loop_annotation}
do i=1,10
a(i)=i
end do
end subroutine intermediate_directive

11 changes: 11 additions & 0 deletions flang/test/Parser/compiler-directives.f90
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,14 @@ subroutine vector_always
do i=1,10
enddo
end subroutine

subroutine unroll
!dir$ unroll
! CHECK: !DIR$ UNROLL
do i=1,10
enddo
!dir$ unroll 2
! CHECK: !DIR$ UNROLL 2
do i=1,10
enddo
end subroutine
16 changes: 16 additions & 0 deletions flang/test/Semantics/loop-directives.f90
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,24 @@
subroutine empty
! WARNING: A DO loop must follow the VECTOR ALWAYS directive
!dir$ vector always
! WARNING: A DO loop must follow the UNROLL directive
!dir$ unroll
end subroutine empty

subroutine non_do
! WARNING: A DO loop must follow the VECTOR ALWAYS directive
!dir$ vector always
! WARNING: A DO loop must follow the UNROLL directive
!dir$ unroll
a = 1
end subroutine non_do

subroutine execution_part
do i=1,10
! WARNING: A DO loop must follow the VECTOR ALWAYS directive
!dir$ vector always
! WARNING: A DO loop must follow the UNROLL directive
!dir$ unroll
end do
end subroutine execution_part

Expand All @@ -28,3 +34,13 @@ subroutine test_vector_always_before_acc(a, b, c)
a(i) = b(i) + c(i)
enddo
end subroutine

! OK
subroutine test_unroll_before_acc(a, b, c)
real, dimension(10) :: a,b,c
!dir$ unroll
!$acc loop
do i=1,N
a(i) = b(i) + c(i)
enddo
end subroutine
Loading