diff --git a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h --- a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h +++ b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.h @@ -14,6 +14,7 @@ #include "mlir/IR/BuiltinOps.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/Operation.h" +#include "mlir/IR/PatternMatch.h" #include "mlir/Support/LLVM.h" #include "llvm/ADT/EquivalenceClasses.h" #include "llvm/ADT/SetVector.h" @@ -296,7 +297,8 @@ /// * `replaceOp` replaces an op with new values. class BufferizationState { public: - BufferizationState(Operation *op, const BufferizationOptions &options); + BufferizationState(Operation *op, const BufferizationOptions &options, + RewriterBase &rewriter); // BufferizationState should be passed as a reference. BufferizationState(const BufferizationState &) = delete; @@ -387,9 +389,10 @@ /// Replace an op with a new op. Tensor OpResults must be replaced with memref /// values. template - OpTy replaceOpWithNewOp(OpBuilder &b, Operation *op, Args &&...args) { + OpTy replaceOpWithNewOp(RewriterBase &rewriter, Operation *op, + Args &&...args) { Operation *newOp = - b.create(op->getLoc(), std::forward(args)...); + rewriter.create(op->getLoc(), std::forward(args)...); replaceOp(op, newOp->getResults()); return cast(newOp); } @@ -417,8 +420,8 @@ /// Return a reference to the BufferizationOptions. const BufferizationOptions &getOptions() const { return options; } - /// Return a reference to the OpBuilder. - OpBuilder &getBuilder() { return builder; } + /// Return a reference to the rewriter. + RewriterBase &getRewriter() { return rewriter; } private: friend LogicalResult @@ -440,7 +443,7 @@ const BufferizationOptions &options; /// The OpBuilder used during bufferization. - OpBuilder builder; + RewriterBase &rewriter; }; /// Bufferize all ops in the given region. @@ -523,7 +526,7 @@ return false; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto isaTensor = [](Type t) { return t.isa(); }; if (any_of(op->getOperandTypes(), isaTensor) || diff --git a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.td b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.td --- a/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.td +++ b/mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.td @@ -209,7 +209,7 @@ }], /*retType=*/"LogicalResult", /*methodName=*/"bufferize", - /*args=*/(ins "OpBuilder &":$b, + /*args=*/(ins "RewriterBase &":$rewriter, "BufferizationState &":$state), /*methodBody=*/"", /*defaultImplementation=*/[{ diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ArithInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ArithInterfaceImpl.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ArithInterfaceImpl.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ArithInterfaceImpl.cpp @@ -23,7 +23,7 @@ struct ConstantOpInterface : public BufferizableOpInterface::ExternalModel { - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto constantOp = cast(op); assert(constantOp.getType().dyn_cast() && @@ -35,8 +35,8 @@ GlobalCreator globalCreator(moduleOp); auto globalMemref = globalCreator.getGlobalFor(constantOp); - state.replaceOpWithNewOp(b, op, globalMemref.type(), - globalMemref.getName()); + state.replaceOpWithNewOp( + rewriter, op, globalMemref.type(), globalMemref.getName()); return success(); } diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizableOpInterface.cpp @@ -333,8 +333,8 @@ } mlir::linalg::comprehensive_bufferize::BufferizationState::BufferizationState( - Operation *op, const BufferizationOptions &options) - : aliasInfo(op), options(options), builder(op->getContext()) { + Operation *op, const BufferizationOptions &options, RewriterBase &rewriter) + : aliasInfo(op), options(options), rewriter(rewriter) { // Set up alias sets for OpResults that must bufferize in-place. This should // be done before making any other bufferization decisions. op->walk([&](BufferizableOpInterface bufferizableOp) { @@ -361,7 +361,7 @@ /// bufferization is necessary. Value mlir::linalg::comprehensive_bufferize::BufferizationState:: getResultBuffer(OpResult result) { - OpBuilder::InsertionGuard guard(builder); + OpBuilder::InsertionGuard guard(rewriter); Operation *op = result.getOwner(); SmallVector aliasingOperands = getAliasingOpOperand(result); assert(!aliasingOperands.empty() && "could not get aliasing OpOperand"); @@ -391,9 +391,9 @@ Location loc = op->getLoc(); // Move insertion point right after `operandBuffer`. That is where the // allocation should be inserted (in the absence of allocation hoisting). - setInsertionPointAfter(builder, operandBuffer); + setInsertionPointAfter(rewriter, operandBuffer); // Allocate the result buffer. - Value resultBuffer = createAllocDeallocPair(builder, loc, operandBuffer); + Value resultBuffer = createAllocDeallocPair(rewriter, loc, operandBuffer); bool skipCopy = false; // Do not copy if the last preceding write of `operand` is an op that does // not write (skipping ops that merely create aliases). E.g., InitTensorOp. @@ -413,8 +413,8 @@ skipCopy = true; if (!skipCopy) { // The copy happens right before the op that is bufferized. - builder.setInsertionPoint(op); - createMemCpy(builder, loc, operandBuffer, resultBuffer); + rewriter.setInsertionPoint(op); + createMemCpy(rewriter, loc, operandBuffer, resultBuffer); } return resultBuffer; } @@ -425,8 +425,7 @@ void mlir::linalg::comprehensive_bufferize::BufferizationState::replaceOp( Operation *op, ValueRange values) { - OpBuilder &b = getBuilder(); - OpBuilder::InsertionGuard g(b); + OpBuilder::InsertionGuard g(rewriter); // Replace all OpResults with the given values. for (OpResult opResult : op->getOpResults()) { @@ -444,14 +443,14 @@ // The existing uses of the OpResult still expect a tensor. Insert a // ToTensorOp. Throughout bufferization, this ToTensorOp will gradually // loose all of its users and eventually DCE away. - setInsertionPointAfter(b, replacement); - replacement = b.create(replacement.getLoc(), - replacement); + setInsertionPointAfter(rewriter, replacement); + replacement = rewriter.create( + replacement.getLoc(), replacement); } opResult.replaceAllUsesWith(replacement); } - op->erase(); + rewriter.eraseOp(op); } LogicalResult @@ -481,7 +480,7 @@ LogicalResult mlir::linalg::comprehensive_bufferize::bufferize(Operation *op, BufferizationState &state) { - OpBuilder &b = state.getBuilder(); + RewriterBase &rewriter = state.getRewriter(); // Check if op has tensor results or operands. auto isaTensor = [](Type t) { return t.isa(); }; @@ -496,8 +495,8 @@ // Bufferize using `BufferizableOpInterface`. Interface implementations are // responsible for bufferizing nested ops. if (auto bufferizableOp = state.getOptions().dynCastBufferizableOp(op)) { - b.setInsertionPoint(op); - return bufferizableOp.bufferize(b, state); + rewriter.setInsertionPoint(op); + return bufferizableOp.bufferize(rewriter, state); } // `op` is an unbufferizable tensor op. @@ -679,10 +678,9 @@ } // Insert to_memref op. - OpBuilder &b = getBuilder(); - OpBuilder::InsertionGuard g(b); - setInsertionPointAfter(b, tensor); - return b.create( + OpBuilder::InsertionGuard g(rewriter); + setInsertionPointAfter(rewriter, tensor); + return rewriter.create( tensor.getLoc(), getDynamicMemRefType(tensor.getType().cast()), tensor); } diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizationInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizationInterfaceImpl.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizationInterfaceImpl.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/BufferizationInterfaceImpl.cpp @@ -50,15 +50,14 @@ return OpResult(); } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto toMemrefOp = cast(op); // Fold to_memref(to_tensor(x)) to x. if (auto toTensorOp = toMemrefOp.tensor().getDefiningOp()) { - toMemrefOp.replaceAllUsesWith(toTensorOp.memref()); - toMemrefOp.erase(); + rewriter.replaceOp(toMemrefOp, toTensorOp.memref()); return success(); } @@ -86,7 +85,7 @@ struct ToTensorOpInterface : public BufferizableOpInterface::ExternalModel { - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { return success(); } diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ComprehensiveBufferize.cpp @@ -654,7 +654,8 @@ LogicalResult mlir::linalg::comprehensive_bufferize::runComprehensiveBufferize( Operation *op, std::unique_ptr options) { - BufferizationState state(op, *options); + IRRewriter rewriter(op->getContext()); + BufferizationState state(op, *options, rewriter); return runComprehensiveBufferize(op, *options, state); } diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/LinalgInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/LinalgInterfaceImpl.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/LinalgInterfaceImpl.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/LinalgInterfaceImpl.cpp @@ -23,11 +23,11 @@ // TODO: Ops in the linalg dialect can directly implement this interface. /// Generic conversion for any LinalgOp on tensors. -static LogicalResult bufferizeLinalgOp(OpBuilder &b, LinalgOp op, +static LogicalResult bufferizeLinalgOp(RewriterBase &rewriter, LinalgOp op, BufferizationState &state) { // Take a guard before anything else. - OpBuilder::InsertionGuard g(b); - b.setInsertionPoint(op); + OpBuilder::InsertionGuard g(rewriter); + rewriter.setInsertionPoint(op); // Nothing to do. This op is already bufferized. if (op.hasBufferSemantics()) @@ -63,9 +63,9 @@ newOperands.append(newOutputBuffers.begin(), newOutputBuffers.end()); // Set insertion point now that potential alloc/dealloc are introduced. - b.setInsertionPoint(op); - auto bufferizedOp = cast( - op.clone(b, op.getLoc(), /*resultTypes=*/TypeRange{}, newOperands)); + rewriter.setInsertionPoint(op); + auto bufferizedOp = cast(op.clone( + rewriter, op.getLoc(), /*resultTypes=*/TypeRange{}, newOperands)); // Replace the results of the old op with the new output buffers. state.replaceOp(op, newOutputBuffers); @@ -177,9 +177,9 @@ return BufferRelation::Equivalent; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { - return bufferizeLinalgOp(b, cast(op), state); + return bufferizeLinalgOp(rewriter, cast(op), state); } }; @@ -192,7 +192,7 @@ return false; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto initTensorOp = cast(op); @@ -200,7 +200,7 @@ if (initTensorOp->getUses().empty()) return success(); - Value alloc = state.createAllocDeallocPair(b, initTensorOp->getLoc(), + Value alloc = state.createAllocDeallocPair(rewriter, initTensorOp->getLoc(), initTensorOp.result()); state.replaceOp(op, alloc); return success(); @@ -251,15 +251,10 @@ bool isAllocationHoistingBarrier(Operation *op) const { return true; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto tiledLoopOp = cast(op); - // Use IRRewriter instead of OpBuilder because it has additional helper - // functions. - IRRewriter rewriter(op->getContext()); - rewriter.setInsertionPoint(tiledLoopOp); - // Compute new inputs, outputs and results. SmallVector newInputs, newOutputs, newResults; for (Value value : tiledLoopOp.inputs()) { @@ -358,7 +353,7 @@ return OpResult(); } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto yieldOp = cast(op); diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ModuleBufferization.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ModuleBufferization.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ModuleBufferization.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/ModuleBufferization.cpp @@ -725,7 +725,8 @@ LogicalResult mlir::linalg::comprehensive_bufferize::runComprehensiveBufferize( ModuleOp moduleOp, std::unique_ptr options) { - BufferizationState state(moduleOp, *options); + IRRewriter rewriter(moduleOp.getContext()); + BufferizationState state(moduleOp, *options, rewriter); ModuleBufferizationState &moduleState = getModuleBufferizationState(state); BufferizationAliasInfo &aliasInfo = state.aliasInfo; diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/SCFInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/SCFInterfaceImpl.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/SCFInterfaceImpl.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/SCFInterfaceImpl.cpp @@ -60,7 +60,7 @@ return true; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { // TODO: Add bufferization support when needed. scf.execute_region should be // bufferized similar to scf.if. @@ -134,15 +134,10 @@ return true; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto ifOp = cast(op); - // Use IRRewriter instead of OpBuilder because it has additional helper - // functions. - IRRewriter rewriter(op->getContext()); - rewriter.setInsertionPoint(ifOp); - // Compute new types of the bufferized scf.if op. SmallVector newTypes; for (Type returnType : ifOp->getResultTypes()) { @@ -275,16 +270,11 @@ return true; } - LogicalResult bufferize(Operation *op, OpBuilder & /*b*/, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto forOp = cast(op); Block *oldLoopBody = &forOp.getLoopBody().front(); - // Use IRRewriter instead of OpBuilder because it has additional helper - // functions. - IRRewriter rewriter(op->getContext()); - rewriter.setInsertionPoint(forOp); - // Indices of all iter_args that have tensor type. These are the ones that // are bufferized. DenseSet indices; @@ -437,7 +427,7 @@ return OpResult(); } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto yieldOp = cast(op); if (!isa( diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/TensorInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/TensorInterfaceImpl.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/TensorInterfaceImpl.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/TensorInterfaceImpl.cpp @@ -61,7 +61,7 @@ return BufferRelation::Equivalent; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto castOp = cast(op); @@ -82,7 +82,8 @@ : MemRefLayoutAttrInterface(); Type memRefType = getContiguousOrUnrankedMemRefType( castOp.getResult().getType(), layout, memorySpace); - state.replaceOpWithNewOp(b, op, memRefType, resultBuffer); + state.replaceOpWithNewOp(rewriter, op, memRefType, + resultBuffer); return success(); } }; @@ -105,13 +106,13 @@ return OpResult(); } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto dimOp = cast(op); if (!dimOp.source().getType().isa()) return dimOp.emitError("unranked tensor not supported"); Value v = state.lookupBuffer(dimOp.source()); - state.replaceOpWithNewOp(b, op, v, dimOp.index()); + state.replaceOpWithNewOp(rewriter, op, v, dimOp.index()); return success(); } }; @@ -142,7 +143,7 @@ return BufferRelation::None; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto extractSliceOp = cast(op); Location loc = extractSliceOp.getLoc(); @@ -155,7 +156,8 @@ bool inplace = state.isInPlace(extractSliceOp->getResult(0)); Value alloc; if (!inplace) - alloc = state.createAllocDeallocPair(b, loc, extractSliceOp.result()); + alloc = + state.createAllocDeallocPair(rewriter, loc, extractSliceOp.result()); // Bufferize to subview. auto subviewMemRefType = @@ -164,7 +166,7 @@ extractSliceOp.getMixedOffsets(), extractSliceOp.getMixedSizes(), extractSliceOp.getMixedStrides()) .cast(); - Value subView = b.create( + Value subView = rewriter.create( loc, subviewMemRefType, srcMemref, extractSliceOp.getMixedOffsets(), extractSliceOp.getMixedSizes(), extractSliceOp.getMixedStrides()); @@ -172,7 +174,7 @@ if (!inplace) { // Do not copy if the copied data is never read. if (state.isValueRead(extractSliceOp.result())) - state.createMemCpy(b, extractSliceOp.getLoc(), subView, alloc); + state.createMemCpy(rewriter, extractSliceOp.getLoc(), subView, alloc); subView = alloc; } @@ -199,11 +201,11 @@ return OpResult(); } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto extractOp = cast(op); Value srcMemref = state.lookupBuffer(extractOp.tensor()); - state.replaceOpWithNewOp(b, op, srcMemref, + state.replaceOpWithNewOp(rewriter, op, srcMemref, extractOp.indices()); return success(); } @@ -235,13 +237,13 @@ return {&op->getOpOperand(1) /*dest*/}; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto insertOp = cast(op); Location loc = insertOp.getLoc(); Value destMemref = state.getResultBuffer(insertOp->getOpResult(0)); - b.create(loc, insertOp.scalar(), destMemref, - insertOp.indices()); + rewriter.create(loc, insertOp.scalar(), destMemref, + insertOp.indices()); state.replaceOp(op, destMemref); return success(); } @@ -407,7 +409,7 @@ return false; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { // insert_slice ops arise from tiling and bufferizing them out-of-place is // generally a deal breaker. When used with loops, this ends up cloning the @@ -434,12 +436,12 @@ insertSliceOp.getMixedOffsets(), insertSliceOp.getMixedSizes(), insertSliceOp.getMixedStrides()) .cast(); - Value subView = b.create( + Value subView = rewriter.create( loc, subviewMemRefType, dstMemref, insertSliceOp.getMixedOffsets(), insertSliceOp.getMixedSizes(), insertSliceOp.getMixedStrides()); // Copy tensor. Value srcMemref = state.lookupBuffer(insertSliceOp.source()); - state.createMemCpy(b, insertSliceOp.getLoc(), srcMemref, subView); + state.createMemCpy(rewriter, insertSliceOp.getLoc(), srcMemref, subView); } state.replaceOp(op, dstMemref); diff --git a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/VectorInterfaceImpl.cpp b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/VectorInterfaceImpl.cpp --- a/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/VectorInterfaceImpl.cpp +++ b/mlir/lib/Dialect/Linalg/ComprehensiveBufferize/VectorInterfaceImpl.cpp @@ -39,7 +39,7 @@ return OpResult(); } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto readOp = cast(op); assert(readOp.getShapedType().isa() && @@ -47,7 +47,7 @@ // TransferReadOp always reads from the bufferized op.source(). Value buffer = state.lookupBuffer(readOp.source()); - Value read = b.create( + Value read = rewriter.create( readOp.getLoc(), readOp.getVectorType(), buffer, readOp.indices(), readOp.permutation_map(), readOp.padding(), readOp.mask(), readOp.in_boundsAttr()); @@ -86,7 +86,7 @@ return BufferRelation::Equivalent; } - LogicalResult bufferize(Operation *op, OpBuilder &b, + LogicalResult bufferize(Operation *op, RewriterBase &rewriter, BufferizationState &state) const { auto writeOp = cast(op); assert(writeOp.getShapedType().isa() && @@ -98,7 +98,7 @@ Value resultBuffer = state.getResultBuffer(op->getResult(0)); if (!resultBuffer) return failure(); - b.create( + rewriter.create( writeOp.getLoc(), writeOp.vector(), resultBuffer, writeOp.indices(), writeOp.permutation_mapAttr(), writeOp.in_boundsAttr()); state.replaceOp(op, resultBuffer);