23#include "llvm/ADT/SmallPtrSet.h"
24#include "llvm/Support/ErrorHandling.h"
31 Value step,
bool inclusiveUpperbound) {
32 Type type =
b.getIndexType();
39 if (!inclusiveUpperbound) {
41 ub =
b.createOrFold<arith::SubIOp>(loc,
ub, one,
42 arith::IntegerOverflowFlags::nsw);
45 Value sub =
b.createOrFold<arith::SubIOp>(loc,
ub, lb,
46 arith::IntegerOverflowFlags::nsw);
47 Value add =
b.createOrFold<arith::AddIOp>(loc, sub, step,
48 arith::IntegerOverflowFlags::nsw);
49 return b.createOrFold<arith::DivSIOp>(loc,
add, step);
57 for (
auto [origIV, newIV] :
58 llvm::zip(accLoop.getBody().getArguments(), newIVs)) {
60 b, accLoop->getLoc(), origIV.getType(), newIV);
61 mapping.
map(origIV, replacementIV);
70 Type indexType =
b.getIndexType();
76 arith::MulIOp::create(
b, loc, iv, step, arith::IntegerOverflowFlags::nsw);
77 Value denormalized = arith::AddIOp::create(
b, loc, scaled, lb,
78 arith::IntegerOverflowFlags::nsw);
94 auto [replacements, ip] =
115 llvm_unreachable(
"cloneACCRegionInto: multi-block region not supported "
116 "(requires scf.execute_region)");
120 src->
cloneInto(insertRegion, postInsertBlock->getIterator(), mapping);
123 Block *lastNewBlock = &*std::prev(postInsertBlock->getIterator());
126 if (
auto yieldOp = dyn_cast<acc::YieldOp>(lastNewBlock->
getTerminator())) {
128 llvm::zip(yieldOp.getOperands(), resultsToReplace)) {
131 replacements.append(yieldOp.getOperands().begin(),
132 yieldOp.getOperands().end());
133 ip = std::prev(yieldOp->getIterator());
140 "cloneACCRegionInto: expected acc.yield or acc.terminator");
141 ip = std::prev(terminatorOp->getIterator());
142 terminatorOp.erase();
147 postInsertBlock->
erase();
149 Block *firstNewBlock = &*std::next(dest->getIterator());
151 firstNewBlock->
erase();
152 return {replacements, ip};
165 terminators.push_back(term);
168 if (!terminators.empty())
169 for (
Value operand : terminators.front()->getOperands())
170 resultTypes.push_back(operand.getType());
173 scf::ExecuteRegionOp::create(rewriter, loc,
TypeRange(resultTypes));
176 exeRegionOp.getRegion().
end(), mapping);
180 assert(blockTerminator &&
"expected terminator to be in mapping");
182 (
void)scf::YieldOp::create(rewriter, blockTerminator->
getLoc(),
184 rewriter.
eraseOp(blockTerminator);
191 bool enableCollapse) {
192 assert(!loopOp.getUnstructured() &&
193 "use convertUnstructuredACCLoopToSCFExecuteRegion for unstructured "
212 for (
auto [idx, iv] : llvm::enumerate(loopOp.getBody().getArguments())) {
213 bool inclusiveUpperbound =
false;
214 if (loopOp.getInclusiveUpperbound().has_value())
215 inclusiveUpperbound =
216 loopOp.getInclusiveUpperboundAttr().asArrayRef()[idx];
219 loopOp.getUpperbound()[idx],
220 loopOp.getStep()[idx], inclusiveUpperbound);
221 tripCounts.push_back(tc);
224 for (
auto [idx, iv] : llvm::enumerate(loopOp.getBody().getArguments())) {
230 scf::ForOp::create(rewriter, loc, zero, tripCounts[idx], one);
231 forOps.push_back(forOp);
232 mapping.
map(iv, forOp.getInductionVar());
240 for (scf::ForOp forOp : forOps)
241 scfIVs.push_back(forOp.getInductionVar());
249 for (
size_t idx = 0; idx < forOps.size(); ++idx) {
250 Value iv = forOps[idx].getInductionVar();
254 loopOp.getStep()[idx]);
259 if (enableCollapse && forOps.size() > 1) {
260 unsigned numCollapsed = forOps.size();
262 loopOp.emitError(
"failed to collapse acc.loop");
268 return forOps.front();
273 assert(!loopOp.getUnstructured() &&
274 "use convertUnstructuredACCLoopToSCFExecuteRegion for unstructured "
279 "builder insertion point must not be inside the loop being converted");
289 for (
auto [idx, iv] : llvm::enumerate(loopOp.getBody().getArguments())) {
290 bool inclusiveUpperbound =
false;
291 if (loopOp.getInclusiveUpperbound().has_value())
292 inclusiveUpperbound = loopOp.getInclusiveUpperbound().value()[idx];
295 loopOp.getUpperbound()[idx],
296 loopOp.getStep()[idx], inclusiveUpperbound);
298 lowerBounds.push_back(lb);
299 upperBounds.push_back(
ub);
300 steps.push_back(step);
304 scf::ParallelOp::create(rewriter, loc, lowerBounds, upperBounds, steps);
312 if (!loopOp.getRegion().hasOneBlock()) {
314 loopOp.getRegion(), mapping, loc, rewriter);
326 for (
auto [idx, iv] : llvm::enumerate(parallelOp.getBody()->getArguments()))
329 loopOp.getStep()[idx]);
339 assert(loopOp.getUnstructured() &&
340 "use convertACCLoopToSCFFor for structured loops");
344 "builder insertion point must not be inside the loop being converted");
348 loopOp->getLoc(), rewriter);
354 IntegerAttr::get(IntegerType::get(op->
getContext(), 64), count));
360 return attr.getValue().getZExtValue();
*if copies could not be generated due to yet unimplemented cases *copyInPlacementStart and copyOutPlacementStart in copyPlacementBlock *specify the insertion points where the incoming copies and outgoing should be the output argument nBegin is set to its * replacement(set to `begin` if no invalidation happens). Since outgoing *copies could have been inserted at `end`
static void mapACCLoopIVsToSCFIVs(acc::LoopOp accLoop, ValueRange newIVs, OpBuilder &b, IRMapping &mapping)
Handle differing types between SCF (index) and ACC loops.
static void copyLoopAnnotationAttr(Operation *from, Operation *to)
Copy the discardable LLVM loop annotation attribute from an acc.loop to the lowered SCF op so later S...
static Block::iterator cloneACCRegionIntoForLoop(Region *src, Block *dest, Block::iterator insertionPoint, IRMapping &mapping, RewriterBase &rewriter)
Helper used by loop conversion: clone region and return insertion point only.
Attributes are known-constant values of operations.
Block represents an ordered list of Operations.
OpListType::iterator iterator
void erase()
Unlink this Block from its parent region and delete it.
Block * splitBlock(iterator splitBefore)
Split the block into two blocks before the specified operation or iterator.
Region * getParent() const
Provide a 'getParent' method for ilist_node_with_parent methods.
OpListType & getOperations()
Operation * getTerminator()
Get the terminator operation of this block.
Operation * getParentOp()
Returns the closest surrounding operation that contains this block.
This is a utility class for mapping one set of IR entities to another.
auto lookup(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 defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
RAII guard to reset the insertion point of the builder when destroyed.
This class helps build Operations.
Block::iterator getInsertionPoint() const
Returns the current insertion point of the builder.
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 cloneRegionBefore(Region ®ion, Region &parent, Region::iterator before, IRMapping &mapping)
Clone the blocks that belong to "region" before the given position in another region "parent".
Block * getInsertionBlock() const
Return the block the current insertion point belongs to.
Operation is the basic unit of execution within MLIR.
Attribute getDiscardableAttr(StringRef name)
Access a discardable attribute by name, returns a null Attribute if the discardable attribute does no...
unsigned getNumSuccessors()
void setDiscardableAttr(StringAttr name, Attribute value)
Set a discardable attribute by name.
Location getLoc()
The source location the operation was defined or derived from.
operand_range getOperands()
Returns an iterator on the underlying Value's.
AttrClass getDiscardableAttrOfType(StringRef name)
Access a discardable attribute by name and cast it to AttrClass.
MLIRContext * getContext()
Return the context this operation is associated with.
This class contains a list of basic blocks and a link to the parent operation it is attached to.
void cloneInto(Region *dest, IRMapping &mapper)
Clone the internal blocks from this region into dest.
BlockListType & getBlocks()
bool hasOneBlock()
Return true if this region has exactly one block.
This class coordinates the application of a rewrite on a set of IR, providing a way for clients to tr...
virtual void eraseOp(Operation *op)
This method erases an operation that is known to have no uses.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
bool use_empty() const
Returns true if this value has no uses.
void replaceAllUsesExcept(Value newValue, const SmallPtrSetImpl< Operation * > &exceptions)
Replace all uses of 'this' value with 'newValue', updating anything in the IR that uses 'this' to use...
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
static ConstantIndexOp create(OpBuilder &builder, Location location, int64_t value)
uint64_t getCollapseCount(Operation *op)
Number of original loops collapsed into op, or 1 when op carries no collapse_count attribute.
void setCollapseCountAttr(Operation *op, uint64_t count)
Record on a collapsed loop how many original loops were folded into it.
Value calculateTripCount(OpBuilder &b, Location loc, Value lb, Value ub, Value step, bool inclusiveUpperbound)
Calculate trip count for a loop: (ub - lb + step) / step.
scf::ParallelOp convertACCLoopToSCFParallel(LoopOp loopOp, RewriterBase &rewriter)
Convert acc.loop to scf.parallel.
scf::ExecuteRegionOp wrapMultiBlockRegionWithSCFExecuteRegion(Region ®ion, IRMapping &mapping, Location loc, RewriterBase &rewriter)
Wrap a multi-block region in an scf.execute_region.
scf::ExecuteRegionOp convertUnstructuredACCLoopToSCFExecuteRegion(LoopOp loopOp, RewriterBase &rewriter)
Convert an unstructured acc.loop to scf.execute_region.
static constexpr StringLiteral getCollapseCountAttrName()
Name for an attribute attached to a loop indicating the number of loops collapsed to create that loop...
std::pair< llvm::SmallVector< Value >, Block::iterator > cloneACCRegionInto(Region *src, Block *dest, Block::iterator inlinePoint, IRMapping &mapping, ValueRange resultsToReplace)
Clone an ACC region into a destination block at the given insertion point.
void normalizeIVUses(OpBuilder &b, Location loc, Value iv, Value origLB, Value origStep)
Normalize IV uses after converting to normalized loop form (lb=0, step=1).
scf::ForOp convertACCLoopToSCFFor(LoopOp loopOp, RewriterBase &rewriter, bool enableCollapse)
Convert a structured acc.loop to scf.for.
Include the generated interface declarations.
void replaceAllUsesInRegionWith(Value orig, Value replacement, Region ®ion)
Replace all uses of orig within the given region with replacement.
Value getValueOrCreateCastToIndexLike(OpBuilder &b, Location loc, Type targetType, Value value)
Create a cast from an index-like value (index or integer) to another index-like value.
LogicalResult coalesceLoops(MutableArrayRef< scf::ForOp > loops)
Replace a perfect nest of "for" loops with a single linearized loop.