69#include "llvm/ADT/STLExtras.h"
70#include "llvm/ADT/SetVector.h"
71#include "llvm/Support/Debug.h"
75#define GEN_PASS_DEF_ACCIFCLAUSELOWERING
76#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
80#define DEBUG_TYPE "acc-if-clause-lowering"
86class ACCIfClauseLowering
88 using ACCIfClauseLoweringBase<ACCIfClauseLowering>::ACCIfClauseLoweringBase;
91 ACCIfClauseLoweringBase<ACCIfClauseLowering>::getDependentDialects(
101 template <
typename OpTy>
103 lowerIfClauseForComputeConstruct(OpTy computeConstructOp,
108 void runOnOperation()
override;
111void ACCIfClauseLowering::convertHostRegion(
Operation *computeOp,
116 if (isa<acc::OpenACCDialect>(op->getDialect()))
117 hostOps.push_back(op);
127 accSupport->
emitNYI(computeOp->
getLoc(),
"failed to convert host region");
132template <
typename OpTy>
133void ACCIfClauseLowering::lowerIfClauseForComputeConstruct(
136 Value ifCond = computeConstructOp.getIfCond();
142 LLVM_DEBUG(llvm::dbgs() <<
"Converting " << computeConstructOp->getName()
143 <<
" with if condition: " << computeConstructOp
156 auto isExternallyOwned = [&](
Operation *dataOp) {
158 if (!isa<ACC_DATA_EXIT_OPS>(user) && user != computeConstructOp &&
159 !computeConstructOp->isAncestor(user))
165 for (
Value operand : computeConstructOp.getDataClauseOperands())
166 if (
Operation *defOp = operand.getDefiningOp())
167 if (isa<ACC_DATA_ENTRY_OPS>(defOp))
168 dataEntryOps.insert(defOp);
173 for (
Operation *dataEntryOp : llvm::reverse(dataEntryOps))
174 if (!isExternallyOwned(dataEntryOp))
176 if (isa<ACC_DATA_EXIT_OPS>(user))
177 dataExitOps.insert(user);
181 for (
Value operand : operands)
182 if (
Operation *defOp = operand.getDefiningOp())
183 ops.push_back(defOp);
185 collectOps(firstprivateOps, computeConstructOp.getFirstprivateOperands());
186 collectOps(privateOps, computeConstructOp.getPrivateOperands());
187 collectOps(reductionOps, computeConstructOp.getReductionOperands());
190 auto ifOp = scf::IfOp::create(rewriter, computeConstructOp.getLoc(),
193 LLVM_DEBUG(llvm::dbgs() <<
"Cloning " << dataEntryOps.size()
194 <<
" data entry operations for device path\n");
197 Block &thenBlock = ifOp.getThenRegion().
front();
212 operands.push_back(clonedOp->
getResult(0));
213 deviceMapping.
map(op->getResult(0), clonedOp->
getResult(0));
219 if (isExternallyOwned(op))
222 deviceMapping.
map(op->getResult(0), clonedOp->
getResult(0));
226 for (
Value operand : computeConstructOp.getDataClauseOperands())
228 cloneAndMapOps(firstprivateOps, firstprivateOperands);
229 cloneAndMapOps(privateOps, privateOperands);
230 cloneAndMapOps(reductionOps, reductionOperands);
234 OpTy newComputeOp = cast<OpTy>(
235 rewriter.
clone(*computeConstructOp.getOperation(), deviceMapping));
236 newComputeOp.getIfCondMutable().clear();
237 newComputeOp.getDataClauseOperandsMutable().assign(deviceDataOperands);
238 newComputeOp.getFirstprivateOperandsMutable().assign(firstprivateOperands);
239 newComputeOp.getPrivateOperandsMutable().assign(privateOperands);
240 newComputeOp.getReductionOperandsMutable().assign(reductionOperands);
245 rewriter.
clone(*dataOp, deviceMapping);
249 scf::YieldOp::create(rewriter, computeConstructOp.getLoc());
252 Region &hostRegion = computeConstructOp.getRegion();
255 ifOp.getElseRegion().takeBody(hostRegion);
258 Block &elseBlock = ifOp.getElseRegion().
front();
261 scf::YieldOp::create(rewriter, computeConstructOp.getLoc());
263 convertHostRegion(computeConstructOp, ifOp.getElseRegion());
267 Block &elseBlock = ifOp.getElseRegion().
front();
271 hostRegion, hostMapping, computeConstructOp.getLoc(), rewriter);
272 convertHostRegion(computeConstructOp, hostExecuteRegion.getRegion());
276 eraseOps.insert(computeConstructOp);
281 eraseOps.insert(dataOp);
285 Region &elseRegion = ifOp.getElseRegion();
286 auto replaceHostUsesAndScheduleErase = [&](
auto &ops) {
291 condEraseOps.insert(op);
294 replaceHostUsesAndScheduleErase(dataEntryOps);
295 replaceHostUsesAndScheduleErase(firstprivateOps);
296 replaceHostUsesAndScheduleErase(privateOps);
297 replaceHostUsesAndScheduleErase(reductionOps);
300void ACCIfClauseLowering::runOnOperation() {
301 func::FuncOp funcOp = getOperation();
302 accSupport = &getAnalysis<OpenACCSupport>();
307 if (
auto parallelOp = dyn_cast<acc::ParallelOp>(op))
308 lowerIfClauseForComputeConstruct(parallelOp, eraseOps, condEraseOps);
309 else if (
auto kernelsOp = dyn_cast<acc::KernelsOp>(op))
310 lowerIfClauseForComputeConstruct(kernelsOp, eraseOps, condEraseOps);
311 else if (
auto serialOp = dyn_cast<acc::SerialOp>(op))
312 lowerIfClauseForComputeConstruct(serialOp, eraseOps, condEraseOps);
315 for (
Operation *op : llvm::reverse(eraseOps))
324 for (
size_t i = pendingEraseOps.size(); i > 0; --i) {
328 pendingEraseOps.erase(pendingEraseOps.begin() + i - 1);
Block represents an ordered list of Operations.
Operation * getTerminator()
Get the terminator operation of this block.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
This class allows control over how the GreedyPatternRewriteDriver works.
GreedyRewriteConfig & setUseTopDownTraversal(bool use=true)
GreedyRewriteConfig & setStrictness(GreedyRewriteStrictness mode)
This is a utility class for mapping one set of IR entities to another.
auto lookupOrDefault(T from) const
Lookup a mapped value within the map.
void map(Value from, Value to)
Inserts a new mapping for 'from' to 'to'.
This class coordinates rewriting a piece of IR outside of a pattern rewrite, providing a way to keep ...
Operation * clone(Operation &op, IRMapping &mapper)
Creates a deep copy of the specified operation, remapping any operands that use values outside of the...
void setInsertionPointToStart(Block *block)
Sets the insertion point to the start of the specified block.
void setInsertionPoint(Block *block, Block::iterator insertPoint)
Set the insertion point to the specified location.
void setInsertionPointToEnd(Block *block)
Sets the insertion point to the end of the specified block.
void setInsertionPointAfter(Operation *op)
Sets the insertion point to the node after the specified operation, which will cause subsequent inser...
This class represents an operand of an operation.
This class implements the operand iterators for the Operation class.
Operation is the basic unit of execution within MLIR.
bool use_empty()
Returns true if this operation has no uses.
OpResult getResult(unsigned idx)
Get the 'idx'th result of this operation.
Location getLoc()
The source location the operation was defined or derived from.
user_range getUsers()
Returns a range of all users.
Region * getParentRegion()
Returns the region to which the instruction belongs.
MLIRContext * getContext()
Return the context this operation is associated with.
void erase()
Remove this operation from its parent block and delete it.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
bool isAncestor(Region *other)
Return true if this region is ancestor of the other region.
bool hasOneBlock()
Return true if this region has exactly one block.
RetT walk(FnT &&callback)
Walk all nested operations, blocks or regions (including this region), depending on the type of callb...
This class provides an abstraction over the various different ranges of value types.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool replaceUsesWithIf(Value newValue, function_ref< bool(OpOperand &)> shouldReplace)
Replace all uses of 'this' value with 'newValue' if the given callback returns true.
InFlightDiagnostic emitNYI(Location loc, const Twine &message)
Report a case that is not yet supported by the implementation.
Operation * getOwner() const
Return the owner of this operand.
mlir::Value getAccVar(mlir::Operation *accDataClauseOp)
Used to obtain the accVar from a data clause operation.
mlir::Value getVar(mlir::Operation *accDataClauseOp)
Used to obtain the var from a data clause operation.
scf::ExecuteRegionOp wrapMultiBlockRegionWithSCFExecuteRegion(Region ®ion, IRMapping &mapping, Location loc, RewriterBase &rewriter)
Wrap a multi-block region in an scf.execute_region.
void populateACCHostFallbackPatterns(RewritePatternSet &patterns, OpenACCSupport &accSupport, bool enableLoopConversion=true)
Populates all patterns for host fallback path (when if clause evaluates to false).
void registerAllExtensions(DialectRegistry ®istry)
Register the standard OpenACC models for GPU, LLVM and MemRef IR.
Include the generated interface declarations.
LogicalResult applyOpPatternsGreedily(ArrayRef< Operation * > ops, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr, bool *allErased=nullptr)
Rewrite the specified ops by repeatedly applying the highest benefit patterns in a greedy worklist dr...
@ ExistingOps
Only pre-existing ops are processed.