diff --git a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td --- a/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td +++ b/mlir/include/mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.td @@ -37,6 +37,25 @@ }]; } +def FuseOp : Op]> { + let description = [{ + Tiles the operations pointed to by the target handle and fuses their + producers greedily using the options provided as attributes. + }]; + + let arguments = + (ins PDL_Operation:$target, + DefaultValuedAttr:$tile_sizes, + DefaultValuedAttr:$tile_interchange); + let results = (outs PDL_Operation:$transformed, + Variadic:$loops); + + let hasCustomAssemblyFormat = 1; + let hasVerifier = 1; +} + def GeneralizeOp : Op { @@ -136,7 +155,7 @@ def TileOp : Op, - DeclareOpInterfaceMethods]> { + FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface]> { let description = [{ Indicates that the given `target` op should be tiled with the options provided as attributes. This transform generates a loop nest with a smaller diff --git a/mlir/include/mlir/Dialect/SCF/Patterns.h b/mlir/include/mlir/Dialect/SCF/Patterns.h --- a/mlir/include/mlir/Dialect/SCF/Patterns.h +++ b/mlir/include/mlir/Dialect/SCF/Patterns.h @@ -19,10 +19,10 @@ /// as option. This applies the mechanical transformation of changing the loop /// and generating the prologue/epilogue for the pipelining and doesn't make any /// decision regarding the schedule. -/// Based on the options the loop is split into several stages. +/// Based on the option the loop is split into several stages. /// The transformation assumes that the scheduling given by user is valid. /// For example if we break a loop into 3 stages named S0, S1, S2 we would -/// generate the following code with the number in parenthesis as the iteration +/// generate the following code with the number in parenthesis the iteration /// index: /// S0(0) // Prologue /// S0(1) S1(0) // Prologue diff --git a/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td b/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td --- a/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td +++ b/mlir/include/mlir/Dialect/SCF/TransformOps/SCFTransformOps.td @@ -16,10 +16,10 @@ include "mlir/Interfaces/SideEffectInterfaces.td" include "mlir/IR/OpBase.td" -def GetParentForOp : Op]> { - let summary = "Gets a handle to the parent 'for' loop of the given operation"; + let summary = "Gets a handle to the parent loop of the given operation"; let description = [{ Produces a handle to the n-th (default 1) parent `scf.for` loop for each Payload IR operation associated with the operand. Fails if such a loop @@ -44,8 +44,8 @@ let summary = "Outlines a loop into a named function"; let description = [{ Moves the loop into a separate function with the specified name and - replaces the loop in the Payload IR with a call to that function. Takes - care of forwarding values that are used in the loop as function arguments. + replaces the loop in the Payload IR with the call to that function. Takes + care or forwarding values that are used in the loop as function arguments. If the operand is associated with more than one loop, each loop will be outlined into a separate function. The provided name is used as a _base_ for forming actual function names following SymbolTable auto-renaming @@ -65,24 +65,17 @@ def LoopPeelOp : Op { - let summary = "Peels the last iteration of the loop"; + let summary = "Peels of the last iterations of the loop"; let description = [{ - Updates the given loop so that its step evenly divides its range and puts - the remaining iteration into a separate loop or a conditional. Note that - even though the Payload IR modification may be performed in-place, this + Updates the given loop so that its step evenly divides range and puts the + remaining iterations into a separate loop or a conditional. Note that even + though the Payload IR modification may be performed in-place, this operation consumes the operand handle and produces a new one. Applies to each loop associated with the operand handle individually. The results follow the same order as the operand. - - Note: If it can be proven statically that the step already evenly divides - the range, this op is a no-op. In the absence of sufficient static - information, this op may peel a loop, even if the step always divides the - range evenly at runtime. }]; - let arguments = - (ins PDL_Operation:$target, - DefaultValuedAttr:$fail_if_already_divisible); + let arguments = (ins PDL_Operation:$target); let results = (outs PDL_Operation:$transformed); let assemblyFormat = "$target attr-dict"; diff --git a/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.h b/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.h --- a/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.h +++ b/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.h @@ -451,16 +451,15 @@ StringRef getName() override { return "transform.payload_ir"; } }; -/// Trait implementing the MemoryEffectOpInterface for single-operand zero- or -/// single-result operations that "consume" their operand and produce a new -/// result. +/// Trait implementing the MemoryEffectOpInterface for single-operand operations +/// that "consume" their operand and produce a new result. template class FunctionalStyleTransformOpTrait : public OpTrait::TraitBase { public: /// This op "consumes" the operand by reading and freeing it, "produces" the - /// result by allocating and writing it and reads/writes the payload IR in the - /// process. + /// results by allocating and writing it and reads/writes the payload IR in + /// the process. void getEffects(SmallVectorImpl &effects) { effects.emplace_back(MemoryEffects::Read::get(), this->getOperation()->getOperand(0), @@ -468,12 +467,10 @@ effects.emplace_back(MemoryEffects::Free::get(), this->getOperation()->getOperand(0), TransformMappingResource::get()); - if (this->getOperation()->getNumResults() == 1) { - effects.emplace_back(MemoryEffects::Allocate::get(), - this->getOperation()->getResult(0), + for (Value result : this->getOperation()->getResults()) { + effects.emplace_back(MemoryEffects::Allocate::get(), result, TransformMappingResource::get()); - effects.emplace_back(MemoryEffects::Write::get(), - this->getOperation()->getResult(0), + effects.emplace_back(MemoryEffects::Write::get(), result, TransformMappingResource::get()); } effects.emplace_back(MemoryEffects::Read::get(), PayloadIRResource::get()); @@ -484,9 +481,6 @@ static LogicalResult verifyTrait(Operation *op) { static_assert(OpTy::template hasTrait(), "expected single-operand op"); - static_assert(OpTy::template hasTrait() || - OpTy::template hasTrait(), - "expected zero- or single-result op"); if (!op->getName().getInterface()) { op->emitError() << "FunctionalStyleTransformOpTrait should only be attached to ops " diff --git a/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.td b/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.td --- a/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.td +++ b/mlir/include/mlir/Dialect/Transform/IR/TransformInterfaces.td @@ -50,7 +50,7 @@ let extraSharedClassDeclaration = [{ /// Emits a generic transform error for the current transform operation - /// targeting the given Payload IR operation and returns failure. Should + /// targeting the given Payload IR opreation and returns failure. Should /// be only used as a last resort when the transformation itself provides /// no further indication as to the reason of the failure. ::mlir::LogicalResult reportUnknownTransformError( diff --git a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp --- a/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp +++ b/mlir/lib/Dialect/Linalg/TransformOps/LinalgTransformOps.cpp @@ -92,6 +92,130 @@ return reportUnknownTransformError(target); } +//===----------------------------------------------------------------------===// +// FuseOp +//===----------------------------------------------------------------------===// + +/// Apply a tiling transformation to all payload ops and store both the +/// tiled operation as well as the created tile loops. +static LogicalResult +applyTilingToAll(Operation *transformOp, Value target, + ArrayRef tileSizes, + transform::TransformResults &transformResults, + transform::TransformState &state, + function_ref(LinalgOp)> applyFn) { + // Number of loops: Number of tiles sizes that are not zero. + size_t numLoops = tileSizes.size() - llvm::count(tileSizes, 0); + // All payload ops. These should all be LinalgOps for now. + ArrayRef payloadOps = state.getPayloadOps(target); + + SmallVector tiledLinalgOps; + SmallVector> loopOps(numLoops); + for (unsigned int i = 0; i < numLoops; ++i) + loopOps[i].reserve(payloadOps.size()); + + for (Operation *target : payloadOps) { + auto linalgOp = dyn_cast(target); + if (!linalgOp) + return transformOp->emitError("only LinalgOps are supported"); + + FailureOr tiled = applyFn(linalgOp); + if (failed(tiled)) + return failure(); + + tiledLinalgOps.push_back(tiled->op); + if (tiled->loops.size() != numLoops) + // Not enough loops were generated. This usually means that the input size + // was smaller than the tiling size. + // TODO: LinalgTilingPattern should return failure(). + return failure(); + for (unsigned int i = 0; i < numLoops; ++i) + loopOps[i].push_back(tiled->loops[i]); + } + + transformResults.set(transformOp->getOpResult(0), tiledLinalgOps); + for (unsigned int i = 0; i < numLoops; ++i) + transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]); + return success(); +} + +/// Parse a tiling-like operation that returns the tiled op as well as the +/// created tile loops. The function counts the non-zero tile sizes to compute +/// the number of results. +static ParseResult parseTileLikeOp(OpAsmParser &parser, OperationState &result, + StringRef sizesAttrName) { + OpAsmParser::UnresolvedOperand targetOperand; + SMLoc opLoc = parser.getCurrentLocation(); + if (parser.parseOperand(targetOperand) || + parser.parseOptionalAttrDict(result.attributes)) + return failure(); + Attribute sizesAttr = result.attributes.get(sizesAttrName); + if (!sizesAttr) + return parser.emitError(opLoc) + << "expected '" << sizesAttrName << "' attribute"; + auto sizesArrayAttr = sizesAttr.dyn_cast(); + if (!sizesArrayAttr) + return parser.emitError(opLoc) + << "'" << sizesAttrName << "' attribute must be an array"; + Type pdlOpType = parser.getBuilder().getType(); + size_t numExpectedLoops = + sizesArrayAttr.size() - llvm::count(extractI64Array(sizesArrayAttr), 0); + result.addTypes(SmallVector(numExpectedLoops + 1, pdlOpType)); + if (parser.resolveOperand(targetOperand, pdlOpType, result.operands)) + return failure(); + return success(); +} + +LogicalResult +transform::FuseOp::apply(mlir::transform::TransformResults &transformResults, + mlir::transform::TransformState &state) { + LinalgTilingAndFusionOptions fusionOptions; + fusionOptions.tileSizes = extractI64Array(getTileSizes()); + fusionOptions.tileInterchange = extractI64Array(getTileInterchange()); + + return applyTilingToAll( + getOperation(), getTarget(), fusionOptions.tileSizes, transformResults, + state, [&](LinalgOp linalgOp) -> FailureOr { + LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions); + SimpleRewriter rewriter(getContext()); + rewriter.setInsertionPoint(linalgOp); + FailureOr tileLoopNest = + pattern.returningMatchAndRewrite(linalgOp, rewriter); + if (failed(tileLoopNest)) + return failure(); + + TiledLinalgOp tiledLinalgOp; + tiledLinalgOp.op = tileLoopNest->getRootOp(); + tiledLinalgOp.loops = {tileLoopNest->getLoopOps().begin(), + tileLoopNest->getLoopOps().end()}; + return tiledLinalgOp; + }); +} + +ParseResult transform::FuseOp::parse(OpAsmParser &parser, + OperationState &result) { + return parseTileLikeOp( + parser, result, + transform::FuseOp::getTileSizesAttrName(result.name).getValue()); +} + +void transform::FuseOp::print(OpAsmPrinter &p) { + p << ' '; + p << getTarget(); + p.printOptionalAttrDict((*this)->getAttrs()); +} + +LogicalResult transform::FuseOp::verify() { + SmallVector permutation = extractI64Array(getTileInterchange()); + auto sequence = llvm::to_vector(llvm::seq(0, permutation.size())); + if (!std::is_permutation(sequence.begin(), sequence.end(), + permutation.begin(), permutation.end())) { + return emitOpError() << "expects interchange to be a permutation, found " + << getTileInterchange(); + } + return success(); +} + //===----------------------------------------------------------------------===// // GeneralizeOp //===----------------------------------------------------------------------===// @@ -274,49 +398,6 @@ // TileOp //===----------------------------------------------------------------------===// -/// Apply a tiling transformation to all payload ops and store both the -/// tiled operation as well as the created tile loops. -static LogicalResult -applyTilingToAll(Operation *transformOp, Value target, - ArrayRef tileSizes, - transform::TransformResults &transformResults, - transform::TransformState &state, - function_ref(LinalgOp)> applyFn) { - // Number of loops: Number of tiles sizes that are not zero. - size_t numLoops = tileSizes.size() - llvm::count(tileSizes, 0); - // All payload ops. These should all be LinalgOps for now. - ArrayRef payloadOps = state.getPayloadOps(target); - - SmallVector tiledLinalgOps; - SmallVector> loopOps(numLoops); - for (unsigned int i = 0; i < numLoops; ++i) - loopOps[i].reserve(payloadOps.size()); - - for (Operation *target : payloadOps) { - auto linalgOp = dyn_cast(target); - if (!linalgOp) - return transformOp->emitError("only LinalgOps are supported"); - - FailureOr tiled = applyFn(linalgOp); - if (failed(tiled)) - return failure(); - - tiledLinalgOps.push_back(tiled->op); - if (tiled->loops.size() != numLoops) - // Not enough loops were generated. This usually means that the input size - // was smaller than the tiling size. - // TODO: LinalgTilingPattern should return failure(). - return failure(); - for (unsigned int i = 0; i < numLoops; ++i) - loopOps[i].push_back(tiled->loops[i]); - } - - transformResults.set(transformOp->getOpResult(0), tiledLinalgOps); - for (unsigned int i = 0; i < numLoops; ++i) - transformResults.set(transformOp->getOpResult(i + 1), loopOps[i]); - return success(); -} - LogicalResult transform::TileOp::apply(TransformResults &transformResults, TransformState &state) { LinalgTilingOptions tilingOptions; @@ -337,27 +418,8 @@ ParseResult transform::TileOp::parse(OpAsmParser &parser, OperationState &result) { - StringRef sizesAttrName = TileOp::getSizesAttrName(result.name).getValue(); - OpAsmParser::UnresolvedOperand targetOperand; - SMLoc opLoc = parser.getCurrentLocation(); - if (parser.parseOperand(targetOperand) || - parser.parseOptionalAttrDict(result.attributes)) - return failure(); - Attribute sizesAttr = result.attributes.get(sizesAttrName); - if (!sizesAttr) - return parser.emitError(opLoc) - << "expected '" << sizesAttrName << "' attribute"; - auto sizesArrayAttr = sizesAttr.dyn_cast(); - if (!sizesArrayAttr) - return parser.emitError(opLoc) - << "'" << sizesAttrName << "' attribute must be an array"; - Type pdlOpType = parser.getBuilder().getType(); - size_t numExpectedLoops = - sizesArrayAttr.size() - llvm::count(extractI64Array(sizesArrayAttr), 0); - result.addTypes(SmallVector(numExpectedLoops + 1, pdlOpType)); - if (parser.resolveOperand(targetOperand, pdlOpType, result.operands)) - return failure(); - return success(); + return parseTileLikeOp(parser, result, + TileOp::getSizesAttrName(result.name).getValue()); } void TileOp::print(OpAsmPrinter &p) { @@ -366,26 +428,6 @@ p.printOptionalAttrDict((*this)->getAttrs()); } -void TileOp::getEffects( - SmallVectorImpl> - &effects) { - // `target` arg is consumed and can no longer be used. - effects.emplace_back(MemoryEffects::Read::get(), getTarget(), - TransformMappingResource::get()); - effects.emplace_back(MemoryEffects::Free::get(), getTarget(), - TransformMappingResource::get()); - - for (Value r : getResults()) { - effects.emplace_back(MemoryEffects::Write::get(), r, - TransformMappingResource::get()); - effects.emplace_back(MemoryEffects::Allocate::get(), r, - TransformMappingResource::get()); - } - - effects.emplace_back(MemoryEffects::Read::get(), PayloadIRResource::get()); - effects.emplace_back(MemoryEffects::Write::get(), PayloadIRResource::get()); -} - //===----------------------------------------------------------------------===// // VectorizeOp //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp b/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp --- a/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp +++ b/mlir/lib/Dialect/SCF/TransformOps/SCFTransformOps.cpp @@ -27,12 +27,12 @@ } // namespace //===----------------------------------------------------------------------===// -// GetParentForOp +// GetParentLoopOp //===----------------------------------------------------------------------===// LogicalResult -transform::GetParentForOp::apply(transform::TransformResults &results, - transform::TransformState &state) { +transform::GetParentLoopOp::apply(transform::TransformResults &results, + transform::TransformState &state) { SetVector parents; for (Operation *target : state.getPayloadOps(getTarget())) { scf::ForOp loop; @@ -127,11 +127,8 @@ IRRewriter rewriter(loop->getContext()); LogicalResult status = scf::peelAndCanonicalizeForLoop(rewriter, loop, result); - if (failed(status)) { - if (getFailIfAlreadyDivisible()) - return reportUnknownTransformError(loop); + if (failed(status)) return loop; - } return result; } diff --git a/mlir/python/mlir/dialects/_loop_transform_ops_ext.py b/mlir/python/mlir/dialects/_loop_transform_ops_ext.py --- a/mlir/python/mlir/dialects/_loop_transform_ops_ext.py +++ b/mlir/python/mlir/dialects/_loop_transform_ops_ext.py @@ -24,8 +24,8 @@ return IntegerAttr.get(IntegerType.get_signless(64), arg) -class GetParentForOp: - """Extension for GetParentForOp.""" +class GetParentLoopOp: + """Extension for GetParentLoopOp.""" def __init__(self, target: Union[Operation, Value], @@ -62,18 +62,10 @@ class LoopPeelOp: """Extension for LoopPeelOp.""" - def __init__(self, - target: Union[Operation, Value], - *, - fail_if_already_divisible: Union[bool, BoolAttr] = False, - ip=None, - loc=None): + def __init__(self, target: Union[Operation, Value], *, ip=None, loc=None): super().__init__( pdl.OperationType.get(), _get_op_result_or_value(target), - fail_if_already_divisible=(fail_if_already_divisible if isinstance( - fail_if_already_divisible, BoolAttr) else - BoolAttr.get(fail_if_already_divisible)), ip=ip, loc=loc) diff --git a/mlir/test/Dialect/Linalg/transform-op-fuse.mlir b/mlir/test/Dialect/Linalg/transform-op-fuse.mlir new file mode 100644 --- /dev/null +++ b/mlir/test/Dialect/Linalg/transform-op-fuse.mlir @@ -0,0 +1,70 @@ +// RUN: mlir-opt %s --test-transform-dialect-interpreter --split-input-file | FileCheck %s + +// CHECK-LABEL: func.func @fuse_unary +func.func @fuse_unary(%arg0: tensor, %arg1: tensor) -> tensor { + + // CHECK: scf.for + // CHECK: scf.for + // CHECK: linalg.elemwise_unary + // CHECK: linalg.elemwise_binary + %0 = linalg.elemwise_unary ins(%arg0 : tensor) + outs(%arg1: tensor) -> tensor + %1 = linalg.elemwise_binary ins(%0, %arg0 : tensor, tensor) + outs(%arg1: tensor) -> tensor + return %1 : tensor +} + +transform.with_pdl_patterns { +^bb0(%arg0: !pdl.operation): + pdl.pattern @pdl_target : benefit(1) { + %args = operands + %results = types + %0 = pdl.operation "linalg.elemwise_binary"(%args : !pdl.range) -> (%results : !pdl.range) + // TODO: we don't want this, but it is the required terminator for pdl.pattern + rewrite %0 with "transform.dialect" + } + + transform.sequence %arg0 { + ^bb1(%arg1: !pdl.operation): + %0 = pdl_match @pdl_target in %arg1 + %1, %loops:2 = transform.structured.fuse %0 {tile_sizes = [32, 32], tile_interchange = [0, 1]} + } +} + +// ----- + +// CHECK-LABEL: func.func @fuse_unary +func.func @fuse_unary(%arg0: tensor, %arg1: tensor) -> tensor { + + // CHECK: scf.for + // CHECK: scf.for + // CHECK: linalg.elemwise_unary + // CHECK: linalg.elemwise_binary + // CHECK: scf.for + // CHECK: scf.for + // CHECK: linalg.elemwise_unary + // CHECK: linalg.elemwise_binary + %0 = linalg.elemwise_unary ins(%arg0 : tensor) + outs(%arg1: tensor) -> tensor + %1 = linalg.elemwise_binary ins(%0, %arg0 : tensor, tensor) + outs(%arg1: tensor) -> tensor + return %1 : tensor +} + +transform.with_pdl_patterns { +^bb0(%arg0: !pdl.operation): + pdl.pattern @pdl_target : benefit(1) { + %args = operands + %results = types + %0 = pdl.operation "linalg.elemwise_binary"(%args : !pdl.range) -> (%results : !pdl.range) + // TODO: we don't want this, but it is the required terminator for pdl.pattern + rewrite %0 with "transform.dialect" + } + + transform.sequence %arg0 { + ^bb1(%arg1: !pdl.operation): + %0 = pdl_match @pdl_target in %arg1 + %1, %loops:2 = transform.structured.fuse %0 {tile_sizes = [32, 32], tile_interchange = [0, 1]} + transform.loop.peel %loops#0 + } +} diff --git a/mlir/test/Dialect/SCF/transform-ops.mlir b/mlir/test/Dialect/SCF/transform-ops.mlir --- a/mlir/test/Dialect/SCF/transform-ops.mlir +++ b/mlir/test/Dialect/SCF/transform-ops.mlir @@ -1,7 +1,7 @@ // RUN: mlir-opt %s -test-transform-dialect-interpreter -split-input-file -verify-diagnostics | FileCheck %s -// CHECK-LABEL: @get_parent_for_op -func.func @get_parent_for_op(%arg0: index, %arg1: index, %arg2: index) { +// CHECK-LABEL: @get_parent_loop_op +func.func @get_parent_loop_op(%arg0: index, %arg1: index, %arg2: index) { // expected-remark @below {{first loop}} scf.for %i = %arg0 to %arg1 step %arg2 { // expected-remark @below {{second loop}} @@ -27,10 +27,10 @@ sequence %arg0 { ^bb1(%arg1: !pdl.operation): %0 = pdl_match @match_addi in %arg1 - // CHECK: = transform.loop.get_parent_for - %1 = transform.loop.get_parent_for %0 - %2 = transform.loop.get_parent_for %0 { num_loops = 2 } - %3 = transform.loop.get_parent_for %0 { num_loops = 3 } + // CHECK: = transform.loop.get_parent_loop + %1 = transform.loop.get_parent_loop %0 + %2 = transform.loop.get_parent_loop %0 { num_loops = 2 } + %3 = transform.loop.get_parent_loop %0 { num_loops = 3 } transform.test_print_remark_at_operand %1, "third loop" transform.test_print_remark_at_operand %2, "second loop" transform.test_print_remark_at_operand %3, "first loop" @@ -39,7 +39,7 @@ // ----- -func.func @get_parent_for_op_no_loop(%arg0: index, %arg1: index) { +func.func @get_parent_loop_op_no_loop(%arg0: index, %arg1: index) { // expected-note @below {{target op}} arith.addi %arg0, %arg1 : index return @@ -58,7 +58,7 @@ ^bb1(%arg1: !pdl.operation): %0 = pdl_match @match_addi in %arg1 // expected-error @below {{could not find an 'scf.for' parent}} - %1 = transform.loop.get_parent_for %0 + %1 = transform.loop.get_parent_loop %0 } } @@ -106,7 +106,7 @@ sequence %arg0 { ^bb1(%arg1: !pdl.operation): %0 = pdl_match @match_addi in %arg1 - %1 = transform.loop.get_parent_for %0 + %1 = transform.loop.get_parent_loop %0 // CHECK: = transform.loop.outline %{{.*}} transform.loop.outline %1 {func_name = "foo"} } @@ -180,7 +180,7 @@ sequence %arg0 { ^bb1(%arg1: !pdl.operation): %0 = pdl_match @match_addi in %arg1 - %1 = transform.loop.get_parent_for %0 + %1 = transform.loop.get_parent_loop %0 transform.loop.peel %1 } } @@ -223,7 +223,7 @@ sequence %arg0 { ^bb1(%arg1: !pdl.operation): %0 = pdl_match @match_addf in %arg1 - %1 = transform.loop.get_parent_for %0 + %1 = transform.loop.get_parent_loop %0 %2 = transform.loop.pipeline %1 // Verify that the returned handle is usable. transform.test_print_remark_at_operand %2, "transformed" @@ -257,7 +257,7 @@ sequence %arg0 { ^bb1(%arg1: !pdl.operation): %0 = pdl_match @match_addi in %arg1 - %1 = transform.loop.get_parent_for %0 + %1 = transform.loop.get_parent_loop %0 transform.loop.unroll %1 { factor = 4 } } } diff --git a/mlir/test/python/dialects/transform_loop_ext.py b/mlir/test/python/dialects/transform_loop_ext.py --- a/mlir/test/python/dialects/transform_loop_ext.py +++ b/mlir/test/python/dialects/transform_loop_ext.py @@ -20,10 +20,10 @@ def getParentLoop(): sequence = transform.SequenceOp() with InsertionPoint(sequence.body): - loop.GetParentForOp(sequence.bodyTarget, num_loops=2) + loop.GetParentLoopOp(sequence.bodyTarget, num_loops=2) transform.YieldOp() # CHECK-LABEL: TEST: getParentLoop - # CHECK: = transform.loop.get_parent_for % + # CHECK: = transform.loop.get_parent_loop % # CHECK: num_loops = 2