blob: c290d17c4400a40142b78a20bbd8000ec566e7ea [file] [edit]
//===-- Lower/Support/LoopAnnotation.cpp ----------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "flang/Lower/Support/LoopAnnotation.h"
#include "flang/Common/idioms.h"
#include "flang/Parser/parse-tree.h"
#include "mlir/IR/BuiltinAttributes.h"
// For unroll directives without a value, force full unrolling.
// For unroll directives with a value, if the value is greater than 1,
// force unrolling with the given factor. Otherwise, disable unrolling.
static mlir::LLVM::LoopUnrollAttr
genLoopUnrollAttr(mlir::MLIRContext *context,
std::optional<std::uint64_t> directiveArg) {
mlir::BoolAttr falseAttr = mlir::BoolAttr::get(context, false);
mlir::BoolAttr trueAttr = mlir::BoolAttr::get(context, true);
mlir::IntegerAttr countAttr;
mlir::BoolAttr fullUnrollAttr;
bool shouldUnroll = true;
if (directiveArg.has_value()) {
auto unrollingFactor = directiveArg.value();
if (unrollingFactor == 0 || unrollingFactor == 1) {
shouldUnroll = false;
} else {
countAttr = mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64),
unrollingFactor);
}
} else {
fullUnrollAttr = trueAttr;
}
mlir::BoolAttr disableAttr = shouldUnroll ? falseAttr : trueAttr;
return mlir::LLVM::LoopUnrollAttr::get(context, /*disable=*/disableAttr,
/*count=*/countAttr, {},
/*full=*/fullUnrollAttr, {}, {}, {});
}
static mlir::LLVM::LoopUnrollAndJamAttr
genLoopUnrollAndJamAttr(mlir::MLIRContext *context,
std::optional<std::uint64_t> count) {
mlir::BoolAttr falseAttr = mlir::BoolAttr::get(context, false);
mlir::BoolAttr trueAttr = mlir::BoolAttr::get(context, true);
mlir::IntegerAttr countAttr;
bool shouldUnroll = true;
if (count.has_value()) {
auto unrollingFactor = count.value();
if (unrollingFactor == 0 || unrollingFactor == 1) {
shouldUnroll = false;
} else {
countAttr = mlir::IntegerAttr::get(mlir::IntegerType::get(context, 64),
unrollingFactor);
}
}
mlir::BoolAttr disableAttr = shouldUnroll ? falseAttr : trueAttr;
return mlir::LLVM::LoopUnrollAndJamAttr::get(context, /*disable=*/disableAttr,
/*count*/ countAttr, {}, {}, {},
{}, {});
}
static mlir::LLVM::LoopVectorizeAttr
genLoopVectorizeAttr(mlir::MLIRContext *context, mlir::BoolAttr disableAttr,
mlir::BoolAttr scalableEnable,
mlir::IntegerAttr vectorWidth) {
mlir::LLVM::LoopVectorizeAttr va;
if (disableAttr)
va = mlir::LLVM::LoopVectorizeAttr::get(context,
/*disable=*/disableAttr,
/*predicate=*/{},
/*scalableEnable=*/scalableEnable,
/*vectorWidth=*/vectorWidth, {}, {},
{});
return va;
}
mlir::LLVM::LoopAnnotationAttr Fortran::lower::genLoopAnnotationAttr(
mlir::MLIRContext *context,
llvm::ArrayRef<const Fortran::parser::CompilerDirective *> dirs) {
mlir::BoolAttr disableVecAttr;
mlir::BoolAttr scalableEnable;
mlir::IntegerAttr vectorWidth;
mlir::LLVM::LoopUnrollAttr ua;
mlir::LLVM::LoopUnrollAndJamAttr uja;
llvm::SmallVector<mlir::LLVM::AccessGroupAttr> aga;
bool hasAttrs = false;
for (const auto *dir : dirs) {
Fortran::common::visit(
Fortran::common::visitors{
[&](const Fortran::parser::CompilerDirective::VectorAlways &) {
disableVecAttr = mlir::BoolAttr::get(context, false);
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::VectorLength &vl) {
using Kind =
Fortran::parser::CompilerDirective::VectorLength::Kind;
Kind kind = std::get<Kind>(vl.t);
uint64_t length = std::get<uint64_t>(vl.t);
disableVecAttr = mlir::BoolAttr::get(context, false);
if (length != 0)
vectorWidth = mlir::IntegerAttr::get(
mlir::IntegerType::get(context, 64), length);
switch (kind) {
case Kind::Scalable:
scalableEnable = mlir::BoolAttr::get(context, true);
break;
case Kind::Fixed:
scalableEnable = mlir::BoolAttr::get(context, false);
break;
case Kind::Auto:
break;
}
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::Unroll &u) {
ua = genLoopUnrollAttr(context, u.v);
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::UnrollAndJam &u) {
uja = genLoopUnrollAndJamAttr(context, u.v);
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::NoVector &) {
disableVecAttr = mlir::BoolAttr::get(context, true);
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::NoUnroll &) {
ua = genLoopUnrollAttr(context, /*directiveArg=*/0);
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::NoUnrollAndJam &) {
uja = genLoopUnrollAndJamAttr(context, /*count=*/0);
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::IVDep &) {
aga.push_back(mlir::LLVM::AccessGroupAttr::get(context));
hasAttrs = true;
},
[&](const Fortran::parser::CompilerDirective::Simd &) {
disableVecAttr = mlir::BoolAttr::get(context, false);
hasAttrs = true;
},
[&](const auto &) {}},
dir->u);
}
if (!hasAttrs)
return {};
mlir::LLVM::LoopVectorizeAttr va = genLoopVectorizeAttr(
context, disableVecAttr, scalableEnable, vectorWidth);
return mlir::LLVM::LoopAnnotationAttr::get(
context, {}, /*vectorize=*/va, {}, /*unroll*/ ua,
/*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {},
/*parallelAccesses*/ aga);
}