#include "bishengir/Dialect/Scope/Utils/Utils.h"
#include "bishengir/Dialect/Vector/Transforms/Passes.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/Dialect/Tensor/IR/Tensor.h"
#include "mlir/Dialect/Vector/IR/VectorOps.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
namespace mlir {
#define GEN_PASS_DEF_MATERIALIZEVECTORWRITETODESTINATION
#include "bishengir/Dialect/Vector/Transforms/Passes.h.inc"
}
#define DEBUG_TYPE "materialize-vector-write-to-destination"
using namespace mlir;
using namespace mlir::scf;
using namespace mlir::tensor;
namespace {
struct FoldInsertSliceToTransferWrite
: public OpRewritePattern<tensor::InsertSliceOp> {
using OpRewritePattern<tensor::InsertSliceOp>::OpRewritePattern;
LogicalResult matchAndRewrite(tensor::InsertSliceOp insertOp,
PatternRewriter &rewriter) const override {
auto transferWriteOp =
insertOp.getSource().getDefiningOp<vector::TransferWriteOp>();
if (!transferWriteOp)
return failure();
#ifndef __LLVM_MAJOR_VERSION_22_COMPATIBLE__
if (transferWriteOp.getSource().getDefiningOp<tensor::ExtractSliceOp>())
return failure();
#else
if (transferWriteOp.getBase().getDefiningOp<tensor::ExtractSliceOp>())
return failure();
#endif
rewriter.setInsertionPoint(transferWriteOp);
if (transferWriteOp->hasOneUse()) {
rewriter.modifyOpInPlace(
insertOp, [&]() { transferWriteOp->moveBefore(insertOp); });
}
auto insertDest = insertOp.getDest();
auto extractOp = rewriter.create<tensor::ExtractSliceOp>(
transferWriteOp.getLoc(), insertOp.getSourceType(), insertDest,
insertOp.getMixedOffsets(), insertOp.getMixedSizes(),
insertOp.getMixedStrides());
auto newTransferWriteOp = rewriter.create<vector::TransferWriteOp>(
transferWriteOp.getLoc(), transferWriteOp.getVector(),
extractOp.getResult(),
transferWriteOp.getIndices(), transferWriteOp.getPermutationMapAttr(),
transferWriteOp.getMask(), transferWriteOp.getInBoundsAttr());
rewriter.replaceOp(transferWriteOp, newTransferWriteOp.getResult());
return success();
}
};
struct RedirectWriteDstToIterArg : public OpRewritePattern<scf::ForOp> {
using OpRewritePattern<scf::ForOp>::OpRewritePattern;
LogicalResult matchAndRewrite(scf::ForOp forOp,
PatternRewriter &rewriter) const override {
auto yieldOp = cast<scf::YieldOp>(forOp.getBody()->getTerminator());
bool changed = false;
for (auto it : llvm::enumerate(yieldOp.getOperands())) {
Value yieldedVal = it.value();
auto writeOp = yieldedVal.getDefiningOp<vector::TransferWriteOp>();
if (!writeOp)
continue;
Value destTensor = writeOp.getSource();
if (!destTensor.getDefiningOp<tensor::EmptyOp>() &&
!isFuncArg(destTensor)) {
continue;
}
BlockArgument iterArg = forOp.getRegionIterArg(it.index());
if (iterArg.getType() != destTensor.getType())
continue;
rewriter.setInsertionPoint(writeOp);
auto newWriteOp = rewriter.create<vector::TransferWriteOp>(
writeOp.getLoc(), writeOp.getVector(),
iterArg,
writeOp.getIndices(), writeOp.getPermutationMapAttr(),
writeOp.getMask(), writeOp.getInBoundsAttr());
rewriter.replaceOp(writeOp, newWriteOp.getResult());
changed = true;
}
return success(changed);
}
private:
bool isFuncArg(Value value) const {
auto blockArg = dyn_cast<BlockArgument>(value);
return blockArg && blockArg.getOwner()->isEntryBlock() &&
isa<FunctionOpInterface>(blockArg.getOwner()->getParentOp());
}
};
struct MaterializeVectorWriteToDestinationPass
: public impl::MaterializeVectorWriteToDestinationBase<
MaterializeVectorWriteToDestinationPass> {
public:
void runOnOperation() override;
};
}
void MaterializeVectorWriteToDestinationPass::runOnOperation() {
func::FuncOp funcOp = getOperation();
if (!scope::utils::isManualVFScope(funcOp)) {
return;
}
MLIRContext *context = &getContext();
RewritePatternSet patterns(context);
patterns.add<FoldInsertSliceToTransferWrite>(context);
patterns.add<RedirectWriteDstToIterArg>(context);
if (failed(applyPatternsGreedily(funcOp, std::move(patterns)))) {
signalPassFailure();
}
}
std::unique_ptr<Pass>
mlir::vector::createMaterializeVectorWriteToDestinationPass() {
return std::make_unique<MaterializeVectorWriteToDestinationPass>();
}