[Mlir-commits] [mlir] 0d37546 - [mlir][linalg] Remove abandoned `Detensorize` pass (#177579)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Feb 10 04:29:24 PST 2026
Author: Matthias Springer
Date: 2026-02-10T13:29:19+01:00
New Revision: 0d375463ebdc9cc72e186f2366983c8053debb27
URL: https://github.com/llvm/llvm-project/commit/0d375463ebdc9cc72e186f2366983c8053debb27
DIFF: https://github.com/llvm/llvm-project/commit/0d375463ebdc9cc72e186f2366983c8053debb27.diff
LOG: [mlir][linalg] Remove abandoned `Detensorize` pass (#177579)
RFC:
https://discourse.llvm.org/t/how-to-deal-with-abandoned-unmaintained-code/89560
Added:
Modified:
mlir/include/mlir/Dialect/Linalg/Passes.td
mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
Removed:
mlir/lib/Dialect/Linalg/Transforms/Detensorize.cpp
mlir/test/Dialect/Linalg/detensorize_0d.mlir
mlir/test/Dialect/Linalg/detensorize_br_operands.mlir
mlir/test/Dialect/Linalg/detensorize_entry_block.mlir
mlir/test/Dialect/Linalg/detensorize_if.mlir
mlir/test/Dialect/Linalg/detensorize_trivial.mlir
mlir/test/Dialect/Linalg/detensorize_while.mlir
mlir/test/Dialect/Linalg/detensorize_while_impure_cf.mlir
mlir/test/Dialect/Linalg/detensorize_while_pure_cf.mlir
################################################################################
diff --git a/mlir/include/mlir/Dialect/Linalg/Passes.td b/mlir/include/mlir/Dialect/Linalg/Passes.td
index 42d4d2083fc1c..f48ea9849e237 100644
--- a/mlir/include/mlir/Dialect/Linalg/Passes.td
+++ b/mlir/include/mlir/Dialect/Linalg/Passes.td
@@ -178,43 +178,6 @@ def LinalgFoldIntoElementwisePass : Pass<"linalg-fold-into-elementwise"> {
}];
}
-def LinalgDetensorizePass : InterfacePass<"linalg-detensorize", "FunctionOpInterface"> {
- let summary = "Detensorize linalg ops";
- let dependentDialects = [];
-
- let description = [{
- Detensoring is the process through which a tensor value is converted to one
- or potentially more primitive value(s). During this process, operations with
- such detensored operands are also converted to an equivalent form that works
- on primitives.
-
- The detensoring process is driven by linalg-on-tensor ops. In particular, a
- linalg-on-tensor op is checked to see whether *all* its operands can be
- detensored. If so, those operands are converted to their primitive
- counterparts and the linalg op is replaced by an equivalent op that takes
- those new primitive values as operands. Therefore, detensoring an op can be
- divided into 2 main logical phases:
-
- 1. Detect/match an op that can be detensored.
- 2. Detensor the operands of the op and replace it with a primitive
- equivalent.
-
- In addition to detensoring individual ops, this pass detensors internal
- control flow inside a function. All blocks except for the entry block are
- detensored by converting their arguments whenever possible.
-
- This can be run on any FunctionOpInterface op and must not be
- run on others. This is because it performs specific legalization of the
- blocks that make up the body, which it assumes has is a FunctionOpInterface.
- }];
- let options = [
- Option<"aggressiveMode", "aggressive-mode", "bool", /*default=*/"false",
- "Detensorize all ops that qualify for detensoring along with branch"
- " operands and basic-block arguments.">
-
- ];
-}
-
def LinalgBlockPackMatmul : Pass<"linalg-block-pack-matmul"> {
let summary = "Convert linalg matmul ops to block layout and back";
let description = [{
diff --git a/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt b/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
index fb39e18691e03..a2149478e4c2d 100644
--- a/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/Linalg/Transforms/CMakeLists.txt
@@ -7,7 +7,6 @@ add_mlir_dialect_library(MLIRLinalgTransforms
ConvertConv2DToImg2Col.cpp
DataLayoutPropagation.cpp
DecomposeLinalgOps.cpp
- Detensorize.cpp
DropUnitDims.cpp
ElementwiseOpFusion.cpp
ElementwiseToLinalg.cpp
diff --git a/mlir/lib/Dialect/Linalg/Transforms/Detensorize.cpp b/mlir/lib/Dialect/Linalg/Transforms/Detensorize.cpp
deleted file mode 100644
index 830905495e759..0000000000000
--- a/mlir/lib/Dialect/Linalg/Transforms/Detensorize.cpp
+++ /dev/null
@@ -1,569 +0,0 @@
-//===- Detensorize.cpp - Linalg transformations as patterns ----------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "mlir/Dialect/Linalg/Passes.h"
-
-#include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
-#include "mlir/Dialect/Func/Transforms/FuncConversions.h"
-#include "mlir/Dialect/Linalg/IR/Linalg.h"
-#include "mlir/Dialect/Tensor/IR/Tensor.h"
-#include "mlir/IR/OpDefinition.h"
-#include "mlir/Transforms/DialectConversion.h"
-#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
-#include <utility>
-
-namespace mlir {
-#define GEN_PASS_DEF_LINALGDETENSORIZEPASS
-#include "mlir/Dialect/Linalg/Passes.h.inc"
-} // namespace mlir
-
-using namespace mlir;
-using namespace mlir::linalg;
-
-static Value sourceMaterializationCallback(OpBuilder &builder, Type type,
- ValueRange inputs, Location loc) {
- assert(inputs.size() == 1);
- auto inputType = inputs[0].getType();
- if (isa<TensorType>(inputType))
- return nullptr;
-
- // A detensored value is converted back by creating a new tensor from its
- // element(s).
- return tensor::FromElementsOp::create(
- builder, loc, RankedTensorType::get({}, inputType), inputs[0]);
-}
-
-namespace {
-/// Defines the criteria a TensorType must follow in order to be considered
-/// "detensorable".
-///
-/// NOTE: For now, only 0-D tensors are supported.
-///
-/// Returns true if tensorType can be detensored.
-bool canBeDetensored(TensorType tensorType) {
- return tensorType.hasRank() && tensorType.getRank() == 0;
-}
-
-bool shouldBeDetensored(Operation *op, TypeConverter typeConverter) {
- GenericOp genericOp = dyn_cast_or_null<GenericOp>(op);
- return genericOp &&
- llvm::all_of(genericOp->getOpOperands(), [&](OpOperand &opOperand) {
- return !typeConverter.isLegal(opOperand.get().getType());
- });
-}
-
-/// A conversion pattern for detensoring `linalg.generic` ops.
-class DetensorizeGenericOp : public OpConversionPattern<GenericOp> {
-public:
- using OpConversionPattern::OpConversionPattern;
- LogicalResult
- matchAndRewrite(GenericOp op, OpAdaptor adaptor,
- ConversionPatternRewriter &rewriter) const override {
- Block *originalBlock = op->getBlock();
-
- // Gather some information about the op before inlining its region.
- Block *opEntryBlock = &*op.getRegion().begin();
- YieldOp yieldOp = dyn_cast<YieldOp>(op.getRegion().back().getTerminator());
-
- // Split the op's region before the op. This way, we have a clear insertion
- // point in which the op can be inlined.
- Block *newBlock = rewriter.splitBlock(originalBlock, Block::iterator(op));
- rewriter.inlineRegionBefore(op.getRegion(), newBlock);
- // Now that op's region is inlined, the operands of its YieldOp are mapped
- // to the materialized target values. Therefore, we can replace the op's
- // uses with those of its YielOp's operands.
- rewriter.replaceOp(op, yieldOp->getOperands());
-
- // No need for these intermediate blocks, merge them into 1.
- rewriter.mergeBlocks(opEntryBlock, originalBlock, adaptor.getOperands());
- rewriter.mergeBlocks(newBlock, originalBlock, {});
-
- rewriter.eraseOp(&*Block::iterator(yieldOp));
-
- return success();
- }
-};
-
-/// A conversion pattern for detensoring internal (non-entry) blocks within a
-/// function.
-struct FunctionNonEntryBlockConversion
- : public OpInterfaceConversionPattern<FunctionOpInterface> {
- FunctionNonEntryBlockConversion(MLIRContext *ctx, TypeConverter &converter,
- DenseSet<BlockArgument> blockArgsToDetensor)
- : OpInterfaceConversionPattern(converter, ctx),
- blockArgsToDetensor(std::move(blockArgsToDetensor)) {}
-
- LogicalResult
- matchAndRewrite(FunctionOpInterface op, ArrayRef<Value> operands,
- ConversionPatternRewriter &rewriter) const override {
- rewriter.startOpModification(op);
- Region ®ion = op.getFunctionBody();
-
- for (Block &block :
- llvm::make_early_inc_range(llvm::drop_begin(region, 1))) {
- TypeConverter::SignatureConversion conversion(
- /*numOrigInputs=*/block.getNumArguments());
-
- for (BlockArgument blockArgument : block.getArguments()) {
- int idx = blockArgument.getArgNumber();
-
- if (blockArgsToDetensor.count(blockArgument))
- conversion.addInputs(idx, {getTypeConverter()->convertType(
- block.getArgumentTypes()[idx])});
- else
- conversion.addInputs(idx, {block.getArgumentTypes()[idx]});
- }
-
- rewriter.applySignatureConversion(&block, conversion, getTypeConverter());
- }
-
- rewriter.finalizeOpModification(op);
- return success();
- }
-
-private:
- const DenseSet<BlockArgument> blockArgsToDetensor;
-};
-
-class DetensorizeTypeConverter : public TypeConverter {
-public:
- DetensorizeTypeConverter() {
- addConversion([](Type type) { return type; });
-
- // A TensorType that can be detensored, is converted to the underlying
- // element type.
- addConversion([](TensorType tensorType) -> Type {
- if (canBeDetensored(tensorType))
- return tensorType.getElementType();
-
- return tensorType;
- });
-
- // A tensor value is detensoried by extracting its element(s).
- addTargetMaterialization([](OpBuilder &builder, Type type,
- ValueRange inputs, Location loc) -> Value {
- return tensor::ExtractOp::create(builder, loc, inputs[0], ValueRange{});
- });
-
- addSourceMaterialization(sourceMaterializationCallback);
- }
-};
-
-/// @see LinalgDetensorize in Linalg/Passes.td for more details.
-struct LinalgDetensorize
- : public impl::LinalgDetensorizePassBase<LinalgDetensorize> {
- using impl::LinalgDetensorizePassBase<
- LinalgDetensorize>::LinalgDetensorizePassBase;
- LinalgDetensorize() = default;
-
- class CostModel {
- public:
- virtual ~CostModel() = default;
-
- /// A cost model algorithm computes the following outputs:
- ///
- /// - opsToDetensor: the list of linalg ops that should be
- /// detensored.
- ///
- /// - blockArgsToDetensor: since the operands and results of detensored
- /// linalg ops can cross the BB boundary (e.g. a linalg op's input can come
- /// from a BB argument and a linalg op's output can be passed to successor
- /// BBs), we need to maintain the sub-set of arguments that should be
- /// detensored (i.e. converted by typeConverter) for each affected BB.
- ///
- /// Example:
- ///
- /// For the following snippet:
- /// ...
- /// ^bb1(%6: tensor<i32>, %9: tensor<i32>):
- /// %7 = tensor.empty() : tensor<i32>
- /// %8 = linalg.generic #attrs
- /// ins(%6, %6 : tensor<i32>, tensor<i32>)
- /// outs(%7 : tensor<i32>) {
- /// ^bb0(%arg0: i32, %arg1: i32, %arg2: i32):
- /// %9 = arith.addi %arg0, %arg1 : i32
- /// linalg.yield %9 : i32
- /// } -> tensor<i32>
- /// %10 = "some.op"(%9)
- /// br ^bb2(%8 : tensor<i32>)
- /// ...
- ///
- /// if the cost model decides that the linalg.generic op should be
- /// detensored, then:
- /// - opsToDetensor should be = {linalg.generic{add}}.
- /// - blockArgsToDetensor should be = {bb1 -> {0}, bb2 -> {0}}.
- virtual void compute(FunctionOpInterface func,
- DetensorizeTypeConverter typeConverter,
- DenseSet<Operation *> &opsToDetensor,
- DenseSet<BlockArgument> &blockArgsToDetensor) = 0;
-
- /// From the blockArgsToDetensor set computed by a CostModel
- /// implementation, this method computes the corresponding branch op
- /// detensoring. The result is a map from a branch op to a subset of indices
- /// of its operands. The indices specify which of the branch op's operands
- /// should be detensored.
- ///
- /// For the previous example, this method would compute: {bb2 -> {0}}.
- static DenseMap<Operation *, DenseSet<int>> computeBranchOpDetensoring(
- const DenseSet<BlockArgument> &blockArgsToDetensor) {
- DenseMap<Operation *, DenseSet<int>> detensorableBranchOps;
-
- for (auto blockArgumentElem : blockArgsToDetensor) {
- Block *block = blockArgumentElem.getOwner();
-
- for (PredecessorIterator pred = block->pred_begin();
- pred != block->pred_end(); ++pred) {
- BranchOpInterface terminator =
- dyn_cast<BranchOpInterface>((*pred)->getTerminator());
- auto blockOperands =
- terminator.getSuccessorOperands(pred.getSuccessorIndex());
-
- if (blockOperands.empty() ||
- blockOperands.isOperandProduced(blockArgumentElem.getArgNumber()))
- continue;
-
- detensorableBranchOps[terminator].insert(
- blockOperands.getOperandIndex(blockArgumentElem.getArgNumber()));
- }
- }
-
- return detensorableBranchOps;
- }
- };
-
- /// Detensorize linalg ops involved in control-flow within a function.
- ///
- /// This model starts from BranchOps and CondBranchOps within a function. For
- /// each such branch, the model then walks the use-def chain for the branch's
- /// condition backwards in order to understand where the condition's value
- /// comes from. If the condition value is (indirectly) computed by a linalg op
- /// that can be detensored, the model then continues walking the use-def chain
- /// in order to understand where the linalg op's operands come from. This
- /// leads to discovering a "detensoring component". A detensoring component is
- /// the set of operations + block arguments that are involved in control-flow
- /// AND can be detensored.
- class ControlFlowDetectionModel : public CostModel {
- public:
- void compute(FunctionOpInterface func,
- DetensorizeTypeConverter typeConverter,
- DenseSet<Operation *> &opsToDetensor,
- DenseSet<BlockArgument> &blockArgsToDetensor) override {
- SmallVector<Value> workList;
-
- func->walk([&](cf::CondBranchOp condBr) {
- llvm::append_range(workList, condBr.getOperands());
- });
-
- func->walk([&](cf::BranchOp br) {
- llvm::append_range(workList, br.getOperands());
- });
-
- DenseSet<Value> visitedValues;
- DenseSet<Operation *> visitedOps;
-
- // For a (to-be-detesored) value, check if it "escapes" the block by being
- // passed to terminator. If it does, then workList is updated with the
- // corresponding argument to the successor block.
- auto updateWorkListWithSuccessorArguments =
- [&](Value value, BranchOpInterface terminator) {
- if (!terminator)
- return;
-
- for (auto operandIdx :
- llvm::seq<unsigned>(0, terminator->getOperands().size())) {
- Value operand = terminator->getOperand(operandIdx);
-
- if (operand == value) {
- auto succBlockArg =
- terminator.getSuccessorBlockArgument(operandIdx);
-
- if (succBlockArg && !blockArgsToDetensor.count(*succBlockArg))
- workList.push_back(*succBlockArg);
- }
- }
- };
-
- while (!workList.empty()) {
- Value currentItem = workList.pop_back_val();
-
- if (!visitedValues.insert(currentItem).second)
- continue;
-
- // 1 - Look forward:
- // 1.1 - If currentItem escapes to one or more successors, add
- // the corresponding successor arguments to workList.
- updateWorkListWithSuccessorArguments(
- currentItem, dyn_cast<BranchOpInterface>(
- currentItem.getParentBlock()->getTerminator()));
-
- // 1.2 - For each user of currentItem, add the defined values to
- // workList. This way, the user ops can be inspected later if they are
- // detensorable and if so, their operands will be added to workList to
- // potentially discover other parts of the detensorable component.
- for (auto *user : currentItem.getUsers())
- llvm::append_range(workList, user->getResults());
-
- // 2 - Look backward:
- // 2.1 - The current item is defined by a block argument. If the owner
- // block is a non-entry one, then:
- // * Add the argument to blockArgsToDetensor.
- // * Walk the use-def chain backwards to add each predecessor's
- // terminator-operands corresponding to currentItem to workList.
- if (auto currentItemBlockArgument =
- dyn_cast<BlockArgument>(currentItem)) {
- Block *ownerBlock = currentItemBlockArgument.getOwner();
-
- // Function arguments are not detensored/converted.
- if (&*ownerBlock->getParent()->begin() == ownerBlock)
- continue;
-
- // This inner-block argument is involved in control-flow, it should be
- // detensored.
- blockArgsToDetensor.insert(currentItemBlockArgument);
-
- for (PredecessorIterator pred = ownerBlock->pred_begin();
- pred != ownerBlock->pred_end(); ++pred) {
- BranchOpInterface predTerminator =
- dyn_cast<BranchOpInterface>((*pred)->getTerminator());
-
- // TODO: For now, we give up if any of the control-flow components
- // in a function is not detensorable. Fix that.
- if (!predTerminator) {
- opsToDetensor.clear();
- blockArgsToDetensor.clear();
- return;
- }
-
- auto ownerBlockOperands =
- predTerminator.getSuccessorOperands(pred.getSuccessorIndex());
-
- if (ownerBlockOperands.empty() ||
- ownerBlockOperands.isOperandProduced(
- currentItemBlockArgument.getArgNumber()))
- continue;
-
- // For each predecessor, add the value it passes to that argument to
- // workList to find out how it's computed.
- workList.push_back(
- ownerBlockOperands[currentItemBlockArgument.getArgNumber()]);
- }
-
- continue;
- }
-
- Operation *currentItemDefiningOp = currentItem.getDefiningOp();
-
- if (!visitedOps.insert(currentItemDefiningOp).second)
- continue;
-
- // 2.2 - The current item is computed by a GenericOp. If the op should
- // be detensored, then:
- // * Add it to opsToDetensor.
- // * Add its operands to workList to discover other parts of the
- // potentially detensorable component.
- if (auto genericOp = dyn_cast<GenericOp>(currentItemDefiningOp)) {
- // The op was encountered already, no need to inspect it again.
- if (opsToDetensor.count(genericOp))
- continue;
-
- // The op should not be detensored, give up on it but continue with
- // discovering the rest of the control-flow component.
- if (!shouldBeDetensored(genericOp, typeConverter)) {
- continue;
- }
-
- opsToDetensor.insert(genericOp);
- llvm::append_range(workList, genericOp.getInputs());
- continue;
- }
-
- // 2.3 - The current item is the result of a FromElementsOp, it will be
- // trivially detensored later as part of canonicalization patterns
- // applied at the end of detensoring.
- //
- // Note: No need to check whether the result type of this op is
- // detensorable since if it wasn't we wouldn't reach that point in the
- // work list.
- if (isa<tensor::FromElementsOp>(currentItemDefiningOp))
- continue;
-
- // 2.4 - The current item is the result of a scalar op, add all its
- // operands to the work list.
- if (llvm::all_of(
- currentItemDefiningOp->getResultTypes(),
- [&](Type resultType) { return resultType.isIntOrFloat(); }))
- llvm::append_range(workList, currentItemDefiningOp->getOperands());
- }
-
- // Since the cost model gives up on some ops (see the details of step 2.2
- // above), block arguments that correspond to the values produced by those
- // ops should not be detensored as well.
-
- DenseSet<BlockArgument> blockArgsToRemove;
-
- for (auto &blockArg : blockArgsToDetensor) {
- Block *block = blockArg.getParentBlock();
-
- // For the potentially detensorable block argument, find the
- // corresponding operands in predecessor blocks.
- for (PredecessorIterator pred = block->pred_begin();
- pred != block->pred_end(); ++pred) {
- BranchOpInterface terminator =
- dyn_cast<BranchOpInterface>((*pred)->getTerminator());
- auto blockOperands =
- terminator.getSuccessorOperands(pred.getSuccessorIndex());
-
- if (blockOperands.empty() ||
- blockOperands.isOperandProduced(blockArg.getArgNumber()))
- continue;
-
- Operation *definingOp =
- blockOperands[blockArg.getArgNumber()].getDefiningOp();
-
- // If the operand is defined by a GenericOp that will not be
- // detensored, then do not detensor the corresponding block argument.
- if (isa_and_nonnull<GenericOp>(definingOp) &&
- opsToDetensor.count(definingOp) == 0) {
- blockArgsToRemove.insert(blockArg);
- break;
- }
- }
- }
-
- for (auto &blockArg : blockArgsToRemove) {
- blockArgsToDetensor.erase(blockArg);
- }
- }
- };
-
- /// Detensorize everything that can detensored.
- class AggressiveDetensoringModel : public CostModel {
- public:
- void compute(FunctionOpInterface func,
- DetensorizeTypeConverter typeConverter,
- DenseSet<Operation *> &opsToDetensor,
- DenseSet<BlockArgument> &blockArgsToDetensor) override {
- func->walk([&](GenericOp genericOp) {
- if (shouldBeDetensored(genericOp, typeConverter))
- opsToDetensor.insert(genericOp);
- });
-
- for (Block &block : llvm::drop_begin(func.getFunctionBody(), 1))
- blockArgsToDetensor.insert_range(block.getArguments());
- }
- };
-
- void runOnOperation() override {
- MLIRContext *context = &getContext();
- DetensorizeTypeConverter typeConverter;
- RewritePatternSet patterns(context);
- ConversionTarget target(*context);
- DenseSet<Operation *> opsToDetensor;
- DenseMap<Operation *, DenseSet<int>> detensorableBranchOps;
- DenseSet<BlockArgument> blockArgsToDetensor;
- FunctionOpInterface funcOp = getOperation();
-
- if (funcOp.getFunctionBody().empty())
- return;
-
- // Make sure the entry block of the function doesn't contain any Linalg ops.
- // Otherwise, it may lead to the signature of the block being changed by the
- // dialect conversion below, which would make the function op invalid
- // because its type shouldn't change.
- IRRewriter rewriter(funcOp->getContext());
- Block *entryBlock = &funcOp.getFunctionBody().front();
- Block *postEntryBlock =
- rewriter.splitBlock(entryBlock, entryBlock->begin());
- rewriter.setInsertionPointToStart(entryBlock);
- auto branch = cf::BranchOp::create(rewriter, rewriter.getUnknownLoc(),
- postEntryBlock);
-
- if (aggressiveMode.getValue()) {
- AggressiveDetensoringModel costModel;
- costModel.compute(funcOp, typeConverter, opsToDetensor,
- blockArgsToDetensor);
- } else {
- ControlFlowDetectionModel costModel;
- costModel.compute(funcOp, typeConverter, opsToDetensor,
- blockArgsToDetensor);
- }
-
- detensorableBranchOps =
- CostModel::computeBranchOpDetensoring(blockArgsToDetensor);
-
- target.addDynamicallyLegalOp<GenericOp>(
- [&](GenericOp op) { return !opsToDetensor.count(op); });
-
- target.markUnknownOpDynamicallyLegal([&](Operation *op) {
- // A function is legal if all of its non-entry blocks are legal. We
- // don't legalize the entry block (i.e. the function's signature)
- // since detensoring can't happen along external calling convention
- // boundaries, which we conservatively approximate as all function
- // signatures.
- if (auto funcOp = dyn_cast<FunctionOpInterface>(op)) {
- Region &body = funcOp.getFunctionBody();
- return llvm::all_of(llvm::drop_begin(body, 1), [&](Block &block) {
- return !llvm::any_of(
- blockArgsToDetensor, [&](BlockArgument blockArgument) {
- return blockArgument.getOwner() == &block &&
- !typeConverter.isLegal(blockArgument.getType());
- });
- });
- }
-
- if (isNotBranchOpInterfaceOrReturnLikeOp(op) ||
- isLegalForReturnOpTypeConversionPattern(op, typeConverter,
- /*returnOpAlwaysLegal*/ true))
- return true;
-
- if (auto branchOp = dyn_cast<BranchOpInterface>(op)) {
- if (!detensorableBranchOps.count(branchOp))
- return true;
-
- for (auto operandIdx : detensorableBranchOps[branchOp])
- if (!typeConverter.isLegal(
- branchOp->getOperand(operandIdx).getType()))
- return false;
-
- return true;
- }
-
- return false;
- });
-
- patterns.add<DetensorizeGenericOp>(typeConverter, context);
- patterns.add<FunctionNonEntryBlockConversion>(context, typeConverter,
- blockArgsToDetensor);
- // Since non-entry block arguments get detensorized, we also need to
- // update the control flow inside the function to reflect the correct
- // types.
- auto shouldConvertBranchOperand = [&](BranchOpInterface branchOp,
- int operandIdx) -> bool {
- return detensorableBranchOps.count(branchOp) &&
- detensorableBranchOps[branchOp].count(operandIdx);
- };
-
- populateBranchOpInterfaceTypeConversionPattern(patterns, typeConverter,
- shouldConvertBranchOperand);
-
- if (failed(
- applyFullConversion(getOperation(), target, std::move(patterns))))
- signalPassFailure();
-
- RewritePatternSet canonPatterns(context);
- tensor::FromElementsOp::getCanonicalizationPatterns(canonPatterns, context);
- if (failed(applyPatternsGreedily(getOperation(), std::move(canonPatterns))))
- signalPassFailure();
-
- // Get rid of the dummy entry block we created in the beginning to work
- // around dialect conversion signature rewriting.
- rewriter.eraseOp(branch);
- rewriter.mergeBlocks(postEntryBlock, entryBlock);
- }
-};
-} // namespace
diff --git a/mlir/test/Dialect/Linalg/detensorize_0d.mlir b/mlir/test/Dialect/Linalg/detensorize_0d.mlir
deleted file mode 100644
index 74931cb0830bc..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_0d.mlir
+++ /dev/null
@@ -1,102 +0,0 @@
-// RUN: mlir-opt %s -allow-unregistered-dialect -pass-pipeline="builtin.module(func.func(linalg-detensorize{aggressive-mode}))" | FileCheck %s
-
-#map = affine_map<() -> ()>
-
-func.func @detensor_simple(%arg1: tensor<f32>, %arg2: tensor<f32>) -> tensor<f32> {
- %0 = tensor.empty() : tensor<f32>
- %1 = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = []}
- ins(%arg1, %arg2 : tensor<f32>, tensor<f32>)
- outs(%0 : tensor<f32>) {
- ^bb0(%arg3: f32, %arg4: f32, %arg5: f32):
- %2 = arith.addf %arg3, %arg4 : f32
- linalg.yield %2 : f32
- } -> tensor<f32>
- return %1: tensor<f32>
-}
-// CHECK-LABEL: func @detensor_simple
-// CHECK-SAME: (%[[arg1:.*]]: tensor<f32>, %[[arg2:.*]]: tensor<f32>)
-// CHECK-DAG: %[[arg1_val:.*]] = tensor.extract %[[arg1]]
-// CHECK-DAG: %[[arg2_val:.*]] = tensor.extract %[[arg2]]
-// CHECK: %[[detensored_res:.*]] = arith.addf %[[arg1_val]], %[[arg2_val]]
-// CHECK: %[[new_tensor_res:.*]] = tensor.from_elements %[[detensored_res]]
-// CHECK: return %[[new_tensor_res]]
-
-func.func @detensor_op_sequence(%arg1: tensor<f32>, %arg2: tensor<f32>) -> tensor<f32> {
- %0 = tensor.empty() : tensor<f32>
- %1 = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = []}
- ins(%arg1, %arg2 : tensor<f32>, tensor<f32>)
- outs(%0 : tensor<f32>) {
- ^bb0(%arg3: f32, %arg4: f32, %arg5: f32):
- %2 = arith.addf %arg3, %arg4 : f32
- linalg.yield %2 : f32
- } -> tensor<f32>
-
- %3 = tensor.empty() : tensor<f32>
- %4 = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = []}
- ins(%arg1, %1 : tensor<f32>, tensor<f32>)
- outs(%3 : tensor<f32>) {
- ^bb0(%arg3: f32, %arg4: f32, %arg5: f32):
- %5 = arith.mulf %arg3, %arg4 : f32
- linalg.yield %5 : f32
- } -> tensor<f32>
-
- %6 = tensor.empty() : tensor<f32>
- %7 = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = []}
- ins(%1, %4 : tensor<f32>, tensor<f32>)
- outs(%6 : tensor<f32>) {
- ^bb0(%arg3: f32, %arg4: f32, %arg5: f32):
- %5 = arith.divf %arg3, %arg4 : f32
- linalg.yield %5 : f32
- } -> tensor<f32>
-
- return %7: tensor<f32>
-}
-// CHECK-LABEL: func @detensor_op_sequence
-// CHECK-SAME: (%[[arg1:.*]]: tensor<f32>, %[[arg2:.*]]: tensor<f32>)
-// CHECK-DAG: %[[arg1_val:.*]] = tensor.extract %[[arg1]]
-// CHECK-DAG: %[[arg2_val:.*]] = tensor.extract %[[arg2]]
-// CHECK: %[[detensored_res:.*]] = arith.addf %[[arg1_val]], %[[arg2_val]]
-// CHECK: %[[detensored_res2:.*]] = arith.mulf %[[arg1_val]], %[[detensored_res]]
-// CHECK: %[[detensored_res3:.*]] = arith.divf %[[detensored_res]], %[[detensored_res2]]
-// CHECK: %[[new_tensor_res:.*]] = tensor.from_elements %[[detensored_res3]]
-// CHECK: return %[[new_tensor_res]]
-
-func.func @detensor_multiple_ops(%arg1: tensor<f32>, %arg2: tensor<f32>) -> tensor<f32> {
- %0 = tensor.empty() : tensor<f32>
- %1 = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = []}
- ins(%arg1, %arg2 : tensor<f32>, tensor<f32>)
- outs(%0 : tensor<f32>) {
- ^bb0(%arg3: f32, %arg4: f32, %arg5: f32):
- %2 = arith.addf %arg3, %arg4 : f32
- %3 = arith.mulf %2, %arg4 : f32
- linalg.yield %3 : f32
- } -> tensor<f32>
- return %1: tensor<f32>
-}
-// CHECK-LABEL: func @detensor_multiple_ops
-// CHECK-SAME: (%[[arg1:.*]]: tensor<f32>, %[[arg2:.*]]: tensor<f32>)
-// CHECK-DAG: %[[arg1_val:.*]] = tensor.extract %[[arg1]]
-// CHECK-DAG: %[[arg2_val:.*]] = tensor.extract %[[arg2]]
-// CHECK: %[[detensored_res:.*]] = arith.addf %[[arg1_val]], %[[arg2_val]]
-// CHECK: %[[detensored_res2:.*]] = arith.mulf %[[detensored_res]], %[[arg2_val]]
-// CHECK: %[[new_tensor_res:.*]] = tensor.from_elements %[[detensored_res2]]
-// CHECK: return %[[new_tensor_res]]
-
-func.func @detensor_foreign_op(%arg1: tensor<f32>, %arg2: tensor<f32>) -> tensor<f32> {
- %0 = tensor.empty() : tensor<f32>
- %1 = linalg.generic {indexing_maps = [#map, #map, #map], iterator_types = []}
- ins(%arg1, %arg2 : tensor<f32>, tensor<f32>)
- outs(%0 : tensor<f32>) {
- ^bb0(%arg3: f32, %arg4: f32, %arg5: f32):
- %2 = "foreign.do_something"(%arg3, %arg4) {} : (f32, f32) -> f32
- linalg.yield %2 : f32
- } -> tensor<f32>
- return %1: tensor<f32>
-}
-// CHECK-LABEL: func @detensor_foreign_op
-// CHECK-SAME: (%[[arg1:.*]]: tensor<f32>, %[[arg2:.*]]: tensor<f32>)
-// CHECK-DAG: %[[arg1_val:.*]] = tensor.extract %[[arg1]]
-// CHECK-DAG: %[[arg2_val:.*]] = tensor.extract %[[arg2]]
-// CHECK: %[[detensored_res:.*]] = "foreign.do_something"(%[[arg1_val]], %[[arg2_val]])
-// CHECK: %[[new_tensor_res:.*]] = tensor.from_elements %[[detensored_res]]
-// CHECK: return %[[new_tensor_res]]
diff --git a/mlir/test/Dialect/Linalg/detensorize_br_operands.mlir b/mlir/test/Dialect/Linalg/detensorize_br_operands.mlir
deleted file mode 100644
index f36f72a340445..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_br_operands.mlir
+++ /dev/null
@@ -1,45 +0,0 @@
-// RUN: mlir-opt %s -split-input-file -allow-unregistered-dialect -pass-pipeline="builtin.module(func.func(linalg-detensorize))" | FileCheck %s
-
-// TODO: Detensoring breaks if %arg0 or %arg1 are passed directly as tensors. Fix that.
-func.func @if_true_test(%arg0: i1, %arg1: i32) -> tensor<i32> attributes {} {
- %arg0_t = tensor.from_elements %arg0 : tensor<i1>
- %arg1_t = tensor.from_elements %arg1 : tensor<i32>
-
- %cst = arith.constant dense<10> : tensor<i32>
- %2 = tensor.empty() : tensor<i8>
- %3 = linalg.generic
- {indexing_maps = [affine_map<() -> ()>, affine_map<() -> ()>], iterator_types = []}
- ins(%arg0_t : tensor<i1>)
- outs(%2 : tensor<i8>) {
- ^bb0(%arg2: i1, %arg3: i8):
- %10 = arith.extui %arg2 : i1 to i8
- linalg.yield %10 : i8
- } -> tensor<i8>
- %4 = tensor.extract %3[] : tensor<i8>
- %5 = arith.trunci %4 : i8 to i1
- cf.cond_br %5, ^bb1, ^bb2(%arg1_t : tensor<i32>)
-^bb1:
- %6 = tensor.empty() : tensor<i32>
- %7 = linalg.generic
- {indexing_maps = [affine_map<() -> ()>, affine_map<() -> ()>, affine_map<() -> ()>], iterator_types = []}
- ins(%arg1_t, %cst : tensor<i32>, tensor<i32>)
- outs(%6 : tensor<i32>) {
- ^bb0(%arg2: i32, %arg3: i32, %arg4: i32):
- %10 = arith.addi %arg2, %arg3 : i32
- linalg.yield %10 : i32
- } -> tensor<i32>
- cf.br ^bb2(%7 : tensor<i32>)
-^bb2(%8: tensor<i32>):
- return %8 : tensor<i32>
-}
-
-// CHECK-LABEL: func @if_true_test
-// CHECK-SAME: (%[[arg0:.*]]: i1, %[[arg1:.*]]: i32)
-// CHECK-NEXT: arith.constant 10 : i32
-// CHECK-NEXT: cf.cond_br %[[arg0]], ^[[bb1:.*]], ^[[bb2:.*]](%[[arg1]] : i32)
-// CHECK-NEXT: ^[[bb1]]:
-// CHECK-NEXT: %[[add_res:.*]] = arith.addi
-// CHECK-NEXT: cf.br ^[[bb2]](%[[add_res]] : i32)
-// CHECK-NEXT: ^[[bb2]]
-// CHECK-NEXT: %[[func_res:.*]] = tensor.from_elements
-// CHECK-NEXT: return %[[func_res]]
diff --git a/mlir/test/Dialect/Linalg/detensorize_entry_block.mlir b/mlir/test/Dialect/Linalg/detensorize_entry_block.mlir
deleted file mode 100644
index 50a2d6bf532aa..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_entry_block.mlir
+++ /dev/null
@@ -1,21 +0,0 @@
-// RUN: mlir-opt %s -allow-unregistered-dialect -pass-pipeline="builtin.module(func.func(linalg-detensorize))" | FileCheck %s
-
-#map = affine_map<() -> ()>
-func.func @main(%arg0: tensor<f32>) -> tensor<f32> {
- %0 = tensor.empty() : tensor<f32>
- %1 = linalg.generic {indexing_maps = [#map, #map], iterator_types = []} ins(%arg0 : tensor<f32>) outs(%0 : tensor<f32>) {
- ^bb0(%in: f32, %out: f32):
- linalg.yield %in : f32
- } -> tensor<f32>
- cf.br ^bb1(%1 : tensor<f32>)
-^bb1(%2: tensor<f32>): // pred: ^bb0
- return %2 : tensor<f32>
-}
-
-// CHECK-LABEL: @main
-// CHECK-SAME: (%[[ARG0:.+]]: tensor<f32>) -> tensor<f32>
-// CHECK: %[[EXTRACTED:.+]] = tensor.extract %[[ARG0]][] : tensor<f32>
-// CHECK: cf.br ^{{.*}}
-// CHECK: ^{{.*}}:
-// CHECK: %[[ELEMENTS:.+]] = tensor.from_elements %[[EXTRACTED]] : tensor<f32>
-// CHECK: return %[[ELEMENTS]] : tensor<f32>
diff --git a/mlir/test/Dialect/Linalg/detensorize_if.mlir b/mlir/test/Dialect/Linalg/detensorize_if.mlir
deleted file mode 100644
index c728ad21d2209..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_if.mlir
+++ /dev/null
@@ -1,177 +0,0 @@
-// RUN: mlir-opt %s -split-input-file -allow-unregistered-dialect -pass-pipeline="builtin.module(func.func(linalg-detensorize))" | FileCheck %s
-
-#map0 = affine_map<() -> ()>
-
-#attrs = {
- indexing_maps = [#map0, #map0, #map0],
- iterator_types = []
-}
-
-func.func @main() -> (tensor<i32>) attributes {} {
- %c0 = arith.constant 0 : i32
- %0 = tensor.from_elements %c0 : tensor<i32>
- %c10 = arith.constant 10 : i32
- %1 = tensor.from_elements %c10 : tensor<i32>
- cf.br ^bb1(%0 : tensor<i32>)
-
-^bb1(%2: tensor<i32>): // 2 preds: ^bb0, ^bb2
- %3 = tensor.empty() : tensor<i1>
- %4 = linalg.generic #attrs
- ins(%2, %1 : tensor<i32>, tensor<i32>)
- outs(%3 : tensor<i1>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i1):
- %8 = arith.cmpi slt, %arg0, %arg1 : i32
- linalg.yield %8 : i1
- } -> tensor<i1>
- %5 = tensor.extract %4[] : tensor<i1>
- cf.cond_br %5, ^bb2(%2 : tensor<i32>), ^bb3(%2 : tensor<i32>)
-
-^bb2(%6: tensor<i32>): // pred: ^bb1
- %7 = tensor.empty() : tensor<i32>
- %8 = linalg.generic #attrs
- ins(%6, %6 : tensor<i32>, tensor<i32>)
- outs(%7 : tensor<i32>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i32):
- %9 = arith.addi %arg0, %arg1 : i32
- linalg.yield %9 : i32
- } -> tensor<i32>
- cf.br ^bb3(%8 : tensor<i32>)
-
-^bb3(%10: tensor<i32>): // pred: ^bb1
- return %10 : tensor<i32>
-}
-
-// CHECK-LABEL: func @main()
-// CHECK-DAG: %[[cst:.*]] = arith.constant dense<0>
-// CHECK-DAG: arith.constant true
-// CHECK: cf.br
-// CHECK-NEXT: ^[[bb1:.*]]:
-// CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]], ^bb3
-// CHECK-NEXT: ^[[bb2]]
-// CHECK-NEXT: cf.br ^[[bb3:.*]]
-// CHECK-NEXT: ^[[bb3]]
-// CHECK-NEXT: return %[[cst]]
-// CHECK-NEXT: }
-
-// -----
-
-// Similar to the above test with one change: one of the block after the
-// if-condition passes/forwards its tensor argument to another block.
-
-#map0 = affine_map<() -> ()>
-
-#attrs = {
- indexing_maps = [#map0, #map0, #map0],
- iterator_types = []
-}
-
-func.func @main() -> (tensor<i32>) attributes {} {
- %c0 = arith.constant 0 : i32
- %0 = tensor.from_elements %c0 : tensor<i32>
- %c10 = arith.constant 10 : i32
- %1 = tensor.from_elements %c10 : tensor<i32>
- cf.br ^bb1(%0 : tensor<i32>)
-
-^bb1(%2: tensor<i32>): // 2 preds: ^bb0, ^bb2
- %3 = tensor.empty() : tensor<i1>
- %4 = linalg.generic #attrs
- ins(%2, %1 : tensor<i32>, tensor<i32>)
- outs(%3 : tensor<i1>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i1):
- %8 = arith.cmpi slt, %arg0, %arg1 : i32
- linalg.yield %8 : i1
- } -> tensor<i1>
- %5 = tensor.extract %4[] : tensor<i1>
- cf.cond_br %5, ^bb2(%2 : tensor<i32>), ^bb3(%2 : tensor<i32>)
-
-^bb2(%6: tensor<i32>): // pred: ^bb1
- %7 = tensor.empty() : tensor<i32>
- %8 = linalg.generic #attrs
- ins(%6, %6 : tensor<i32>, tensor<i32>)
- outs(%7 : tensor<i32>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i32):
- %9 = arith.addi %arg0, %arg1 : i32
- linalg.yield %9 : i32
- } -> tensor<i32>
- cf.br ^bb3(%8 : tensor<i32>)
-
-^bb3(%10: tensor<i32>): // pred: ^bb1
- cf.br ^bb4(%10 : tensor<i32>)
-
-^bb4(%11: tensor<i32>): // pred: ^bb1
- return %11 : tensor<i32>
-}
-
-// CHECK-LABEL: func @main()
-// CHECK-DAG: %[[cst:.*]] = arith.constant dense<0>
-// CHECK-DAG: arith.constant true
-// CHECK: cf.br ^[[bb1:.*]]
-// CHECK-NEXT: ^[[bb1:.*]]:
-// CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]], ^bb3
-// CHECK-NEXT: ^[[bb2]]:
-// CHECK-NEXT: cf.br ^[[bb3:.*]]
-// CHECK-NEXT: ^[[bb3]]:
-// CHECK-NEXT: cf.br ^[[bb4:.*]]
-// CHECK-NEXT: ^[[bb4]]:
-// CHECK-NEXT: return %[[cst]]
-// CHECK-NEXT: }
-
-// -----
-
-#map0 = affine_map<() -> ()>
-
-#attrs = {
- indexing_maps = [#map0, #map0, #map0],
- iterator_types = []
-}
-
-func.func @main() -> (tensor<i32>) attributes {} {
- %c0 = arith.constant 0 : i32
- %0 = tensor.from_elements %c0 : tensor<i32>
- %c10 = arith.constant 10 : i32
- %1 = tensor.from_elements %c10 : tensor<i32>
- cf.br ^bb1(%0 : tensor<i32>)
-
-^bb1(%2: tensor<i32>): // 2 preds: ^bb0, ^bb2
- %3 = tensor.empty() : tensor<i1>
- %4 = linalg.generic #attrs
- ins(%2, %1 : tensor<i32>, tensor<i32>)
- outs(%3 : tensor<i1>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i1):
- %8 = arith.cmpi slt, %arg0, %arg1 : i32
- linalg.yield %8 : i1
- } -> tensor<i1>
- %5 = tensor.extract %4[] : tensor<i1>
- // This cf.cond_br intentionally has bb2 as it's target for both branches. This
- // is to make sure that the "forward phase" of the cost-model correctly adds
- // the users of a block argument (in this case bb2's argument) to the work
- // list.
- cf.cond_br %5, ^bb2(%2 : tensor<i32>), ^bb2(%2 : tensor<i32>)
-
-^bb2(%6: tensor<i32>): // pred: ^bb1
- %12 = tensor.from_elements %c10 : tensor<i32>
- %7 = tensor.empty() : tensor<i32>
- %8 = linalg.generic #attrs
- ins(%6, %12 : tensor<i32>, tensor<i32>)
- outs(%7 : tensor<i32>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i32):
- %9 = arith.addi %arg0, %arg1 : i32
- linalg.yield %9 : i32
- } -> tensor<i32>
- cf.br ^bb3(%8 : tensor<i32>)
-
-^bb3(%10: tensor<i32>): // pred: ^bb1
- return %10 : tensor<i32>
-}
-
-// CHECK-LABEL: func @main()
-// CHECK-DAG: %[[cst:.*]] = arith.constant dense<10>
-// CHECK-DAG: arith.constant true
-// CHECK: cf.br ^[[bb1:.*]]
-// CHECK-NEXT: ^[[bb1]]:
-// CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]], ^bb2
-// CHECK-NEXT: ^[[bb2]]
-// CHECK-NEXT: cf.br ^[[bb3:.*]]
-// CHECK-NEXT: ^[[bb3]]
-// CHECK-NEXT: return %[[cst]]
-// CHECK-NEXT: }
diff --git a/mlir/test/Dialect/Linalg/detensorize_trivial.mlir b/mlir/test/Dialect/Linalg/detensorize_trivial.mlir
deleted file mode 100644
index 02fa7ace13b9d..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_trivial.mlir
+++ /dev/null
@@ -1,44 +0,0 @@
-// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(linalg-detensorize{aggressive-mode}))" | FileCheck %s -check-prefix=DET-ALL
-// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(linalg-detensorize))" | FileCheck %s -check-prefix=DET-CF
-
-
-#map0 = affine_map<() -> ()>
-
-#attrs = {
- indexing_maps = [#map0, #map0, #map0],
- iterator_types = []
-}
-
-func.func @main(%farg0 : tensor<i32>) -> (tensor<i1>) attributes {} {
- %c10 = arith.constant 10 : i32
- %1 = tensor.from_elements %c10 : tensor<i32>
- %3 = tensor.empty() : tensor<i1>
- %4 = linalg.generic #attrs
- ins(%farg0, %1 : tensor<i32>, tensor<i32>)
- outs(%3 : tensor<i1>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i1):
- %8 = arith.cmpi slt, %arg0, %arg1 : i32
- linalg.yield %8 : i1
- } -> tensor<i1>
- return %4 : tensor<i1>
-}
-
-
-// DET-ALL-LABEL: func @main(%{{.*}}: tensor<i32>)
-// DET-ALL-NEXT: arith.constant 10
-// DET-ALL-NEXT: tensor.extract %{{.*}}[]
-// DET-ALL-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}}
-// DET-ALL-NEXT: tensor.from_elements %{{.*}}
-// DET-ALL-NEXT: return %{{.*}} : tensor<i1>
-// DET-ALL-NEXT: }
-
-// DET-CF-LABEL: func @main(%{{.*}}: tensor<i32>)
-// DET-CF-NEXT: arith.constant dense<10> : tensor<i32>
-// DET-CF-NEXT: tensor.empty() : tensor<i1>
-// DET-CF-NEXT: linalg.generic
-// DET-CF-NEXT: ^{{.*}}(%{{.*}}: i32, %{{.*}}: i32, %{{.*}}: i1)
-// DET-CF-NEXT: arith.cmpi slt, %{{.*}}, %{{.*}}
-// DET-CF-NEXT: linalg.yield %{{.*}}
-// DET-CF-NEXT: } -> tensor<i1>
-// DET-CF-NEXT: return %{{.*}}
-// DET-CF-NEXT: }
diff --git a/mlir/test/Dialect/Linalg/detensorize_while.mlir b/mlir/test/Dialect/Linalg/detensorize_while.mlir
deleted file mode 100644
index 580a97d3a851b..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_while.mlir
+++ /dev/null
@@ -1,71 +0,0 @@
-// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(linalg-detensorize{aggressive-mode}))" | FileCheck %s -check-prefix=DET-ALL
-// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(linalg-detensorize))" | FileCheck %s -check-prefix=DET-CF
-
-#map0 = affine_map<() -> ()>
-
-#attrs = {
- indexing_maps = [#map0, #map0, #map0],
- iterator_types = []
-}
-
-func.func @main(%farg0: tensor<i32>, %farg1: tensor<i32>) -> tensor<i32> attributes {} {
- cf.br ^bb1(%farg0 : tensor<i32>)
-
-^bb1(%0: tensor<i32>): // 2 preds: ^bb0, ^bb2
- %1 = tensor.empty() : tensor<i1>
- %2 = linalg.generic #attrs
- ins(%0, %farg1 : tensor<i32>, tensor<i32>)
- outs(%1 : tensor<i1>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i1):
- %8 = arith.cmpi slt, %arg0, %arg1 : i32
- linalg.yield %8 : i1
- } -> tensor<i1>
- %3 = tensor.extract %2[] : tensor<i1>
- cf.cond_br %3, ^bb2(%0 : tensor<i32>), ^bb3(%0 : tensor<i32>)
-
-^bb2(%4: tensor<i32>): // pred: ^bb1
- %5 = tensor.empty() : tensor<i32>
- %6 = linalg.generic #attrs
- ins(%4, %4 : tensor<i32>, tensor<i32>)
- outs(%5 : tensor<i32>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i32):
- %8 = arith.addi %arg0, %arg1 : i32
- linalg.yield %8 : i32
- } -> tensor<i32>
- cf.br ^bb1(%6 : tensor<i32>)
-
-^bb3(%7: tensor<i32>): // pred: ^bb1
- return %7 : tensor<i32>
-}
-
-// Test aggresively detensoring all detensorable ops.
-//
-// DET-ALL-LABEL: func @main
-// DET-ALL-SAME: (%{{.*}}: tensor<i32>, %{{.*}}: tensor<i32>)
-// DET-ALL: tensor.extract {{.*}}
-// DET-ALL: cf.br ^[[bb1:.*]](%{{.*}} : i32)
-// DET-ALL: ^[[bb1]](%{{.*}}: i32)
-// DET-ALL: arith.cmpi slt, {{.*}}
-// DET-ALL: cf.cond_br {{.*}}, ^[[bb2:.*]], ^[[bb3:.*]]
-// DET-ALL: ^[[bb2]]
-// DET-ALL: arith.addi {{.*}}
-// DET-ALL: cf.br ^[[bb1]](%{{.*}} : i32)
-// DET-ALL: ^[[bb3]]:
-// DET-ALL: tensor.from_elements {{.*}}
-// DET-ALL: return %{{.*}} : tensor<i32>
-
-// Test detensoring only ops involed in control-flow.
-//
-// DET-CF-LABEL: func @main
-// DET-CF-SAME: (%{{.*}}: tensor<i32>, %{{.*}}: tensor<i32>)
-// DET-CF: tensor.extract {{.*}}
-// DET-CF: cf.br ^[[bb1:.*]](%{{.*}} : i32)
-// DET-CF: ^[[bb1]](%{{.*}}: i32)
-// DET-CF: arith.cmpi slt, {{.*}}
-// DET-CF: cf.cond_br {{.*}}, ^[[bb2:.*]], ^[[bb3:.*]]
-// DET-CF: ^[[bb2]]:
-// DET-CF: arith.addi {{.*}}
-// DET-CF: cf.br ^[[bb1]](%{{.*}} : i32)
-// DET-CF: ^[[bb3]]:
-// DET-CF: tensor.from_elements %{{.*}} : tensor<i32>
-// DET-CF: return %{{.*}} : tensor<i32>
diff --git a/mlir/test/Dialect/Linalg/detensorize_while_impure_cf.mlir b/mlir/test/Dialect/Linalg/detensorize_while_impure_cf.mlir
deleted file mode 100644
index 414d9b94cbf53..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_while_impure_cf.mlir
+++ /dev/null
@@ -1,104 +0,0 @@
-// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(linalg-detensorize{aggressive-mode}))" | FileCheck %s -check-prefix=DET-ALL
-// RUN: mlir-opt %s -pass-pipeline="builtin.module(func.func(linalg-detensorize))" | FileCheck %s -check-prefix=DET-CF
-
-#map0 = affine_map<() -> ()>
-#map1 = affine_map<(i) -> ()>
-#map2 = affine_map<(i) -> (i)>
-
-#attrs = {
- indexing_maps = [#map0, #map0, #map0],
- iterator_types = []
-}
-
-#sum_reduction_attrs = {
- indexing_maps = [#map2, #map1],
- iterator_types = ["reduction"]
-}
-
-
-#broadcast_attrs = {
- indexing_maps = [#map1, #map2],
- iterator_types = ["parallel"]
-}
-
-func.func @main(%farg0: tensor<10xi32>, %farg1: tensor<i32>) -> tensor<i32> attributes {} {
- cf.br ^bb1(%farg0 : tensor<10xi32>)
-
-^bb1(%0: tensor<10xi32>): // 2 preds: ^bb0, ^bb2
- %1 = tensor.empty() : tensor<i32>
- %2 = linalg.generic #sum_reduction_attrs
- ins(%0: tensor<10xi32>)
- outs(%1: tensor<i32>) {
- ^bb(%a: i32, %x: i32):
- %b = arith.addi %x, %a : i32
- linalg.yield %b : i32
- } -> tensor<i32>
-
- %3 = tensor.empty() : tensor<i1>
- %4 = linalg.generic #attrs
- ins(%2, %farg1 : tensor<i32>, tensor<i32>)
- outs(%3 : tensor<i1>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i1):
- %8 = arith.cmpi slt, %arg0, %arg1 : i32
- linalg.yield %8 : i1
- } -> tensor<i1>
- %5 = tensor.extract %4[] : tensor<i1>
- cf.cond_br %5, ^bb2(%2 : tensor<i32>), ^bb3(%2 : tensor<i32>)
-
-^bb2(%6: tensor<i32>): // pred: ^bb1
- %7 = tensor.empty() : tensor<10xi32>
- %9 = linalg.generic #broadcast_attrs
- ins(%6: tensor<i32>)
- outs(%7: tensor<10xi32>) {
- ^bb(%a: i32, %b: i32) :
- linalg.yield %a : i32
- } -> tensor<10xi32>
-
- cf.br ^bb1(%9 : tensor<10xi32>)
-
-^bb3(%10: tensor<i32>): // pred: ^bb1
- return %10 : tensor<i32>
-}
-
-// Test aggresively detensoring all detensorable ops.
-//
-// DET-ALL-LABEL: func @main
-// DET-ALL-SAME: (%{{.*}}: tensor<10xi32>, %{{.*}}: tensor<i32>)
-// DET-ALL: cf.br ^[[bb1:.*]](%{{.*}} : tensor<10xi32>)
-// DET-ALL: ^[[bb1]](%{{.*}}: tensor<10xi32>)
-// DET-ALL: tensor.empty() : tensor<i32>
-// DET-ALL: linalg.generic {{{.*}}} ins(%{{.*}} : tensor<10xi32>) outs(%{{.*}} : tensor<i32>) {
-// DET-ALL: ^bb0(%{{.*}}: i32, %{{.*}}: i32):
-// DET-ALL: %{{.*}} = arith.addi %{{.*}}, %{{.*}}
-// DET-ALL: linalg.yield %{{.*}} : i32
-// DET-ALL: } -> tensor<i32>
-// DET-ALL: tensor.extract %{{.*}}[] : tensor<i32>
-// DET-ALL: cmpi slt, %{{.*}}, %{{.*}} : i32
-// DET-ALL: cf.cond_br %{{.*}}, ^[[bb2:.*]], ^[[bb3:.*]]
-// DET-ALL: ^[[bb2]]:
-// DET-ALL: tensor.from_elements %{{.*}} : tensor<i32>
-// DET-ALL: tensor.empty() : tensor<10xi32>
-// DET-ALL: linalg.generic {{{.*}}} ins(%{{.*}} : tensor<i32>) outs(%{{.*}} : tensor<10xi32>) {
-// DET-ALL: ^bb0(%{{.*}}: i32, %{{.*}}: i32):
-// DET-ALL: linalg.yield %{{.*}} : i32
-// DET-ALL: } -> tensor<10xi32>
-// DET-ALL: cf.br ^[[bb1]](%{{.*}} : tensor<10xi32>)
-// DET-ALL: ^[[bb3]]
-// DET-ALL: tensor.from_elements %{{.*}} : tensor<i32>
-// DET-ALL: return %{{.*}} : tensor<i32>
-// DET-ALL: }
-
-// DET-CF-LABEL: func @main
-// DET-CF-SAME: (%{{.*}}: tensor<10xi32>, %{{.*}}: tensor<i32>)
-// DET-CF: cf.br ^[[bb1:.*]](%{{.*}} : tensor<10xi32>)
-// DET-CF: ^bb1(%{{.*}}: tensor<10xi32>)
-// DET-CF: %{{.*}} = linalg.generic {{{.*}}} ins(%{{.*}} : tensor<10xi32>) outs(%{{.*}} : tensor<i32>) {
-// DET-CF: tensor.extract %{{.*}}[] : tensor<i32>
-// DET-CF: cmpi slt, %{{.*}}, %{{.*}} : i32
-// DET-CF: cf.cond_br %{{.*}}, ^bb2, ^bb3
-// DET-CF: ^bb2:
-// DET-CF: %{{.*}} = linalg.generic {{{.*}}} ins(%{{.*}} : tensor<i32>) outs(%{{.*}} : tensor<10xi32>) {
-// DET-CF: cf.br ^bb1(%{{.*}} : tensor<10xi32>)
-// DET-CF: ^bb3:
-// DET-CF: return %{{.*}} : tensor<i32>
-// DET-CF: }
diff --git a/mlir/test/Dialect/Linalg/detensorize_while_pure_cf.mlir b/mlir/test/Dialect/Linalg/detensorize_while_pure_cf.mlir
deleted file mode 100644
index 913e78272db79..0000000000000
--- a/mlir/test/Dialect/Linalg/detensorize_while_pure_cf.mlir
+++ /dev/null
@@ -1,58 +0,0 @@
-// RUN: mlir-opt %s -allow-unregistered-dialect -pass-pipeline="builtin.module(func.func(linalg-detensorize))" | FileCheck %s
-
-#map0 = affine_map<() -> ()>
-
-#attrs = {
- indexing_maps = [#map0, #map0, #map0],
- iterator_types = []
-}
-
-func.func @main() -> () attributes {} {
- %c0 = arith.constant 0 : i32
- %0 = tensor.from_elements %c0 : tensor<1xi32>
- %reshaped0 = tensor.collapse_shape %0 [] : tensor<1xi32> into tensor<i32>
- %c10 = arith.constant 10 : i32
- %1 = tensor.from_elements %c10 : tensor<1xi32>
- %reshaped1 = tensor.collapse_shape %1 [] : tensor<1xi32> into tensor<i32>
- cf.br ^bb1(%reshaped0 : tensor<i32>)
-
-^bb1(%2: tensor<i32>): // 2 preds: ^bb0, ^bb2
- %3 = tensor.empty() : tensor<i1>
- %4 = linalg.generic #attrs
- ins(%2, %reshaped1 : tensor<i32>, tensor<i32>)
- outs(%3 : tensor<i1>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i1):
- %8 = arith.cmpi slt, %arg0, %arg1 : i32
- linalg.yield %8 : i1
- } -> tensor<i1>
- %5 = tensor.extract %4[] : tensor<i1>
- cf.cond_br %5, ^bb2(%2 : tensor<i32>), ^bb3
-
-^bb2(%6: tensor<i32>): // pred: ^bb1
- %7 = tensor.empty() : tensor<i32>
- %8 = linalg.generic #attrs
- ins(%6, %6 : tensor<i32>, tensor<i32>)
- outs(%7 : tensor<i32>) {
- ^bb0(%arg0: i32, %arg1: i32, %arg2: i32):
- %9 = arith.addi %arg0, %arg1 : i32
- linalg.yield %9 : i32
- } -> tensor<i32>
- cf.br ^bb1(%8 : tensor<i32>)
-
-^bb3: // pred: ^bb1
- return
-}
-
-// CHECK-LABEL: func @main
-// CHECK-DAG: arith.constant 0 : i32
-// CHECK-DAG: arith.constant 10
-// CHECK-NEXT: cf.br ^[[bb1:.*]](%{{.*}} : i32)
-// CHECK-NEXT: ^[[bb1]](%{{.*}}: i32)
-// CHECK-NEXT: %{{.*}} = arith.cmpi slt, %{{.*}}, %{{.*}}
-// CHECK-NEXT: cf.cond_br %{{.*}}, ^[[bb2:.*]], ^[[bb3:.*]]
-// CHECK-NEXT: ^[[bb2]]
-// CHECK-NEXT: %{{.*}} = arith.addi %{{.*}}, %{{.*}}
-// CHECK-NEXT: cf.br ^[[bb1]](%{{.*}} : i32)
-// CHECK-NEXT: ^[[bb3]]:
-// CHECK-NEXT: return
-// CHECK-NEXT: }
More information about the Mlir-commits
mailing list