//===- OwnershipBasedBufferDeallocation.cpp - impl. for buffer dealloc. ---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file implements logic for computing correct `bufferization.dealloc` // positions. Furthermore, buffer deallocation also adds required new clone // operations to ensure that memrefs returned by functions never alias an // argument. // // TODO: // The current implementation does not support explicit-control-flow loops and // the resulting code will be invalid with respect to program semantics. // However, structured control-flow loops are fully supported. // //===----------------------------------------------------------------------===// #include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h" #include "mlir/Dialect/Bufferization/IR/Bufferization.h" #include "mlir/Dialect/Bufferization/Transforms/Passes.h" #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/Dialect/MemRef/IR/MemRef.h" #include "mlir/Dialect/SCF/IR/SCF.h" #include "mlir/IR/Iterators.h" #include "mlir/Interfaces/ControlFlowInterfaces.h" namespace mlir { namespace bufferization { #define GEN_PASS_DEF_OWNERSHIPBASEDBUFFERDEALLOCATION #include "mlir/Dialect/Bufferization/Transforms/Passes.h.inc" } // namespace bufferization } // namespace mlir usingnamespacemlir; usingnamespacemlir::bufferization; //===----------------------------------------------------------------------===// // Helpers //===----------------------------------------------------------------------===// static Value buildBoolValue(OpBuilder &builder, Location loc, bool value) { … } static bool isMemref(Value v) { … } /// Return "true" if the given op is guaranteed to have neither "Allocate" nor /// "Free" side effects. static bool hasNeitherAllocateNorFreeSideEffect(Operation *op) { … } /// Return "true" if the given op has buffer semantics. I.e., it has buffer /// operands, buffer results and/or buffer region entry block arguments. static bool hasBufferSemantics(Operation *op) { … } //===----------------------------------------------------------------------===// // Backedges analysis //===----------------------------------------------------------------------===// namespace { /// A straight-forward program analysis which detects loop backedges induced by /// explicit control flow. class Backedges { … }; } // namespace //===----------------------------------------------------------------------===// // BufferDeallocation //===----------------------------------------------------------------------===// namespace { /// The buffer deallocation transformation which ensures that all allocs in the /// program have a corresponding de-allocation. class BufferDeallocation { … }; } // namespace //===----------------------------------------------------------------------===// // BufferDeallocation Implementation //===----------------------------------------------------------------------===// std::pair<Value, Value> BufferDeallocation::materializeUniqueOwnership(OpBuilder &builder, Value memref, Block *block) { … } LogicalResult BufferDeallocation::verifyFunctionPreconditions(FunctionOpInterface op) { … } LogicalResult BufferDeallocation::verifyOperationPreconditions(Operation *op) { … } LogicalResult BufferDeallocation::updateFunctionSignature(FunctionOpInterface op) { … } LogicalResult BufferDeallocation::deallocate(FunctionOpInterface op) { … } LogicalResult BufferDeallocation::deallocate(Block *block) { … } Operation *BufferDeallocation::appendOpResults(Operation *op, ArrayRef<Type> types) { … } FailureOr<Operation *> BufferDeallocation::handleInterface(RegionBranchOpInterface op) { … } Value BufferDeallocation::materializeMemrefWithGuaranteedOwnership( OpBuilder &builder, Value memref, Block *block) { … } FailureOr<Operation *> BufferDeallocation::handleInterface(BranchOpInterface op) { … } FailureOr<Operation *> BufferDeallocation::handleInterface(CallOpInterface op) { … } FailureOr<Operation *> BufferDeallocation::handleInterface(MemoryEffectOpInterface op) { … } FailureOr<Operation *> BufferDeallocation::handleInterface(RegionBranchTerminatorOpInterface op) { … } bool BufferDeallocation::isFunctionWithoutDynamicOwnership(Operation *op) { … } void BufferDeallocation::populateRemainingOwnerships(Operation *op) { … } //===----------------------------------------------------------------------===// // OwnershipBasedBufferDeallocationPass //===----------------------------------------------------------------------===// namespace { /// The actual buffer deallocation pass that inserts and moves dealloc nodes /// into the right positions. Furthermore, it inserts additional clones if /// necessary. It uses the algorithm described at the top of the file. struct OwnershipBasedBufferDeallocationPass : public bufferization::impl::OwnershipBasedBufferDeallocationBase< OwnershipBasedBufferDeallocationPass> { … }; } // namespace //===----------------------------------------------------------------------===// // Implement bufferization API //===----------------------------------------------------------------------===// LogicalResult bufferization::deallocateBuffersOwnershipBased(FunctionOpInterface op, DeallocationOptions options) { … } //===----------------------------------------------------------------------===// // OwnershipBasedBufferDeallocationPass construction //===----------------------------------------------------------------------===// std::unique_ptr<Pass> mlir::bufferization::createOwnershipBasedBufferDeallocationPass( DeallocationOptions options) { … }