Skip to content

Commit 67b466d

Browse files
committed
[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
1 parent 19f5da9 commit 67b466d

File tree

1 file changed

+49
-25
lines changed

1 file changed

+49
-25
lines changed

mlir/lib/Transforms/BufferPlacement.cpp

Lines changed: 49 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,23 @@ class BufferPlacementAnalysis {
187187

188188
/// Finds all associated dealloc nodes for the alloc nodes using alias
189189
/// information.
190-
DeallocSetT findAssociatedDeallocs(AllocOp alloc) const {
190+
DeallocSetT findAssociatedDeallocs(OpResult allocResult) const {
191191
DeallocSetT result;
192-
auto possibleValues = aliases.resolve(alloc);
192+
auto possibleValues = aliases.resolve(allocResult);
193193
for (Value alias : possibleValues)
194-
for (Operation *user : alias.getUsers()) {
195-
if (isa<DeallocOp>(user))
196-
result.insert(user);
194+
for (Operation *op : alias.getUsers()) {
195+
// Check for an existing memory effect interface.
196+
auto effectInstance = dyn_cast<MemoryEffectOpInterface>(op);
197+
if (!effectInstance)
198+
continue;
199+
// Check whether the associated value will be freed using the current
200+
// operation.
201+
SmallVector<MemoryEffects::EffectInstance, 2> effects;
202+
effectInstance.getEffectsOnValue(alias, effects);
203+
if (llvm::any_of(effects, [=](MemoryEffects::EffectInstance &it) {
204+
return isa<MemoryEffects::Free>(it.getEffect());
205+
}))
206+
result.insert(op);
197207
}
198208
return result;
199209
}
@@ -328,51 +338,65 @@ class BufferPlacementAnalysis {
328338

329339
/// The actual buffer placement pass that moves alloc and dealloc nodes into
330340
/// the right positions. It uses the algorithm described at the top of the file.
331-
// TODO: create a templated version that allows to match dialect-specific
332-
// alloc/dealloc nodes and to insert dialect-specific dealloc node.
333341
struct BufferPlacementPass
334342
: mlir::PassWrapper<BufferPlacementPass, FunctionPass> {
335343
void runOnFunction() override {
336344
// Get required analysis information first.
337345
auto &analysis = getAnalysis<BufferPlacementAnalysis>();
338346

339347
// Compute an initial placement of all nodes.
340-
llvm::SmallDenseMap<Value, BufferPlacementPositions, 16> placements;
341-
getFunction().walk([&](AllocOp alloc) {
342-
placements[alloc] = analysis.computeAllocAndDeallocPositions(
343-
alloc.getOperation()->getResult(0));
344-
return WalkResult::advance();
348+
llvm::SmallVector<std::pair<OpResult, BufferPlacementPositions>, 16>
349+
placements;
350+
getFunction().walk([&](MemoryEffectOpInterface op) {
351+
// Try to find a single allocation result.
352+
SmallVector<MemoryEffects::EffectInstance, 2> effects;
353+
op.getEffects(effects);
354+
355+
SmallVector<MemoryEffects::EffectInstance, 2> allocateResultEffects;
356+
llvm::copy_if(effects, std::back_inserter(allocateResultEffects),
357+
[=](MemoryEffects::EffectInstance &it) {
358+
Value value = it.getValue();
359+
return isa<MemoryEffects::Allocate>(it.getEffect()) &&
360+
value && value.isa<OpResult>();
361+
});
362+
// If there is one result only, we will be able to move the allocation and
363+
// (possibly existing) deallocation ops.
364+
if (allocateResultEffects.size() == 1) {
365+
// Insert allocation result.
366+
auto allocResult = allocateResultEffects[0].getValue().cast<OpResult>();
367+
placements.emplace_back(
368+
allocResult, analysis.computeAllocAndDeallocPositions(allocResult));
369+
}
345370
});
346371

347-
// Move alloc (and dealloc - if any) nodes into the right places
348-
// and insert dealloc nodes if necessary.
349-
getFunction().walk([&](AllocOp alloc) {
372+
// Move alloc (and dealloc - if any) nodes into the right places and insert
373+
// dealloc nodes if necessary.
374+
for (auto &entry : placements) {
350375
// Find already associated dealloc nodes.
376+
OpResult alloc = entry.first;
351377
auto deallocs = analysis.findAssociatedDeallocs(alloc);
352378
if (deallocs.size() > 1) {
353379
emitError(alloc.getLoc(),
354-
"Not supported number of associated dealloc operations");
355-
return WalkResult::interrupt();
380+
"not supported number of associated dealloc operations");
381+
return;
356382
}
357383

358384
// Move alloc node to the right place.
359-
BufferPlacementPositions &positions = placements[alloc];
360-
Operation *allocOperation = alloc.getOperation();
385+
BufferPlacementPositions &positions = entry.second;
386+
Operation *allocOperation = alloc.getOwner();
361387
allocOperation->moveBefore(positions.getAllocPosition());
362388

363389
// If there is an existing dealloc, move it to the right place.
390+
Operation *nextOp = positions.getDeallocPosition()->getNextNode();
391+
assert(nextOp && "Invalid Dealloc operation position");
364392
if (deallocs.size()) {
365-
Operation *nextOp = positions.getDeallocPosition()->getNextNode();
366-
assert(nextOp && "Invalid Dealloc operation position");
367393
(*deallocs.begin())->moveBefore(nextOp);
368394
} else {
369395
// If there is no dealloc node, insert one in the right place.
370-
OpBuilder builder(alloc);
371-
builder.setInsertionPointAfter(positions.getDeallocPosition());
396+
OpBuilder builder(nextOp);
372397
builder.create<DeallocOp>(allocOperation->getLoc(), alloc);
373398
}
374-
return WalkResult::advance();
375-
});
399+
}
376400
};
377401
};
378402

0 commit comments

Comments
 (0)