-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[flang][OpenMP] Enable tiling #143715
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[flang][OpenMP] Enable tiling #143715
Changes from all commits
ae81104
dc9506e
99f125e
20b9903
6d56b99
69f0d94
13ddc87
6056202
6ddacf5
b3a1da2
cf6b1d6
9d886dd
323527d
d87797c
8c70c88
531fe64
2923141
5939e18
583e042
219595f
356c166
955ccf6
a0501d0
aea0767
5dca0a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ | |
#include "Utils.h" | ||
|
||
#include "ClauseFinder.h" | ||
#include "flang/Evaluate/fold.h" | ||
#include "flang/Lower/OpenMP/Clauses.h" | ||
#include <flang/Lower/AbstractConverter.h> | ||
#include <flang/Lower/ConvertType.h> | ||
|
@@ -24,10 +25,30 @@ | |
#include <flang/Parser/parse-tree.h> | ||
#include <flang/Parser/tools.h> | ||
#include <flang/Semantics/tools.h> | ||
#include <flang/Semantics/type.h> | ||
#include <llvm/Support/CommandLine.h> | ||
|
||
#include <iterator> | ||
|
||
using namespace Fortran::semantics; | ||
|
||
template <typename T> | ||
MaybeIntExpr EvaluateIntExpr(SemanticsContext &context, const T &expr) { | ||
if (MaybeExpr maybeExpr{ | ||
Fold(context.foldingContext(), AnalyzeExpr(context, expr))}) { | ||
if (auto *intExpr{Fortran::evaluate::UnwrapExpr<SomeIntExpr>(*maybeExpr)}) { | ||
return std::move(*intExpr); | ||
} | ||
} | ||
return std::nullopt; | ||
} | ||
|
||
template <typename T> | ||
std::optional<std::int64_t> EvaluateInt64(SemanticsContext &context, | ||
const T &expr) { | ||
return Fortran::evaluate::ToInt64(EvaluateIntExpr(context, expr)); | ||
} | ||
|
||
llvm::cl::opt<bool> treatIndexAsSection( | ||
"openmp-treat-index-as-section", | ||
llvm::cl::desc("In the OpenMP data clauses treat `a(N)` as `a(N:N)`."), | ||
|
@@ -38,14 +59,21 @@ namespace lower { | |
namespace omp { | ||
|
||
int64_t getCollapseValue(const List<Clause> &clauses) { | ||
auto iter = llvm::find_if(clauses, [](const Clause &clause) { | ||
return clause.id == llvm::omp::Clause::OMPC_collapse; | ||
}); | ||
if (iter != clauses.end()) { | ||
const auto &collapse = std::get<clause::Collapse>(iter->u); | ||
return evaluate::ToInt64(collapse.v).value(); | ||
int64_t collapseValue = 1; | ||
int64_t numTileSizes = 0; | ||
for (auto &clause : clauses) { | ||
if (clause.id == llvm::omp::Clause::OMPC_collapse) { | ||
const auto &collapse = std::get<clause::Collapse>(clause.u); | ||
collapseValue = evaluate::ToInt64(collapse.v).value(); | ||
} else if (clause.id == llvm::omp::Clause::OMPC_sizes) { | ||
const auto &sizes = std::get<clause::Sizes>(clause.u); | ||
numTileSizes = sizes.v.size(); | ||
} | ||
Comment on lines
+65
to
+71
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This mixes the directive that collapse goes on (DO, DISTRIBUTE, ..) and those sizes goes on (TILE). During resolving merge conflicts of #145917 and #144785 the approach of handling tile like a compound construct already caused problems. E.g. it could be So it will need to be tangled apart eventually, and I would appreciate if we could avoid the assumption that there is just one |
||
} | ||
return 1; | ||
|
||
collapseValue = collapseValue - numTileSizes; | ||
int64_t result = collapseValue > numTileSizes ? collapseValue : numTileSizes; | ||
return result; | ||
Comment on lines
+74
to
+76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain to me why we need this calculation? To see the effect of this, I tried replacing these few lines with simply There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The general thing this computes is the number of loops that need to be considered in the source code. If you have collapse(4) on a loop nest with 2 loops that would be incorrect since we can max collapse 2 loops. However tiling creates new loops, so collapse(4) would theoretically be legal if tiling is done first e.g. tile(5,10) since that will result in 4 loops. This is not really testable though since collapse requires independent loops, which is only true for the 2 outer loops after tiling is done. There is a check for this, and an error message is given if the collapse value is larger than the number of loops that are tiled to prevent incorrect code. We could just use numTileSizes if that is present, but if collapse could handle dependent loops in the future the above calculation should be the correct one. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
} | ||
|
||
void genObjectList(const ObjectList &objects, | ||
|
@@ -608,11 +636,52 @@ static void convertLoopBounds(lower::AbstractConverter &converter, | |
} | ||
} | ||
|
||
// Populates the sizes vector with values if the given OpenMPConstruct | ||
// Contains a loop construct with an inner tiling construct. | ||
void collectTileSizesFromOpenMPConstruct( | ||
const parser::OpenMPConstruct *ompCons, | ||
llvm::SmallVectorImpl<int64_t> &tileSizes, SemanticsContext &semaCtx) { | ||
if (!ompCons) | ||
return; | ||
|
||
if (auto *ompLoop{std::get_if<parser::OpenMPLoopConstruct>(&ompCons->u)}) { | ||
const auto &nestedOptional = | ||
std::get<std::optional<parser::NestedConstruct>>(ompLoop->t); | ||
assert(nestedOptional.has_value() && | ||
"Expected a DoConstruct or OpenMPLoopConstruct"); | ||
const auto *innerConstruct = | ||
std::get_if<common::Indirection<parser::OpenMPLoopConstruct>>( | ||
&(nestedOptional.value())); | ||
if (innerConstruct) { | ||
const auto &innerLoopDirective = innerConstruct->value(); | ||
const auto &innerBegin = | ||
std::get<parser::OmpBeginLoopDirective>(innerLoopDirective.t); | ||
const auto &innerDirective = | ||
std::get<parser::OmpLoopDirective>(innerBegin.t).v; | ||
|
||
if (innerDirective == llvm::omp::Directive::OMPD_tile) { | ||
// Get the size values from parse tree and convert to a vector | ||
const auto &innerClauseList{ | ||
std::get<parser::OmpClauseList>(innerBegin.t)}; | ||
for (const auto &clause : innerClauseList.v) | ||
if (const auto tclause{ | ||
std::get_if<parser::OmpClause::Sizes>(&clause.u)}) { | ||
for (auto &tval : tclause->v) { | ||
if (const auto v{EvaluateInt64(semaCtx, tval)}) | ||
tileSizes.push_back(*v); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
bool collectLoopRelatedInfo( | ||
lower::AbstractConverter &converter, mlir::Location currentLocation, | ||
lower::pft::Evaluation &eval, const omp::List<omp::Clause> &clauses, | ||
mlir::omp::LoopRelatedClauseOps &result, | ||
llvm::SmallVectorImpl<const semantics::Symbol *> &iv) { | ||
|
||
bool found = false; | ||
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); | ||
|
||
|
@@ -629,6 +698,42 @@ bool collectLoopRelatedInfo( | |
found = true; | ||
} | ||
|
||
// Collect sizes from tile directive if present | ||
std::int64_t sizesLengthValue = 0l; | ||
if (auto *ompCons{eval.getIf<parser::OpenMPConstruct>()}) { | ||
if (auto *ompLoop{std::get_if<parser::OpenMPLoopConstruct>(&ompCons->u)}) { | ||
const auto &nestedOptional = | ||
std::get<std::optional<parser::NestedConstruct>>(ompLoop->t); | ||
assert(nestedOptional.has_value() && | ||
"Expected a DoConstruct or OpenMPLoopConstruct"); | ||
const auto *innerConstruct = | ||
std::get_if<common::Indirection<parser::OpenMPLoopConstruct>>( | ||
&(nestedOptional.value())); | ||
if (innerConstruct) { | ||
const auto &innerLoopDirective = innerConstruct->value(); | ||
const auto &innerBegin = | ||
std::get<parser::OmpBeginLoopDirective>(innerLoopDirective.t); | ||
const auto &innerDirective = | ||
std::get<parser::OmpLoopDirective>(innerBegin.t).v; | ||
|
||
if (innerDirective == llvm::omp::Directive::OMPD_tile) { | ||
// Get the size values from parse tree and convert to a vector | ||
const auto &innerClauseList{ | ||
std::get<parser::OmpClauseList>(innerBegin.t)}; | ||
for (const auto &clause : innerClauseList.v) | ||
if (const auto tclause{ | ||
std::get_if<parser::OmpClause::Sizes>(&clause.u)}) { | ||
sizesLengthValue = tclause->v.size(); | ||
found = true; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
collapseValue = collapseValue - sizesLengthValue; | ||
collapseValue = | ||
collapseValue < sizesLengthValue ? sizesLengthValue : collapseValue; | ||
std::size_t loopVarTypeSize = 0; | ||
do { | ||
lower::pft::Evaluation *doLoop = | ||
|
@@ -661,7 +766,6 @@ bool collectLoopRelatedInfo( | |
} while (collapseValue > 0); | ||
|
||
convertLoopBounds(converter, currentLocation, result, loopVarTypeSize); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] unrelated change |
||
return found; | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: Extra whitespace