182 for (
Value alias : aliases) {
183 for (
auto *use : alias.getUsers()) {
187 if (isa<RegionBranchTerminatorOpInterface>(use) &&
188 use->getParentRegion() == parentRegion)
224struct BufferAllocationHoistingStateBase {
229 Block *placementBlock;
233 Block *placementBlock)
234 : dominators(dominators), placementBlock(placementBlock) {}
238template <
typename StateT>
243 postDominators(op), scopeOp(op) {}
249 allocsAndAllocas.push_back(std::get<0>(entry));
250 scopeOp->walk([&](memref::AllocaOp op) {
251 allocsAndAllocas.push_back(op.getMemref());
254 for (
auto allocValue : allocsAndAllocas) {
255 if (!StateT::shouldHoistOpType(allocValue.getDefiningOp()))
257 Operation *definingOp = allocValue.getDefiningOp();
258 assert(definingOp &&
"No defining op");
262 if (!dominators.isReachableFromEntry(allocValue.getParentBlock()))
265 auto resultAliases = aliases.resolve(allocValue);
267 Block *dominatorBlock =
270 StateT state(&dominators, allocValue.getParentBlock(), resultAliases);
273 Block *dependencyBlock =
nullptr;
277 for (
Value depValue : operands) {
278 Block *depBlock = depValue.getParentBlock();
279 if (!dependencyBlock || dominators.dominates(dependencyBlock, depBlock))
280 dependencyBlock = depBlock;
286 Block *placementBlock = findPlacementBlock(
287 state, state.computeUpperBound(dominatorBlock, dependencyBlock));
289 allocValue, placementBlock, liveness);
292 Operation *allocOperation = allocValue.getDefiningOp();
301 Block *findPlacementBlock(StateT &state,
Block *upperBound) {
302 Block *currentBlock = state.placementBlock;
313 (parentBlock = parentOp->
getBlock()) &&
315 dominators.properlyDominates(upperBound, currentBlock))) {
318 if (!dominators.isReachableFromEntry(currentBlock))
327 idom = dominators.getNode(currentBlock)->getIDom();
329 if (idom && dominators.properlyDominates(parentBlock, idom->getBlock())) {
332 currentBlock = idom->getBlock();
333 state.recordMoveToDominator(currentBlock);
337 if (parentOp == scopeOp ||
338 parentOp->
hasTrait<OpTrait::IsIsolatedFromAbove>() ||
340 !state.isLegalPlacement(parentOp))
344 currentBlock = parentBlock;
345 state.recordMoveToParent(currentBlock);
349 return state.placementBlock;
354 DominanceInfo dominators;
358 PostDominanceInfo postDominators;
368struct BufferAllocationHoistingState : BufferAllocationHoistingStateBase {
369 BufferAllocationHoistingState(DominanceInfo *dominators,
370 Block *placementBlock,
372 : BufferAllocationHoistingStateBase(dominators, placementBlock) {}
375 Block *computeUpperBound(
Block *dominatorBlock,
Block *dependencyBlock) {
378 if (!dependencyBlock)
379 return dominatorBlock;
383 return dominators->properlyDominates(dominatorBlock, dependencyBlock)
389 bool isLegalPlacement(Operation *op) {
return !
isLoop(op); }
392 static bool shouldHoistOpType(Operation *op) {
397 void recordMoveToDominator(
Block *block) { placementBlock = block; }
400 void recordMoveToParent(
Block *block) { recordMoveToDominator(block); }
405struct BufferAllocationLoopHoistingState : BufferAllocationHoistingStateBase {
410 Block *aliasDominatorBlock =
nullptr;
412 BufferAllocationLoopHoistingState(
413 DominanceInfo *dominators,
Block *placementBlock,
415 : BufferAllocationHoistingStateBase(dominators, placementBlock),
419 Block *computeUpperBound(
Block *dominatorBlock,
Block *dependencyBlock) {
420 aliasDominatorBlock = dominatorBlock;
423 return dependencyBlock ? dependencyBlock :
nullptr;
427 bool isLegalPlacement(Operation *op) {
430 if (!dominators->dominates(aliasDominatorBlock, op->
getBlock()))
432 auto loop = dyn_cast<scf::WhileOp>(op);
437 static bool shouldHoistOpType(Operation *op) {
443 void recordMoveToDominator(
Block *block) {}
446 void recordMoveToParent(
Block *block) { placementBlock = block; }
456 BufferPlacementPromotion(Operation *op)
457 : BufferPlacementTransformationBase(op) {}
462 Value alloc = std::get<0>(entry);
463 Operation *dealloc = std::get<1>(entry);
468 if (!isSmallAlloc(alloc) || dealloc ||
476 OpBuilder builder(startOperation);
478 if (
auto allocInterface = dyn_cast<AllocationOpInterface>(allocOp)) {
479 std::optional<Operation *> alloca =
480 allocInterface.buildPromotedAlloc(builder, alloc);
497struct BufferHoistingPass
500 void runOnOperation()
override {
502 BufferAllocationHoisting<BufferAllocationHoistingState> optimizer(
509struct BufferLoopHoistingPass
511 BufferLoopHoistingPass> {
513 void runOnOperation()
override {
521class PromoteBuffersToStackPass
523 PromoteBuffersToStackPass> {
527 explicit PromoteBuffersToStackPass(std::function<
bool(Value)> isSmallAlloc)
528 : isSmallAlloc(std::move(isSmallAlloc)) {}
530 LogicalResult
initialize(MLIRContext *context)
override {
531 if (isSmallAlloc ==
nullptr) {
532 isSmallAlloc = [=](Value alloc) {
534 maxRankOfAllocatedMemRef);
540 void runOnOperation()
override {
542 BufferPlacementPromotion optimizer(getOperation());
543 optimizer.promote(isSmallAlloc);
547 std::function<bool(Value)> isSmallAlloc;
553 BufferAllocationHoisting<BufferAllocationLoopHoistingState> optimizer(op);
558 std::function<
bool(
Value)> isSmallAlloc) {
559 return std::make_unique<PromoteBuffersToStackPass>(std::move(isSmallAlloc));