-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[flang] Implement !DIR$ IVDEP directive #133728
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?
Changes from all commits
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 |
---|---|---|
|
@@ -2046,6 +2046,37 @@ class FirConverter : public Fortran::lower::AbstractConverter { | |
// so no clean-up needs to be generated for these entities. | ||
} | ||
|
||
// Add attribute(s) on operations in fir::DoLoopOp if necessary. | ||
void attachAttributesToDoLoopOperations(fir::DoLoopOp &doLoop) { | ||
if (!doLoop.getOperation()) | ||
return; | ||
if (auto loopAnnotAttr = doLoop.getLoopAnnotationAttr()) { | ||
if (loopAnnotAttr.getParallelAccesses().size()) { | ||
mlir::LLVM::AccessGroupAttr accessGroupAttr = | ||
loopAnnotAttr.getParallelAccesses().front(); | ||
for (mlir::Block &block : doLoop.getRegion()) { | ||
mlir::ArrayAttr attrs = | ||
mlir::ArrayAttr::get(builder->getContext(), {accessGroupAttr}); | ||
for (mlir::Operation &op : block.getOperations()) { | ||
if (fir::StoreOp storeOp = mlir::dyn_cast<fir::StoreOp>(op)) { | ||
storeOp.setAccessGroupsAttr(attrs); | ||
} else if (fir::LoadOp loadOp = mlir::dyn_cast<fir::LoadOp>(op)) { | ||
loadOp.setAccessGroupsAttr(attrs); | ||
} else if (hlfir::AssignOp assignOp = | ||
mlir::dyn_cast<hlfir::AssignOp>(op)) { | ||
// In some loops, the HLFIR AssignOp operation can be translated | ||
// into FIR operation(s) containing StoreOp. It is therefore | ||
// necessary to forward the AccessGroups attribute. | ||
assignOp.getOperation()->setAttr("access_groups", attrs); | ||
Comment on lines
+2065
to
+2070
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. Tracking everything that could generate a store sounds difficult to maintain in the long term. I wonder if this should instead be added by a pass late in the pipeline after all of these stores have been generated. 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. Adding a pass that checks for all |
||
} else if (fir::CallOp callOp = mlir::dyn_cast<fir::CallOp>(op)) { | ||
callOp.setAccessGroupsAttr(attrs); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
Comment on lines
+2050
to
+2078
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. Do we need to go into operations that are nested inside other operations?
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. Yes, that's right ! So I also have to go through the operations in depth 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. Is
|
||
|
||
/// Generate FIR for a DO construct. There are six variants: | ||
/// - unstructured infinite and while loops | ||
/// - structured and unstructured increment loops | ||
|
@@ -2155,6 +2186,10 @@ class FirConverter : public Fortran::lower::AbstractConverter { | |
|
||
// This call may generate a branch in some contexts. | ||
genFIR(endDoEval, unstructuredContext); | ||
|
||
// Add attribute(s) on operations in fir::DoLoopOp if necessary | ||
for (IncrementLoopInfo &info : incrementLoopNestInfo) | ||
attachAttributesToDoLoopOperations(info.doLoop); | ||
} | ||
|
||
/// Generate FIR to evaluate loop control values (lower, upper and step). | ||
|
@@ -2235,22 +2270,28 @@ class FirConverter : public Fortran::lower::AbstractConverter { | |
{}, {}, {}, {}); | ||
} | ||
|
||
// Enabling loop vectorization attribute. | ||
mlir::LLVM::LoopVectorizeAttr genLoopVectorizeAttr(bool enable = true) { | ||
mlir::BoolAttr disableAttr = | ||
mlir::BoolAttr::get(builder->getContext(), !enable); | ||
return mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(), | ||
/*disable=*/disableAttr, {}, {}, | ||
{}, {}, {}, {}); | ||
} | ||
|
||
void addLoopAnnotationAttr( | ||
IncrementLoopInfo &info, | ||
llvm::SmallVectorImpl<const Fortran::parser::CompilerDirective *> &dirs) { | ||
mlir::LLVM::LoopVectorizeAttr va; | ||
mlir::LLVM::LoopUnrollAttr ua; | ||
mlir::LLVM::LoopUnrollAndJamAttr uja; | ||
llvm::SmallVector<mlir::LLVM::AccessGroupAttr> aga; | ||
bool has_attrs = false; | ||
for (const auto *dir : dirs) { | ||
Fortran::common::visit( | ||
Fortran::common::visitors{ | ||
[&](const Fortran::parser::CompilerDirective::VectorAlways &) { | ||
mlir::BoolAttr falseAttr = | ||
mlir::BoolAttr::get(builder->getContext(), false); | ||
va = mlir::LLVM::LoopVectorizeAttr::get(builder->getContext(), | ||
/*disable=*/falseAttr, | ||
{}, {}, {}, {}, {}, {}); | ||
va = genLoopVectorizeAttr(); | ||
has_attrs = true; | ||
}, | ||
[&](const Fortran::parser::CompilerDirective::Unroll &u) { | ||
|
@@ -2261,12 +2302,19 @@ class FirConverter : public Fortran::lower::AbstractConverter { | |
uja = genLoopUnrollAndJamAttr(u.v); | ||
has_attrs = true; | ||
}, | ||
[&](const Fortran::parser::CompilerDirective::IVDep &iv) { | ||
va = genLoopVectorizeAttr(); | ||
aga.push_back( | ||
mlir::LLVM::AccessGroupAttr::get(builder->getContext())); | ||
has_attrs = true; | ||
}, | ||
[&](const auto &) {}}, | ||
dir->u); | ||
} | ||
mlir::LLVM::LoopAnnotationAttr la = mlir::LLVM::LoopAnnotationAttr::get( | ||
builder->getContext(), {}, /*vectorize=*/va, {}, /*unroll*/ ua, | ||
/*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}); | ||
/*unroll_and_jam*/ uja, {}, {}, {}, {}, {}, {}, {}, {}, {}, | ||
/*parallelAccesses*/ aga); | ||
if (has_attrs) | ||
info.doLoop.setLoopAnnotationAttr(la); | ||
} | ||
|
@@ -2925,6 +2973,9 @@ class FirConverter : public Fortran::lower::AbstractConverter { | |
[&](const Fortran::parser::CompilerDirective::UnrollAndJam &) { | ||
attachDirectiveToLoop(dir, &eval); | ||
}, | ||
[&](const Fortran::parser::CompilerDirective::IVDep &) { | ||
attachDirectiveToLoop(dir, &eval); | ||
}, | ||
[&](const auto &) {}}, | ||
dir.u); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -148,13 +148,17 @@ class AssignOpConversion : public mlir::OpRewritePattern<hlfir::AssignOp> { | |
!assignOp.isTemporaryLHS() && | ||
mlir::isa<fir::RecordType>(fir::getElementTypeOf(lhsExv)); | ||
|
||
std::optional<mlir::ArrayAttr> accessGroups = nullptr; | ||
if (auto attrs = assignOp.getOperation()->getAttrOfType<mlir::ArrayAttr>( | ||
"access_groups")) | ||
accessGroups = attrs; | ||
// genScalarAssignment() must take care of potential overlap | ||
// between LHS and RHS. Note that the overlap is possible | ||
// also for components of LHS/RHS, and the Assign() runtime | ||
// must take care of it. | ||
fir::factory::genScalarAssignment(builder, loc, lhsExv, rhsExv, | ||
needFinalization, | ||
assignOp.isTemporaryLHS()); | ||
fir::factory::genScalarAssignment( | ||
builder, loc, lhsExv, rhsExv, needFinalization, | ||
assignOp.isTemporaryLHS(), accessGroups); | ||
} | ||
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. There are a few other places in this file where 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. I don't think so. The |
||
rewriter.eraseOp(assignOp); | ||
return mlir::success(); | ||
|
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: What is this needed for?
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.
No, I don't need it ! Sorry