[mlir] Removed tight coupling of BufferPlacement pass to Alloc and Dealloc.

The current BufferPlacement implementation tries to find Alloc and Dealloc
operations in order to move them. However, this is a tight coupling to
standard-dialect ops which has been removed in this CL.

Differential Revision: https://reviews.llvm.org/D78993
This commit is contained in:
Marcel Koester 2020-04-21 15:12:10 +02:00
parent 19f5da9c1d
commit 67b466deda
1 changed files with 49 additions and 25 deletions

View File

@ -187,13 +187,23 @@ public:
/// Finds all associated dealloc nodes for the alloc nodes using alias /// Finds all associated dealloc nodes for the alloc nodes using alias
/// information. /// information.
DeallocSetT findAssociatedDeallocs(AllocOp alloc) const { DeallocSetT findAssociatedDeallocs(OpResult allocResult) const {
DeallocSetT result; DeallocSetT result;
auto possibleValues = aliases.resolve(alloc); auto possibleValues = aliases.resolve(allocResult);
for (Value alias : possibleValues) for (Value alias : possibleValues)
for (Operation *user : alias.getUsers()) { for (Operation *op : alias.getUsers()) {
if (isa<DeallocOp>(user)) // Check for an existing memory effect interface.
result.insert(user); auto effectInstance = dyn_cast<MemoryEffectOpInterface>(op);
if (!effectInstance)
continue;
// Check whether the associated value will be freed using the current
// operation.
SmallVector<MemoryEffects::EffectInstance, 2> effects;
effectInstance.getEffectsOnValue(alias, effects);
if (llvm::any_of(effects, [=](MemoryEffects::EffectInstance &it) {
return isa<MemoryEffects::Free>(it.getEffect());
}))
result.insert(op);
} }
return result; return result;
} }
@ -328,8 +338,6 @@ private:
/// The actual buffer placement pass that moves alloc and dealloc nodes into /// The actual buffer placement pass that moves alloc and dealloc nodes into
/// the right positions. It uses the algorithm described at the top of the file. /// the right positions. It uses the algorithm described at the top of the file.
// TODO: create a templated version that allows to match dialect-specific
// alloc/dealloc nodes and to insert dialect-specific dealloc node.
struct BufferPlacementPass struct BufferPlacementPass
: mlir::PassWrapper<BufferPlacementPass, FunctionPass> { : mlir::PassWrapper<BufferPlacementPass, FunctionPass> {
void runOnFunction() override { void runOnFunction() override {
@ -337,42 +345,58 @@ struct BufferPlacementPass
auto &analysis = getAnalysis<BufferPlacementAnalysis>(); auto &analysis = getAnalysis<BufferPlacementAnalysis>();
// Compute an initial placement of all nodes. // Compute an initial placement of all nodes.
llvm::SmallDenseMap<Value, BufferPlacementPositions, 16> placements; llvm::SmallVector<std::pair<OpResult, BufferPlacementPositions>, 16>
getFunction().walk([&](AllocOp alloc) { placements;
placements[alloc] = analysis.computeAllocAndDeallocPositions( getFunction().walk([&](MemoryEffectOpInterface op) {
alloc.getOperation()->getResult(0)); // Try to find a single allocation result.
return WalkResult::advance(); SmallVector<MemoryEffects::EffectInstance, 2> effects;
op.getEffects(effects);
SmallVector<MemoryEffects::EffectInstance, 2> allocateResultEffects;
llvm::copy_if(effects, std::back_inserter(allocateResultEffects),
[=](MemoryEffects::EffectInstance &it) {
Value value = it.getValue();
return isa<MemoryEffects::Allocate>(it.getEffect()) &&
value && value.isa<OpResult>();
});
// If there is one result only, we will be able to move the allocation and
// (possibly existing) deallocation ops.
if (allocateResultEffects.size() == 1) {
// Insert allocation result.
auto allocResult = allocateResultEffects[0].getValue().cast<OpResult>();
placements.emplace_back(
allocResult, analysis.computeAllocAndDeallocPositions(allocResult));
}
}); });
// Move alloc (and dealloc - if any) nodes into the right places // Move alloc (and dealloc - if any) nodes into the right places and insert
// and insert dealloc nodes if necessary. // dealloc nodes if necessary.
getFunction().walk([&](AllocOp alloc) { for (auto &entry : placements) {
// Find already associated dealloc nodes. // Find already associated dealloc nodes.
OpResult alloc = entry.first;
auto deallocs = analysis.findAssociatedDeallocs(alloc); auto deallocs = analysis.findAssociatedDeallocs(alloc);
if (deallocs.size() > 1) { if (deallocs.size() > 1) {
emitError(alloc.getLoc(), emitError(alloc.getLoc(),
"Not supported number of associated dealloc operations"); "not supported number of associated dealloc operations");
return WalkResult::interrupt(); return;
} }
// Move alloc node to the right place. // Move alloc node to the right place.
BufferPlacementPositions &positions = placements[alloc]; BufferPlacementPositions &positions = entry.second;
Operation *allocOperation = alloc.getOperation(); Operation *allocOperation = alloc.getOwner();
allocOperation->moveBefore(positions.getAllocPosition()); allocOperation->moveBefore(positions.getAllocPosition());
// If there is an existing dealloc, move it to the right place. // If there is an existing dealloc, move it to the right place.
Operation *nextOp = positions.getDeallocPosition()->getNextNode();
assert(nextOp && "Invalid Dealloc operation position");
if (deallocs.size()) { if (deallocs.size()) {
Operation *nextOp = positions.getDeallocPosition()->getNextNode();
assert(nextOp && "Invalid Dealloc operation position");
(*deallocs.begin())->moveBefore(nextOp); (*deallocs.begin())->moveBefore(nextOp);
} else { } else {
// If there is no dealloc node, insert one in the right place. // If there is no dealloc node, insert one in the right place.
OpBuilder builder(alloc); OpBuilder builder(nextOp);
builder.setInsertionPointAfter(positions.getDeallocPosition());
builder.create<DeallocOp>(allocOperation->getLoc(), alloc); builder.create<DeallocOp>(allocOperation->getLoc(), alloc);
} }
return WalkResult::advance(); }
});
}; };
}; };