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;
361 llvm::DenseMap<Value, Block *> placementBlocks;
371struct BufferAllocationHoistingState : BufferAllocationHoistingStateBase {
372 BufferAllocationHoistingState(DominanceInfo *dominators,
373 Block *placementBlock,
375 : BufferAllocationHoistingStateBase(dominators, placementBlock) {}
378 Block *computeUpperBound(
Block *dominatorBlock,
Block *dependencyBlock) {
381 if (!dependencyBlock)
382 return dominatorBlock;
386 return dominators->properlyDominates(dominatorBlock, dependencyBlock)
392 bool isLegalPlacement(Operation *op) {
return !
isLoop(op); }
395 static bool shouldHoistOpType(Operation *op) {
400 void recordMoveToDominator(
Block *block) { placementBlock = block; }
403 void recordMoveToParent(
Block *block) { recordMoveToDominator(block); }
408struct BufferAllocationLoopHoistingState : BufferAllocationHoistingStateBase {
413 Block *aliasDominatorBlock =
nullptr;
415 BufferAllocationLoopHoistingState(
416 DominanceInfo *dominators,
Block *placementBlock,
418 : BufferAllocationHoistingStateBase(dominators, placementBlock),
422 Block *computeUpperBound(
Block *dominatorBlock,
Block *dependencyBlock) {
423 aliasDominatorBlock = dominatorBlock;
426 return dependencyBlock ? dependencyBlock :
nullptr;
430 bool isLegalPlacement(Operation *op) {
433 if (!dominators->dominates(aliasDominatorBlock, op->
getBlock()))
435 auto loop = dyn_cast<scf::WhileOp>(op);
440 static bool shouldHoistOpType(Operation *op) {
446 void recordMoveToDominator(
Block *block) {}
449 void recordMoveToParent(
Block *block) { placementBlock = block; }
459 BufferPlacementPromotion(Operation *op)
460 : BufferPlacementTransformationBase(op) {}
465 Value alloc = std::get<0>(entry);
466 Operation *dealloc = std::get<1>(entry);
471 if (!isSmallAlloc(alloc) || dealloc ||
479 OpBuilder builder(startOperation);
481 if (
auto allocInterface = dyn_cast<AllocationOpInterface>(allocOp)) {
482 std::optional<Operation *> alloca =
483 allocInterface.buildPromotedAlloc(builder, alloc);
500struct BufferHoistingPass
503 void runOnOperation()
override {
505 BufferAllocationHoisting<BufferAllocationHoistingState> optimizer(
512struct BufferLoopHoistingPass
514 BufferLoopHoistingPass> {
516 void runOnOperation()
override {
524class PromoteBuffersToStackPass
526 PromoteBuffersToStackPass> {
530 explicit PromoteBuffersToStackPass(std::function<
bool(Value)> isSmallAlloc)
531 : isSmallAlloc(std::move(isSmallAlloc)) {}
533 LogicalResult
initialize(MLIRContext *context)
override {
534 if (isSmallAlloc ==
nullptr) {
535 isSmallAlloc = [=](Value alloc) {
537 maxRankOfAllocatedMemRef);
543 void runOnOperation()
override {
545 BufferPlacementPromotion optimizer(getOperation());
546 optimizer.promote(isSmallAlloc);
550 std::function<bool(Value)> isSmallAlloc;
556 BufferAllocationHoisting<BufferAllocationLoopHoistingState> optimizer(op);
561 std::function<
bool(
Value)> isSmallAlloc) {
562 return std::make_unique<PromoteBuffersToStackPass>(std::move(isSmallAlloc));