[mlir] Allow Tile transform op to take dynamic sizes

Extend the definition of the Tile structured transform op to enable it
accepting handles to operations that produce tile sizes at runtime. This is
useful by itself and prepares for more advanced tiling strategies. Note that
the changes are relevant only to the transform dialect, the tiling
transformation itself already supports dynamic sizes.

Depends On D129216

Reviewed By: nicolasvasilache

Differential Revision: https://reviews.llvm.org/D129217
This commit is contained in:
Alex Zinenko 2022-07-07 15:55:44 +02:00
parent 7b69843f0b
commit 4e4a4c0576
12 changed files with 296 additions and 66 deletions

View File

@ -396,28 +396,59 @@ def SplitReductionOp : Op<Transform_Dialect, "structured.split_reduction",
def TileOp : Op<Transform_Dialect, "structured.tile",
[DeclareOpInterfaceMethods<TransformOpInterface>,
FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface]> {
DeclareOpInterfaceMethods<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
("tiled") target operation in its body. Currently limited to LinalgOps.
Indicates that the given `target` op should be tiled with the given sizes.
This transform generates a loop nest with a smaller ("tiled") target
operation in its body. Currently limited to LinalgOps.
`sizes` are the tile sizes. A tile size of `0` indicates that the
respective dimension should not be tiled. No loop will be generated for such
dimensions. If all tile sizes are `0`, this transform is effectively a
no-op.
Tile sizes may be known at transformation time, in which case they are
expected to be provided in the `static_size` attribute, or not, in which
case the tile value must be computed by the payload IR and the handle to the
operation computing it must be provided through `dynamic_sizes`. When the
sizes are not known statically, the corresponding entry in the
`static_sizes` attribute must be set to `ShapedType::kDynamicSize`. Only
the dynamic sizes must be provided in `dynamic_sizes`, i.e., there should
be as many handles as `ShapedType::kDynamicSize` values in the
`static_sizes` attribute. A static size of `0` indicates that the dimension
should not be tiled. No loop will be generated for such dimensions. If all
tile sizes are `0`, this transform is effectively a no-op.
This op returns handles to the tiled op (in the generated loop nest) and the
generated loops. The number of loops is the number of non-zero tile sizes.
generated loops. The number of loops is the number of tile sizes that are
statically known to be non-zero.
#### Return modes
On success, the resulting handles are associated with co-indexed lists of
tiled operations and loops around them.
This operation only supports Linalg ops and produces a silenceable failure
if the input contains any non-Linalg ops. The ops preceding it in the list
associated with the `target` handle will have been tiled.
This operation produces a silenceable failure if the `dynamic_sizes` handles
are associated with lists of payload operations of a size different than
that of the list associated with the `target` handle.
If the internal implementation of tiling for any of the operations fails,
produces a definite failure.
}];
let arguments = (ins PDL_Operation:$target,
DefaultValuedAttr<I64ArrayAttr, "{}">:$sizes,
Variadic<PDL_Operation>:$dynamic_sizes,
DefaultValuedAttr<I64ArrayAttr, "{}">:$static_sizes,
DefaultValuedAttr<I64ArrayAttr, "{}">:$interchange);
let results = (outs PDL_Operation:$tiled_linalg_op,
Variadic<PDL_Operation>:$loops);
let hasCustomAssemblyFormat = 1;
let extraClassDeclaration = [{
/// Returns the list of tile sizes, which may be static (Attribute) or
/// dynamic (Value).
SmallVector<OpFoldResult> getMixedSizes();
}];
}
def VectorizeOp : Op<Transform_Dialect, "structured.vectorize",

View File

@ -210,6 +210,11 @@ SmallVector<Value> insertSlicesBack(OpBuilder &builder, Location loc,
LinalgOp op, ValueRange operands,
ValueRange results);
/// Turns an OpFoldResult into a value, creating an index-typed constant if
/// necessary.
Value materializeOpFoldResult(ImplicitLocOpBuilder &builder,
OpFoldResult opFoldResult);
/// Creates an extract_slice/subview op for a single `valueToTile` with
/// `builder`. This new operation extracts a tile of `valueToTile`, starting
/// at offsets `lbs` and with sizes `subShapeSizes`. `omitPartialTileCheck`

View File

@ -8,6 +8,7 @@
#include "mlir/Dialect/Linalg/TransformOps/LinalgTransformOps.h"
#include "mlir/Dialect/Arithmetic/IR/Arithmetic.h"
#include "mlir/Dialect/Linalg/IR/Linalg.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/Dialect/PDL/IR/PDL.h"
@ -103,16 +104,10 @@ transform::DecomposeOp::applyToOne(linalg::LinalgOp target,
/// 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<int64_t> tileSizes,
applyTilingToAll(Operation *transformOp, ArrayRef<Operation *> payloadOps,
unsigned numLoops,
transform::TransformResults &transformResults,
transform::TransformState &state,
function_ref<FailureOr<TiledLinalgOp>(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<Operation *> payloadOps = state.getPayloadOps(target);
SmallVector<Operation *> tiledLinalgOps;
SmallVector<SmallVector<Operation *>> loopOps(numLoops);
for (unsigned int i = 0; i < numLoops; ++i)
@ -178,8 +173,9 @@ transform::FuseOp::apply(mlir::transform::TransformResults &transformResults,
fusionOptions.tileInterchange = extractI64Array(getTileInterchange());
LogicalResult result = applyTilingToAll(
getOperation(), getTarget(), fusionOptions.tileSizes, transformResults,
state, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
getOperation(), state.getPayloadOps(getTarget()),
fusionOptions.tileSizes.size() - llvm::count(fusionOptions.tileSizes, 0),
transformResults, [&](LinalgOp linalgOp) -> FailureOr<TiledLinalgOp> {
LinalgTileAndFuseTensorOpsPattern pattern(getContext(), fusionOptions);
SimpleRewriter rewriter(getContext());
rewriter.setInsertionPoint(linalgOp);
@ -194,8 +190,7 @@ transform::FuseOp::apply(mlir::transform::TransformResults &transformResults,
tileLoopNest->getLoopOps().end()};
return tiledLinalgOp;
});
return failed(result) ? DiagnosedSilenceableFailure::definiteFailure()
: DiagnosedSilenceableFailure::success();
return DiagnosedSilenceableFailure(result);
}
ParseResult transform::FuseOp::parse(OpAsmParser &parser,
@ -603,32 +598,141 @@ DiagnosedSilenceableFailure
transform::TileOp::apply(TransformResults &transformResults,
TransformState &state) {
LinalgTilingOptions tilingOptions;
SmallVector<int64_t> tileSizes = extractI64Array(getSizes());
SmallVector<int64_t> tileSizes = extractI64Array(getStaticSizes());
ArrayRef<Operation *> targets = state.getPayloadOps(getTarget());
SmallVector<ArrayRef<Operation *>> dynamicSizeProducers;
dynamicSizeProducers.reserve(getDynamicSizes().size());
for (Value dynamicSizeProducerHandle : getDynamicSizes()) {
dynamicSizeProducers.push_back(
state.getPayloadOps(dynamicSizeProducerHandle));
if (dynamicSizeProducers.back().size() != targets.size()) {
DiagnosedSilenceableFailure diag =
emitSilenceableError()
<< "expected as many dynamic size-producing operations ("
<< dynamicSizeProducers.back().size() << ") as target ops ("
<< targets.size() << ")";
diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
return diag;
}
for (Operation *op : dynamicSizeProducers.back()) {
if (op->getNumResults() == 1 &&
op->getResult(0).getType().isa<IndexType>())
continue;
DiagnosedSilenceableFailure diag =
emitSilenceableError() << "expected sizes to be produced by ops "
"with a single index-type result";
diag.attachNote(op->getLoc()) << "size producer op";
diag.attachNote(dynamicSizeProducerHandle.getLoc()) << "for this handle";
return diag;
}
}
SmallVector<Operation *> tiled;
SmallVector<SmallVector<Operation *, 4>, 4> loops;
loops.resize(getLoops().size());
for (auto &en : llvm::enumerate(targets)) {
auto linalgOp = dyn_cast<LinalgOp>(en.value());
if (!linalgOp) {
DiagnosedSilenceableFailure diag = emitSilenceableError()
<< "only linalg ops are supported";
diag.attachNote(en.value()->getLoc()) << "target op";
return diag;
}
unsigned index = en.index();
if (!tileSizes.empty()) {
tilingOptions.setTileSizeComputationFunction(
[&, index](OpBuilder &b, Operation *) {
SmallVector<Value, 4> sizes;
sizes.reserve(tileSizes.size());
unsigned dynamicIdx = 0;
for (OpFoldResult ofr : getMixedSizes()) {
if (auto attr = ofr.dyn_cast<Attribute>()) {
sizes.push_back(b.create<arith::ConstantIndexOp>(
getLoc(), attr.cast<IntegerAttr>().getInt()));
} else {
sizes.push_back(
dynamicSizeProducers[dynamicIdx++][index]->getResult(0));
}
}
return sizes;
});
}
if (!tileSizes.empty())
tilingOptions.setTileSizes(tileSizes);
tilingOptions.setInterchange(extractUIntArray(getInterchange()));
LinalgTilingPattern pattern(getContext(), tilingOptions);
LogicalResult result = applyTilingToAll(
getOperation(), getTarget(), tileSizes, transformResults, state,
[&](LinalgOp linalgOp) {
SimpleRewriter rewriter(linalgOp.getContext());
return pattern.returningMatchAndRewrite(linalgOp, rewriter);
});
return DiagnosedSilenceableFailure(result);
FailureOr<TiledLinalgOp> tiledOp =
pattern.returningMatchAndRewrite(linalgOp, rewriter);
if (failed(tiledOp))
return DiagnosedSilenceableFailure::definiteFailure();
tiled.push_back(tiledOp->op);
for (const auto &en2 : llvm::enumerate(tiledOp->loops))
loops[en2.index()].push_back(en2.value());
}
transformResults.set(getTiledLinalgOp().cast<OpResult>(), tiled);
for (const auto &en : llvm::enumerate(loops))
transformResults.set(getLoops()[en.index()].cast<OpResult>(), en.value());
return DiagnosedSilenceableFailure::success();
}
SmallVector<OpFoldResult> transform::TileOp::getMixedSizes() {
ValueRange dynamic = getDynamicSizes();
SmallVector<int64_t> tileSizes = extractI64Array(getStaticSizes());
SmallVector<OpFoldResult> results;
results.reserve(tileSizes.size());
unsigned dynamicPos = 0;
Builder builder(getContext());
for (int64_t size : tileSizes) {
if (size == ShapedType::kDynamicSize) {
results.push_back(dynamic[dynamicPos++]);
} else {
results.push_back(builder.getIndexAttr(size));
}
}
return results;
}
ParseResult transform::TileOp::parse(OpAsmParser &parser,
OperationState &result) {
return parseTileLikeOp(parser, result,
TileOp::getSizesAttrName(result.name).getValue());
OpAsmParser::UnresolvedOperand target;
SmallVector<OpAsmParser::UnresolvedOperand> dynamicSizes;
ArrayAttr staticSizes;
auto pdlOperationType = pdl::OperationType::get(parser.getContext());
if (parser.parseOperand(target) ||
parser.resolveOperand(target, pdlOperationType, result.operands) ||
parseOperandsOrIntegersSizesList(parser, dynamicSizes, staticSizes) ||
parser.resolveOperands(dynamicSizes, pdlOperationType, result.operands) ||
parser.parseOptionalAttrDict(result.attributes))
return ParseResult::failure();
result.addAttribute(getStaticSizesAttrName(result.name), staticSizes);
size_t numExpectedLoops =
staticSizes.size() - llvm::count(extractI64Array(staticSizes), 0);
result.addTypes(SmallVector<Type>(numExpectedLoops + 1, pdlOperationType));
return success();
}
void TileOp::print(OpAsmPrinter &p) {
p << ' ';
p << getTarget();
p.printOptionalAttrDict((*this)->getAttrs());
p << ' ' << getTarget();
printOperandsOrIntegersSizesList(p, getOperation(), getDynamicSizes(),
getStaticSizes());
p.printOptionalAttrDict((*this)->getAttrs(), {getStaticSizesAttrName()});
}
void transform::TileOp::getEffects(
SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
consumesHandle(getTarget(), effects);
onlyReadsHandle(getDynamicSizes(), effects);
producesHandle(getTiledLinalgOp(), effects);
producesHandle(getLoops(), effects);
modifiesPayload(effects);
}
//===----------------------------------------------------------------------===//
@ -678,6 +782,7 @@ class LinalgTransformDialectExtension
LinalgTransformDialectExtension> {
public:
LinalgTransformDialectExtension() {
declareDependentDialect<arith::ArithmeticDialect>();
declareDependentDialect<pdl::PDLDialect>();
declareDependentDialect<scf::SCFDialect>();
declareDependentDialect<vector::VectorDialect>();

View File

@ -15,16 +15,6 @@
using namespace mlir;
using namespace mlir::linalg;
/// Turns an OpFoldResult into a value, creating an index-typed constant if
/// necessary.
static Value materializeOpFoldResult(ImplicitLocOpBuilder &builder,
OpFoldResult opFoldResult) {
if (opFoldResult.is<Value>())
return opFoldResult.get<Value>();
auto attr = opFoldResult.get<Attribute>().cast<IntegerAttr>();
return builder.create<arith::ConstantIndexOp>(attr.getValue().getSExtValue());
}
/// Extract the slices of `operands` supplied to the given operation `op` such
/// that they are sufficient to execute the op for the subset of its iteration
/// space defined by `splitIterationSpace`. The subset is a part of the original

View File

@ -993,6 +993,14 @@ SmallVector<Value> insertSlicesBack(OpBuilder &builder, Location loc,
return tensorResults;
}
Value materializeOpFoldResult(ImplicitLocOpBuilder &builder,
OpFoldResult opFoldResult) {
if (auto value = opFoldResult.dyn_cast<Value>())
return value;
auto attr = opFoldResult.get<Attribute>().cast<IntegerAttr>();
return builder.create<arith::ConstantIndexOp>(attr.getValue().getSExtValue());
}
SmallVector<Value, 4> makeTiledShapes(OpBuilder &b, Location loc,
LinalgOp linalgOp,
ArrayRef<Value> valuesToTile,

View File

@ -191,18 +191,40 @@ class TileOp:
def __init__(self,
target: Union[Operation, Value],
*,
sizes: OptionalIntList = None,
sizes: Optional[Union[Sequence[Union[int, IntegerAttr, Operation,
Value]], ArrayAttr]] = None,
interchange: OptionalIntList = None,
loc=None,
ip=None):
pdl_operation_type = pdl.OperationType.get()
sizes_attr = _get_int_array_attr(sizes)
i64_type = IntegerType.get_signless(64)
if sizes is None:
sizes = []
static_sizes = []
dynamic_sizes = []
if isinstance(sizes, ArrayAttr):
sizes_attr = sizes
else:
for size in sizes:
if isinstance(size, int):
static_sizes.append(IntegerAttr.get(i64_type, size))
elif isinstance(size, IntegerAttr):
static_sizes.append(size)
else:
static_sizes.append(
IntegerAttr.get(i64_type, ShapedType._get_dynamic_size()))
dynamic_sizes.append(_get_op_result_or_value(size))
sizes_attr = ArrayAttr.get(static_sizes)
num_loops = sum(
v if v == 0 else 1 for v in self.__extract_values(sizes_attr))
super().__init__(
pdl_operation_type, [pdl_operation_type] * num_loops,
_get_op_result_or_value(target),
sizes=sizes_attr,
dynamic_sizes=dynamic_sizes,
static_sizes=sizes_attr,
interchange=_get_int_array_attr(interchange) if interchange else None,
loc=loc,
ip=ip)

View File

@ -23,7 +23,7 @@ transform.with_pdl_patterns {
transform.sequence %arg0 {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @pdl_target in %arg1
%1, %loops = transform.structured.tile %0 {sizes = [10, 0, 0]}
%1, %loops = transform.structured.tile %0 [10, 0, 0]
%2 = transform.structured.scalarize %1
}
}

View File

@ -1,11 +1,11 @@
// RUN: mlir-opt --test-transform-dialect-interpreter %s | FileCheck %s
// RUN: mlir-opt --test-transform-dialect-interpreter --split-input-file %s | FileCheck %s
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
sequence %arg0 {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @pdl_target in %arg1
%1, %loops:3 = transform.structured.tile %0 {sizes = [4, 4, 4]}
%1, %loops:3 = transform.structured.tile %0 [4, 4, 4]
}
pdl.pattern @pdl_target : benefit(1) {
@ -44,3 +44,58 @@ func.func @tile_linalg_matmul(
return %0 : tensor<128x128xf32>
}
// -----
transform.with_pdl_patterns {
^bb0(%arg0: !pdl.operation):
sequence %arg0 {
^bb0(%arg1: !pdl.operation):
%0 = pdl_match @pdl_target in %arg1
%1 = pdl_match @func_call in %arg1
%2, %loops:3 = transform.structured.tile %0 [%1, %1, 4]
}
pdl.pattern @pdl_target : benefit(1) {
%args = operands
%results = types
%0 = operation "linalg.matmul"(%args : !pdl.range<value>) -> (%results : !pdl.range<type>)
rewrite %0 with "transform.dialect"
}
pdl.pattern @func_call : benefit(1) {
%args = operands
%results = types
%0 = operation "func.call"(%args : !pdl.range<value>) -> (%results : !pdl.range<type>)
rewrite %0 with "transform.dialect"
}
}
func.func private @get_dynamic_tile_size() -> index
// CHECK-LABEL: func @tile_linalg_matmul_dynamic(
// CHECK-SAME: %[[TA:[0-9a-z]+]]: tensor<128x128xf32>
// CHECK-SAME: %[[TB:[0-9a-z]+]]: tensor<128x128xf32>
// CHECK-SAME: %[[TC:[0-9a-z]+]]: tensor<128x128xf32>
// CHECK-SAME: -> tensor<128x128xf32> {
func.func @tile_linalg_matmul_dynamic(
%arg0: tensor<128x128xf32>, %arg1: tensor<128x128xf32>, %arg2: tensor<128x128xf32>)
-> tensor<128x128xf32> {
// CHECK: %[[TD0:.*]] = scf.for {{.*}} to {{.*}} step {{.*}} iter_args(%[[TC0:.*]] = %[[TC]]) -> (tensor<128x128xf32>) {
// CHECK: %[[TD1:.*]] = scf.for {{.*}} to {{.*}} step {{.*}} iter_args(%[[TC1:.*]] = %[[TC0]]) -> (tensor<128x128xf32>) {
// CHECK: %[[TD2:.*]] = scf.for {{.*}} to {{.*}} step {{.*}} iter_args(%[[TC2:.*]] = %[[TC1]]) -> (tensor<128x128xf32>) {
// CHECK: %[[sTA:.*]] = tensor.extract_slice %[[TA]][{{.*}}] : tensor<128x128xf32> to tensor<?x4xf32>
// CHECK: %[[sTB:.*]] = tensor.extract_slice %[[TB]][{{.*}}] : tensor<128x128xf32> to tensor<4x?xf32>
// CHECK: %[[sTC:.*]] = tensor.extract_slice %[[TC2]][{{.*}}] : tensor<128x128xf32> to tensor<?x?xf32>
// CHECK: %[[sTD:.*]] = linalg.matmul ins(%[[sTA]], %[[sTB]] : tensor<?x4xf32>, tensor<4x?xf32>)
// CHECK-SAME: outs(%[[sTC]] : tensor<?x?xf32>) -> tensor<?x?xf32>
// CHECK: %[[TD:.*]] = tensor.insert_slice %[[sTD]] into %[[TC2]][{{.*}}] : tensor<?x?xf32> into tensor<128x128xf32>
// CHECK: scf.yield %[[TD]] : tensor<128x128xf32>
// CHECK: scf.yield %[[TD2]] : tensor<128x128xf32>
// CHECK: scf.yield %[[TD1]] : tensor<128x128xf32>
%sz = func.call @get_dynamic_tile_size() : () -> index
%0 = linalg.matmul ins(%arg0, %arg1: tensor<128x128xf32>, tensor<128x128xf32>)
outs(%arg2: tensor<128x128xf32>)
-> tensor<128x128xf32>
// CHECK: return %[[TD0]] : tensor<128x128xf32>
return %0 : tensor<128x128xf32>
}

View File

@ -3,7 +3,7 @@
transform.sequence {
^bb1(%arg0: !pdl.operation):
// CHECK %{{.*}}, %{{.*}}:2 = transform.structured.tile
%0, %1:2 = transform.structured.tile %arg0 { sizes = [2, 0, 3] }
%0, %1:2 = transform.structured.tile %arg0 [2, 0, 3]
}
//===----------------------------------------------------------------------===//

View File

@ -77,7 +77,7 @@ transform.with_pdl_patterns {
transform.sequence %arg0 {
^bb1(%arg1: !pdl.operation):
%0 = pdl_match @pdl_target_attrA in %arg1
transform.structured.tile %0 {sizes = [4, 4, 4]}
transform.structured.tile %0 [4, 4, 4]
%1 = pdl_match @pdl_target_attrC in %arg1
%2 = transform.get_closest_isolated_parent %1
transform.structured.vectorize %2

View File

@ -105,9 +105,8 @@ def testTileCompact():
transform.YieldOp()
# CHECK-LABEL: TEST: testTileCompact
# CHECK: transform.sequence
# CHECK: %{{.+}}, %{{.+}}:2 = transform.structured.tile
# CHECK-DAG: interchange = [0, 1]
# CHECK-DAG: sizes = [4, 8]
# CHECK: %{{.+}}, %{{.+}}:2 = transform.structured.tile %{{.*}}[4, 8]
# CHECK: interchange = [0, 1]
@run
@ -122,9 +121,8 @@ def testTileAttributes():
transform.YieldOp()
# CHECK-LABEL: TEST: testTileAttributes
# CHECK: transform.sequence
# CHECK: structured.tile
# CHECK-DAG: interchange = [0, 1]
# CHECK-DAG: sizes = [4, 8]
# CHECK: %{{.+}}, %{{.+}}:2 = transform.structured.tile %{{.*}}[4, 8]
# CHECK: interchange = [0, 1]
@run
@ -136,9 +134,24 @@ def testTileZero():
transform.YieldOp()
# CHECK-LABEL: TEST: testTileZero
# CHECK: transform.sequence
# CHECK: %{{.+}}, %{{.+}}:2 = transform.structured.tile
# CHECK-DAG: interchange = [0, 1, 2, 3]
# CHECK-DAG: sizes = [4, 0, 2, 0]
# CHECK: %{{.+}}, %{{.+}}:2 = transform.structured.tile %{{.*}}[4, 0, 2, 0]
# CHECK: interchange = [0, 1, 2, 3]
@run
def testTileDynamic():
with_pdl = transform.WithPDLPatternsOp()
with InsertionPoint(with_pdl.body):
sequence = transform.SequenceOp(with_pdl.bodyTarget)
with InsertionPoint(sequence.body):
m1 = transform.PDLMatchOp(sequence.bodyTarget, "first")
m2 = transform.PDLMatchOp(sequence.bodyTarget, "second")
structured.TileOp(sequence.bodyTarget, sizes=[m1, 3, m2, 0])
transform.YieldOp()
# CHECK-LABEL: TEST: testTileDynamic
# CHECK: %[[FIRST:.+]] = pdl_match
# CHECK: %[[SECOND:.+]] = pdl_match
# CHECK: %{{.+}}, %{{.+}}:3 = transform.structured.tile %{{.*}}[%[[FIRST]], 3, %[[SECOND]], 0]
@run

View File

@ -7461,6 +7461,7 @@ cc_library(
],
includes = ["include"],
deps = [
":ArithmeticDialect",
":IR",
":LinalgDialect",
":LinalgTransformOpsIncGen",