Files
clang-p2996/mlir/lib/Dialect/Linalg/Transforms/InlineScalarOperands.cpp
Matthias Springer 0a8e3dd432 [mlir][Interfaces] DestinationStyleOpInterface: Rename hasTensor/BufferSemantics (#77574)
Rename interface functions as follows:
* `hasTensorSemantics` -> `hasPureTensorSemantics`
* `hasBufferSemantics` -> `hasPureBufferSemantics`

These two functions return "true" if the op has tensor/buffer operands
but not buffer/tensor operands.

Also drop the "ranked" part from the interface, i.e., do not distinguish
between ranked/unranked types.

The new function names describe the functions more accurately. They also
align their semantics with the notion of "tensor semantics" with the
bufferization framework. (An op is supposed to be bufferized if it has
tensor operands, and we don't care if it also has memref operands.)

This change is in preparation of #75273, which adds
`BufferizableOpInterface::hasTensorSemantics`. By renaming the functions
in the `DestinationStyleOpInterface`, we can avoid name clashes between
the two interfaces.
2024-01-12 10:02:54 +01:00

119 lines
4.3 KiB
C++

//===- InlineScalarOperands.cpp - Pass to inline scalar operands =============//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file implements patterns/pass to inline scalar operands into a generic
// operation. A scalar operand is an operand whose indexing map has a constant
// rhs.
//
//===----------------------------------------------------------------------===//
#include "mlir/Dialect/Linalg/Passes.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/Linalg/IR/Linalg.h"
#include "mlir/Dialect/Linalg/Transforms/Transforms.h"
#include "mlir/IR/AffineExpr.h"
#include "mlir/IR/AffineMap.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
namespace mlir {
#define GEN_PASS_DEF_LINALGINLINESCALAROPERANDS
#include "mlir/Dialect/Linalg/Passes.h.inc"
} // namespace mlir
using namespace mlir;
using namespace mlir::linalg;
namespace {
struct InlineScalarOperands : public OpRewritePattern<GenericOp> {
using OpRewritePattern<GenericOp>::OpRewritePattern;
LogicalResult matchAndRewrite(GenericOp genericOp,
PatternRewriter &rewriter) const override {
if (!genericOp.hasPureTensorSemantics())
return failure();
SmallVector<size_t> scalarOperands;
SmallVector<AffineMap> newIndexingMaps;
SmallVector<Value> newOperands;
for (OpOperand *opOperand : genericOp.getDpsInputOperands()) {
AffineMap map = genericOp.getMatchingIndexingMap(opOperand);
if (genericOp.isDpsInput(opOperand) && map.isConstant()) {
scalarOperands.emplace_back(opOperand->getOperandNumber());
} else {
newIndexingMaps.emplace_back(map);
newOperands.emplace_back(opOperand->get());
}
}
if (scalarOperands.empty())
return failure();
for (OpOperand &opOperand : genericOp.getDpsInitsMutable())
newIndexingMaps.emplace_back(
genericOp.getMatchingIndexingMap(&opOperand));
Location loc = genericOp->getLoc();
SmallVector<Value> outputOperands = genericOp.getOutputs();
auto newOp = rewriter.create<GenericOp>(
loc, genericOp->getResultTypes(), newOperands, outputOperands,
newIndexingMaps, genericOp.getIteratorTypesArray());
rewriter.cloneRegionBefore(genericOp.getRegion(), newOp.getRegion(),
newOp.getRegion().begin());
Block *body = newOp.getBody();
PatternRewriter::InsertionGuard guard(rewriter);
rewriter.setInsertionPointToStart(body);
for (auto idx : llvm::reverse(scalarOperands)) {
OpOperand *opOperand = genericOp.getDpsInputOperand(idx);
AffineMap map = genericOp.getMatchingIndexingMap(opOperand);
SmallVector<int64_t> indices = map.getConstantResults();
SmallVector<Value> indicesValues;
for (auto idx : indices)
indicesValues.emplace_back(
rewriter.create<arith::ConstantIndexOp>(loc, idx));
Value extractedValue = rewriter.create<tensor::ExtractOp>(
loc, opOperand->get(), indicesValues);
body->getArgument(idx).replaceAllUsesWith(extractedValue);
body->eraseArgument(idx);
}
rewriter.replaceOp(genericOp, newOp->getResults());
return success();
}
};
} // namespace
/// Patterns that are used to inline constant operands into linalg generic
/// ops.
void mlir::linalg::populateInlineConstantOperandsPatterns(
RewritePatternSet &patterns) {
auto *context = patterns.getContext();
patterns.add<InlineScalarOperands>(context);
}
namespace {
/// Pass that removes unit-extent dims within generic ops.
struct LinalgInlineScalarOperandsPass
: public impl::LinalgInlineScalarOperandsBase<
LinalgInlineScalarOperandsPass> {
void runOnOperation() override {
Operation *op = getOperation();
MLIRContext &ctx = getContext();
RewritePatternSet patterns(&ctx);
populateInlineConstantOperandsPatterns(patterns);
(void)applyPatternsAndFoldGreedily(op, std::move(patterns));
}
};
} // namespace
std::unique_ptr<Pass> mlir::createLinalgInlineScalarOperandsPass() {
return std::make_unique<LinalgInlineScalarOperandsPass>();
}