| //===-- 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); |
| } |