diff --git a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h index d00183a1e16a1..9e854ad7fffdc 100644 --- a/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h +++ b/mlir/include/mlir/Dialect/Linalg/Transforms/Transforms.h @@ -524,7 +524,34 @@ struct ControlDropUnitDims { RankReductionStrategy rankReductionStrategy = RankReductionStrategy::ReassociativeReshape; + /// Struct to describe how to transform an operand after dropping unit extend + /// dimensions. The \c indexMap field contains the updated affine map that + /// relates the new (reduced) iteration space to the operand's dimensions. The + /// \c targetShape field specifies the new shape of the operand after + /// collapsing unit-extent dimensions, and the \c reassociation field provides + /// the grouping of dimensions needed for reshape operations when using the + /// reassociative reshape strategy. + struct UnitExtentReplacementInfo { + AffineMap indexMap; + SmallVector reassociation; + SmallVector targetShape; + }; + + using DimensionMapping = llvm::SmallDenseMap; + + /// Instances of this type are used to control which dimensions of an operand + /// are considered for dropping unit extent dimensions. The parameter to the + /// function is the operation itself, the expected return is a list of + /// dimensions to consider for dropping unit extent dimensions. If the + /// operation should not be have any dimensions dropped, implementations + /// should return an empty list. using ControlFnTy = std::function(Operation *)>; + + /// Function to control which dimensions, if any, are to be considered for + /// dropping unit extent dimensions. The default behavior is to consider all + /// dimensions of a \c linalg.generic or \c tensor.pad operation for dropping. + /// Users of the \ref dropUnitDims interface can override the default behavior + /// by setting this member to their own implementation. ControlFnTy controlFn = [](Operation *op) { if (auto genericOp = dyn_cast_or_null(op)) { return llvm::to_vector(llvm::seq(0, genericOp.getNumLoops())); @@ -535,6 +562,133 @@ struct ControlDropUnitDims { } return SmallVector{}; }; + + /// Instances of this type are used to control how the different operands of + /// an operation are treated while dropping unit extent dimensions. The + /// function receives the operation and operand currently being processed, in + /// addition to the control struct and MLIR context. It also receives a + /// mapping of old dimensions to new dimensions resulting from dropping unit + /// extent dimensions on the operation and and a list of \c AffineExpr with + /// the updated dimensions or 0 for dimensions that were dropped. + /// The function returns a struct that describes how to transform the operand + /// after dropping unit dimensions. + using ComputeOperandShapeAndMapFnTy = std::function)>; + + /// Function to control how an operand should be transformed after dropping + /// unit extend dimensions from the owning operation. The default behavior is + /// to drop unit extent dimensions from the shape and update the affine map + /// accordingly for either (a) \c memref with identity layout or (b) \c tensor + /// without encoding. Operands with other types retain their shape and affine + /// map, with 0 for the dimensions dropped from the operation. + /// Users of the \ref dropUnitDims interface can override the default behavior + /// by setting this member to their own implementation. + ComputeOperandShapeAndMapFnTy computeOperandShapeAndMapFn = + [](const ControlDropUnitDims &control, MLIRContext *context, + IndexingMapOpInterface op, OpOperand *opOperand, + DimensionMapping &oldDimsToNewDimsMap, + ArrayRef dimReplacements) -> UnitExtentReplacementInfo { + // Only memref with identity layout and tensor without an encoding are + // considered for collapsing them, i.e., drop unit extent dimensions from + // their shape and updating the affine map accordingly. + auto hasCollapsibleType = [](OpOperand &operand) { + Type operandType = operand.get().getType(); + if (auto memrefOperandType = dyn_cast_or_null(operandType)) { + return memrefOperandType.getLayout().isIdentity(); + } + if (auto tensorOperandType = dyn_cast(operandType)) { + return tensorOperandType.getEncoding() == nullptr; + } + return false; + }; + // For types that are considered collapsible, update the shape and affine + // map. + if (hasCollapsibleType(*opOperand)) { + return control.dropUnitExtentFromOperandMetadata( + context, op, opOperand, oldDimsToNewDimsMap, dimReplacements); + } + // For other types, keep their existing shape and update the affine map with + // 0-entries for all dimensions that were dropped from the owning operation + // of this operand. + auto indexingMap = op.getMatchingIndexingMap(opOperand); + SmallVector shape = op.getStaticOperandShape(opOperand); + AffineMap newIndexingMap = indexingMap.replaceDimsAndSymbols( + dimReplacements, ArrayRef{}, oldDimsToNewDimsMap.size(), 0); + UnitExtentReplacementInfo info; + info.indexMap = newIndexingMap; + info.targetShape = llvm::to_vector(shape); + return info; + }; + + /// Instances of this type are used to control how operand values are + /// collapsed after dropping unit extent dimensions. Next to the control + /// struct, rewriter and location, the function receives the operand value to + /// collapse, the new target shape and how old dimensions should be grouped. + /// The function needs to insert the necessary operations to collapse the + /// operand to the target shape and returns the new operand value. + using CollapseValueFnTy = std::function, ArrayRef)>; + + /// Function to control how operands are collapsed into their new target shape + /// after dropping unit extent dimensions. The default behavior \see + /// ControlDropUnitDims::collapseValue. + /// Users of the \ref dropUnitDims interface can override the default behavior + /// by setting this member to their own implementation. + CollapseValueFnTy collapseValueFn = + [](const ControlDropUnitDims &control, RewriterBase &rewriter, + Location loc, Value operand, ArrayRef targetShape, + ArrayRef reassociation) -> Value { + return control.collapseValue(rewriter, loc, operand, targetShape, + reassociation); + }; + + /// Instances of this type are used to control how result values are expanded + /// into their original shape after dropping unit extent dimensions. Next to + /// the control construct, rewriter and location, the function recieves the + /// result value, the original value to replace and and information on how the + /// new dimensions were grouped. + /// The function needs to insert the necessary operations to expand the + /// result to the original shape and returns the new result value. + using ExpandValueFnTy = + std::function)>; + + /// Function to control how results are expanded into their original shape + /// after dropping unit extent dimensions. The default behavior \see + /// ControlDropUnitDims::expandValue. + /// Users of the \ref dropUnitDims interface can override the default behavior + /// by setting this member to their own implementation. + ExpandValueFnTy expandValueFn = + [](const ControlDropUnitDims &control, RewriterBase &rewriter, + Location loc, Value result, Value origDest, + ArrayRef reassociation) -> Value { + return control.expandValue(rewriter, loc, result, origDest, reassociation); + }; + + /// Compute the modified metadata for an operands of operation + /// whose unit dims are being dropped. Return the new indexing map + /// to use, the shape of the operand in the replacement op + /// and the `reassocation` to use to go from original operand shape + /// to modified operand shape. + UnitExtentReplacementInfo + dropUnitExtentFromOperandMetadata(MLIRContext *, IndexingMapOpInterface, + OpOperand *, DimensionMapping &, + ArrayRef) const; + + /// Collapse the given `value` so that the type matches the type of + /// `origOutput`. The `reassociation` is used when `rankReductionStrategy` is + /// set to `RankReductionStrategy::ReassociativeReshape`. + Value collapseValue(RewriterBase &, Location, Value, ArrayRef, + ArrayRef) const; + + /// Expand the given `value` so that the type matches the type of `origDest`. + /// The `reassociation` is used when `rankReductionStrategy` is set to + /// `RankReductionStrategy::ReassociativeReshape`. + Value expandValue(RewriterBase &rewriter, Location loc, Value result, + Value origDest, + ArrayRef reassociation) const; }; struct DropUnitDimsResult { diff --git a/mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp b/mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp index 9e6c1e6036cba..f3bfdc255a5ce 100644 --- a/mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp +++ b/mlir/lib/Dialect/Linalg/Transforms/DropUnitDims.cpp @@ -244,13 +244,9 @@ replaceUnitDimIndexOps(GenericOp genericOp, } } -/// Expand the given `value` so that the type matches the type of `origDest`. -/// The `reassociation` is used when `rankReductionStrategy` is set to -/// `RankReductionStrategy::ReassociativeReshape`. -static Value -expandValue(RewriterBase &rewriter, Location loc, Value result, Value origDest, - ArrayRef reassociation, - ControlDropUnitDims::RankReductionStrategy rankReductionStrategy) { +Value ControlDropUnitDims::expandValue( + RewriterBase &rewriter, Location loc, Value result, Value origDest, + ArrayRef reassociation) const { // There are no results for memref outputs. auto origResultType = cast(origDest.getType()); if (rankReductionStrategy == @@ -272,13 +268,10 @@ expandValue(RewriterBase &rewriter, Location loc, Value result, Value origDest, .getResult(); } -/// Collapse the given `value` so that the type matches the type of -/// `origOutput`. The `reassociation` is used when `rankReductionStrategy` is -/// set to `RankReductionStrategy::ReassociativeReshape`. -static Value collapseValue( +Value ControlDropUnitDims::collapseValue( RewriterBase &rewriter, Location loc, Value operand, - ArrayRef targetShape, ArrayRef reassociation, - ControlDropUnitDims::RankReductionStrategy rankReductionStrategy) { + ArrayRef targetShape, + ArrayRef reassociation) const { if (auto memrefType = dyn_cast(operand.getType())) { if (rankReductionStrategy == ControlDropUnitDims::RankReductionStrategy::ExtractInsertSlice) { @@ -321,20 +314,11 @@ static Value collapseValue( llvm_unreachable("unsupported operand type"); } -/// Compute the modified metadata for an operands of operation -/// whose unit dims are being dropped. Return the new indexing map -/// to use, the shape of the operand in the replacement op -/// and the `reassocation` to use to go from original operand shape -/// to modified operand shape. -struct UnitExtentReplacementInfo { - AffineMap indexMap; - SmallVector reassociation; - SmallVector targetShape; -}; -static UnitExtentReplacementInfo dropUnitExtentFromOperandMetadata( +ControlDropUnitDims::UnitExtentReplacementInfo +ControlDropUnitDims::dropUnitExtentFromOperandMetadata( MLIRContext *context, IndexingMapOpInterface op, OpOperand *opOperand, llvm::SmallDenseMap &oldDimsToNewDimsMap, - ArrayRef dimReplacements) { + ArrayRef dimReplacements) const { UnitExtentReplacementInfo info; ReassociationIndices reassociationGroup; SmallVector newIndexExprs; @@ -457,31 +441,11 @@ linalg::dropUnitDims(RewriterBase &rewriter, IndexingMapOpInterface op, SmallVector> reassociations; SmallVector> targetShapes; SmallVector collapsed; - auto hasCollapsibleType = [](OpOperand &operand) { - Type operandType = operand.get().getType(); - if (auto memrefOperandType = dyn_cast_or_null(operandType)) { - return memrefOperandType.getLayout().isIdentity(); - } - if (auto tensorOperandType = dyn_cast(operandType)) { - return tensorOperandType.getEncoding() == nullptr; - } - return false; - }; for (OpOperand &opOperand : op->getOpOperands()) { auto indexingMap = op.getMatchingIndexingMap(&opOperand); - SmallVector shape = op.getStaticOperandShape(&opOperand); - if (!hasCollapsibleType(opOperand)) { - AffineMap newIndexingMap = indexingMap.replaceDimsAndSymbols( - dimReplacements, ArrayRef{}, oldDimToNewDimMap.size(), 0); - newIndexingMaps.push_back(newIndexingMap); - targetShapes.push_back(llvm::to_vector(shape)); - collapsed.push_back(false); - reassociations.push_back({}); - continue; - } - auto replacementInfo = - dropUnitExtentFromOperandMetadata(rewriter.getContext(), op, &opOperand, - oldDimToNewDimMap, dimReplacements); + auto replacementInfo = options.computeOperandShapeAndMapFn( + options, rewriter.getContext(), op, &opOperand, oldDimToNewDimMap, + dimReplacements); reassociations.push_back(replacementInfo.reassociation); newIndexingMaps.push_back(replacementInfo.indexMap); targetShapes.push_back(replacementInfo.targetShape); @@ -508,9 +472,9 @@ linalg::dropUnitDims(RewriterBase &rewriter, IndexingMapOpInterface op, newOperands.push_back(opOperand.get()); continue; } - newOperands.push_back(collapseValue(rewriter, loc, opOperand.get(), - targetShapes[idx], reassociations[idx], - options.rankReductionStrategy)); + newOperands.push_back( + options.collapseValueFn(options, rewriter, loc, opOperand.get(), + targetShapes[idx], reassociations[idx])); } IndexingMapOpInterface replacementOp = droppedUnitDimsBuilder( @@ -526,9 +490,9 @@ linalg::dropUnitDims(RewriterBase &rewriter, IndexingMapOpInterface op, resultReplacements.push_back(result); continue; } - Value expandedValue = expandValue(rewriter, loc, result, origDest, - reassociations[opOperandIndex], - options.rankReductionStrategy); + Value expandedValue = + options.expandValueFn(options, rewriter, loc, result, origDest, + reassociations[opOperandIndex]); resultReplacements.push_back(expandedValue); } @@ -686,8 +650,8 @@ struct DropPadUnitDims : public OpRewritePattern { } Value collapsedSource = - collapseValue(rewriter, padOp.getLoc(), padOp.getSource(), newShape, - reassociationMap, options.rankReductionStrategy); + options.collapseValueFn(options, rewriter, padOp.getLoc(), + padOp.getSource(), newShape, reassociationMap); auto newResultType = RankedTensorType::get( newResultShape, padOp.getResultType().getElementType()); @@ -714,8 +678,8 @@ struct DropPadUnitDims : public OpRewritePattern { } Value expandedValue = - expandValue(rewriter, padOp.getLoc(), newPadOp.getResult(), dest, - reassociationMap, options.rankReductionStrategy); + options.expandValueFn(options, rewriter, padOp.getLoc(), + newPadOp.getResult(), dest, reassociationMap); rewriter.replaceOp(padOp, expandedValue); return success(); } @@ -904,10 +868,10 @@ static Value collapseSingletonDimAt(PatternRewriter &rewriter, Value val, auto valType = cast(val.getType()); SmallVector collapsedShape(valType.getShape()); collapsedShape.erase(collapsedShape.begin() + pos); - return collapseValue( + ControlDropUnitDims options; + return options.collapseValue( rewriter, val.getLoc(), val, collapsedShape, - getReassociationForReshapeAtDim(valType.getRank(), pos), - ControlDropUnitDims::RankReductionStrategy::ReassociativeReshape); + getReassociationForReshapeAtDim(valType.getRank(), pos)); } /// Base class for all rank reduction patterns for contraction ops diff --git a/mlir/test/Dialect/Linalg/test-drop-unit-dims.mlir b/mlir/test/Dialect/Linalg/test-drop-unit-dims.mlir index 35eeffc1f9953..6b2a19fd324c6 100644 --- a/mlir/test/Dialect/Linalg/test-drop-unit-dims.mlir +++ b/mlir/test/Dialect/Linalg/test-drop-unit-dims.mlir @@ -1,26 +1,55 @@ // RUN: mlir-opt -test-linalg-drop-unit-dims --split-input-file %s | FileCheck %s +// RUN: mlir-opt -test-linalg-drop-unit-dims="collapse-encoded" --split-input-file %s | FileCheck %s --check-prefix=ENCODED + +#encoding = #test.tensor_encoding<"encoding"> // Drop only the outermost unit dimension (controlled using a control function) -func.func @drop_outermost_unit_dims(%arg0: tensor<1x1x42xf32>) -> tensor<1x1x42xf32> { +// In default mode, only the input with no encoding is collapsed. +// With the `collape-encoded` flag, the encoded input is also collapsed. +func.func @drop_outermost_unit_dims(%arg0: tensor<1x1x42xf32>, %arg1: tensor<1x1x42xf32, #encoding>) -> tensor<1x1x42xf32> { %0 = tensor.empty() : tensor<1x1x42xf32> %1 = linalg.generic { indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d1, d2)>, + affine_map<(d0, d1, d2) -> (d0, d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1, d2)>], iterator_types = ["parallel", "parallel", "parallel"]} - ins(%arg0 : tensor<1x1x42xf32>) outs(%0 : tensor<1x1x42xf32>) { - ^bb0(%b0: f32, %b1 : f32): + ins(%arg0, %arg1 : tensor<1x1x42xf32>, tensor<1x1x42xf32, #encoding>) + outs(%0 : tensor<1x1x42xf32>) { + ^bb0(%b0: f32, %b1: f32, %b2: f32): %2 = arith.addf %b0, %b1 : f32 linalg.yield %2 : f32 } -> tensor<1x1x42xf32> return %1 : tensor<1x1x42xf32> } + +// Without the collapse-encoded flag, only the non-encoded tensor is collapsed // CHECK-LABEL: func @drop_outermost_unit_dims // CHECK-SAME: %[[ARG0:.+]]: tensor<1x1x42xf32> +// CHECK-SAME: %[[ARG1:.+]]: tensor<1x1x42xf32, #test.tensor_encoding<"encoding">> // CHECK: %[[OUTS:.+]] = tensor.empty() // CHECK: %[[ARG0_RESHAPE:.+]] = tensor.collapse_shape %[[ARG0]] {{\[}}[0, 1], [2]{{\]}} // CHECK: %[[OUTS_RESHAPE:.+]] = tensor.collapse_shape %[[OUTS]] {{\[}}[0, 1], [2]{{\]}} // CHECK: %[[GENERIC:.+]] = linalg.generic -// CHECK-SAME: ins(%[[ARG0_RESHAPE]] : +// CHECK-SAME: ins(%[[ARG0_RESHAPE]], %[[ARG1]] : // CHECK-SAME: outs(%[[OUTS_RESHAPE]] : // CHECK: %[[EXPAND_SHAPE:.+]] = tensor.expand_shape %[[GENERIC]] {{\[}}[0, 1], [2]{{\]}} // CHECK: return %[[EXPAND_SHAPE]] + +// With the collapse-encoded flag, both tensors are collapsed and encodings are preserved +// ENCODED: affine_map<(d0, d1) -> (d0, d1)> +// ENCODED-LABEL: func @drop_outermost_unit_dims +// ENCODED-SAME: %[[ARG0:.+]]: tensor<1x1x42xf32> +// ENCODED-SAME: %[[ARG1:.+]]: tensor<1x1x42xf32, #test.tensor_encoding<"encoding">> +// ENCODED: %[[OUTS:.+]] = tensor.empty() : tensor<1x1x42xf32> +// ENCODED: %[[ARG0_RESHAPE:.+]] = tensor.collapse_shape %[[ARG0]] {{\[}}[0, 1], [2]{{\]}} +// ENCODED-SAME: : tensor<1x1x42xf32> into tensor<1x42xf32> +// ENCODED: %[[ARG1_RESHAPE:.+]] = tensor.collapse_shape %[[ARG1]] {{\[}}[0, 1], [2]{{\]}} +// ENCODED-SAME: : tensor<1x1x42xf32, #test.tensor_encoding<"encoding">> into tensor<1x42xf32, #test.tensor_encoding<"encoding">> +// ENCODED: %[[OUTS_RESHAPE:.+]] = tensor.collapse_shape %[[OUTS]] {{\[}}[0, 1], [2]{{\]}} +// ENCODED-SAME: : tensor<1x1x42xf32> into tensor<1x42xf32> +// ENCODED: %[[GENERIC:.+]] = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = ["parallel", "parallel"]} +// ENCODED-SAME: ins(%[[ARG0_RESHAPE]], %[[ARG1_RESHAPE]] : tensor<1x42xf32>, tensor<1x42xf32, #test.tensor_encoding<"encoding">>) +// ENCODED-SAME: outs(%[[OUTS_RESHAPE]] : tensor<1x42xf32>) +// ENCODED: %[[EXPAND_SHAPE:.+]] = tensor.expand_shape %[[GENERIC]] {{\[}}[0, 1], [2]{{\]}} +// ENCODED-SAME: output_shape [1, 1, 42] {test.unit_dims_expanded} : tensor<1x42xf32> into tensor<1x1x42xf32> +// ENCODED: return %[[EXPAND_SHAPE]] diff --git a/mlir/test/lib/Dialect/Linalg/TestLinalgDropUnitDims.cpp b/mlir/test/lib/Dialect/Linalg/TestLinalgDropUnitDims.cpp index 402ce154c0848..ee48b4697dcc1 100644 --- a/mlir/test/lib/Dialect/Linalg/TestLinalgDropUnitDims.cpp +++ b/mlir/test/lib/Dialect/Linalg/TestLinalgDropUnitDims.cpp @@ -34,13 +34,85 @@ LogicalResult dropOutermostUnitDims(RewriterBase &rewriter, return success(); } +LogicalResult dropOutermostUnitDimsWithEncoding(RewriterBase &rewriter, + linalg::GenericOp genericOp) { + linalg::ControlDropUnitDims options; + + options.controlFn = [](Operation *op) { return SmallVector{0}; }; + options.computeOperandShapeAndMapFn = + [](const linalg::ControlDropUnitDims &control, MLIRContext *context, + IndexingMapOpInterface op, OpOperand *opOperand, + linalg::ControlDropUnitDims::DimensionMapping &oldDimsToNewDimsMap, + ArrayRef dimReplacements) + -> linalg::ControlDropUnitDims::UnitExtentReplacementInfo { + auto isCollapsible = [](Type ty) { return isa(ty); }; + auto indexingMap = op.getMatchingIndexingMap(opOperand); + SmallVector shape = op.getStaticOperandShape(opOperand); + if (!isCollapsible(opOperand->get().getType())) { + AffineMap newIndexingMap = indexingMap.replaceDimsAndSymbols( + dimReplacements, ArrayRef{}, oldDimsToNewDimsMap.size(), + 0); + linalg::ControlDropUnitDims::UnitExtentReplacementInfo info; + info.indexMap = newIndexingMap; + info.targetShape = llvm::to_vector(shape); + return info; + } + return control.dropUnitExtentFromOperandMetadata( + context, op, opOperand, oldDimsToNewDimsMap, dimReplacements); + }; + + // Preserve encoding when collapsing + options.collapseValueFn = + [](const linalg::ControlDropUnitDims &control, RewriterBase &rewriter, + Location loc, Value operand, ArrayRef targetShape, + ArrayRef reassociation) -> Value { + auto tensorType = cast(operand.getType()); + assert(control.rankReductionStrategy == + linalg::ControlDropUnitDims::RankReductionStrategy:: + ReassociativeReshape && + "unexpected rank reduction strategy"); + auto targetType = RankedTensorType::get( + targetShape, tensorType.getElementType(), tensorType.getEncoding()); + return tensor::CollapseShapeOp::create(rewriter, loc, targetType, operand, + reassociation); + }; + + // Attach test attribute to expand operations + options.expandValueFn = + [](const linalg::ControlDropUnitDims &control, RewriterBase &rewriter, + Location loc, Value result, Value origDest, + ArrayRef reassociation) -> Value { + auto origResultType = cast(origDest.getType()); + auto expandOp = tensor::ExpandShapeOp::create(rewriter, loc, origResultType, + result, reassociation); + expandOp->setDiscardableAttr("test.unit_dims_expanded", + rewriter.getUnitAttr()); + return expandOp.getResult(); + }; + + FailureOr result = + linalg::dropUnitDims(rewriter, genericOp, options); + if (failed(result)) { + return failure(); + } + rewriter.replaceOp(genericOp, result->replacements); + return success(); +} + struct TestLinalgDropUnitDims : public PassWrapper> { MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestLinalgDropUnitDims) TestLinalgDropUnitDims() = default; - TestLinalgDropUnitDims(const TestLinalgDropUnitDims &pass) = default; + TestLinalgDropUnitDims(const TestLinalgDropUnitDims &pass) + : PassWrapper(pass) {} + + Option preserveEncoding{ + *this, "collapse-encoded", + llvm::cl::desc( + "Collapse tensors with encodings and unit extend dimensions"), + llvm::cl::init(false)}; void getDependentDialects(DialectRegistry ®istry) const override { registry.insert(); @@ -63,7 +135,11 @@ struct TestLinalgDropUnitDims for (auto genericOp : genericOps) { rewriter.setInsertionPoint(genericOp); - (void)dropOutermostUnitDims(rewriter, genericOp); + if (preserveEncoding) { + (void)dropOutermostUnitDimsWithEncoding(rewriter, genericOp); + } else { + (void)dropOutermostUnitDims(rewriter, genericOp); + } } } };