MLIR-AIE 1.4.5.dev
DynamicSizeNoImplicitBroadcast.cpp
Go to the documentation of this file.
1//===- DynamicSizeNoImplicitBroadcast.cpp -=====================-*- C++ -*-===//
2//
3// Copyright (C) 2023 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7// This file contains rewrites to the arith dialect to enable the support of
8// dynamic sized tensor/memref for the auto-vectorization to CPP flow.
9// MLIR-AIE auto-vectorization to CPP flow currently doesn't support to
10// implicitly broadcast a dynamic dimension of size `1`. Hence, we assume that
11// dynamic dimensions are not with size '1' that can be interpreted to various
12// broadcasting scenarios. The effectiveness of this rewrite pattern is guarded
13// by the attribute `tosa.no_implicit_broadcast_of_dynamic_sizes`.
14//===----------------------------------------------------------------------===//
15
18
19#include "mlir/Dialect/Arith/IR/Arith.h"
20#include "mlir/Dialect/MemRef/IR/MemRef.h"
21#include "mlir/Dialect/Tensor/IR/Tensor.h"
22#include "mlir/Pass/PassManager.h"
23#include "mlir/Transforms/GreedyPatternRewriteDriver.h"
24
25#define DEBUG_TYPE "dynamic-size-no-implicit-broadcast"
26
27using namespace llvm;
28using namespace mlir;
29using namespace xilinx;
30using namespace xilinx::aievec;
31
32//============================================================================//
33//=========================== Rewrite Patterns ===============================//
34//============================================================================//
35
36// This pattern replaces a arith::CmpIOp with a arith::ConstantOp `false` only
37// when the CmpIOp compares the equality of a dynamic dimension's runtime size
38// to a constant 1, and is guarded by the attribute
39// `tosa.no_implicit_broadcast_of_dynamic_sizes`.
42 : RewritePattern(arith::CmpIOp::getOperationName(), /*benefit=*/1,
43 context) {}
44
45 LogicalResult matchAndRewrite(Operation *op,
46 PatternRewriter &rewriter) const override {
48 return failure();
49
50 arith::CmpIOp cmpiOp = cast<arith::CmpIOp>(op);
51
52 if (cmpiOp.getPredicate() != arith::CmpIPredicate::eq)
53 return failure();
54
55 auto *lhsOp = cmpiOp.getLhs().getDefiningOp();
56 auto *rhsOp = cmpiOp.getRhs().getDefiningOp();
57 if (!((isa<memref::DimOp>(lhsOp) || isa<tensor::DimOp>(lhsOp)) &&
58 isa<arith::ConstantOp>(rhsOp)) &&
59 !((isa<memref::DimOp>(rhsOp) || isa<tensor::DimOp>(rhsOp)) &&
60 isa<arith::ConstantOp>(lhsOp)))
61 return failure();
62
63 // Make sure rhsOp is ConstantOp and lhsOp is DimOp
64 if (isa<memref::DimOp>(rhsOp) || isa<tensor::DimOp>(rhsOp))
65 std::swap(lhsOp, rhsOp);
66
67 // If ConstantOp is 1 for Integer/Index, replace cmpiOp as constant 0
68 auto constantOp = cast<arith::ConstantOp>(rhsOp);
69 if (cast<IntegerAttr>(constantOp.getValue()).getValue().getZExtValue() != 1)
70 return failure();
71
72 // Check the DimOp's input is a dynamic dim from the given index
73 auto constIndexOp = lhsOp->getOperand(1).getDefiningOp<arith::ConstantOp>();
74 if (!constIndexOp)
75 return failure();
76
77 auto index =
78 cast<IntegerAttr>(constIndexOp.getValue()).getValue().getZExtValue();
79 auto inputDimType = dyn_cast<ShapedType>(lhsOp->getOperand(0).getType());
80 if (!inputDimType || !inputDimType.isDynamicDim(index))
81 return failure();
82
83 rewriter.replaceOpWithNewOp<arith::ConstantOp>(
84 cmpiOp, rewriter.getIntegerAttr(rewriter.getI1Type(), 0));
85
86 return success();
87 }
88};
89
90//============================================================================//
91//======================== Canonicalization Passes ===========================//
92//============================================================================//
93
95 : PassWrapper<DynamicSizeNoImplicitBroadcastPass, OperationPass<>> {
96
97 StringRef getArgument() const final {
98 return "test-dynamic-size-no-implicit-broadcast";
99 }
100
101 StringRef getDescription() const final {
102 return "Test rewriting arith operations when assuming no implict "
103 "broadcast of dynamic sizes";
104 }
105
106 void runOnOperation() override {
107 auto *op = getOperation();
108 MLIRContext *context = &getContext();
109 RewritePatternSet patterns(context);
110
111 patterns.add<DynamicSizeNoImplicitBroadcastPattern>(patterns.getContext());
112
113 (void)applyPatternsGreedily(op, std::move(patterns));
114 }
115};
116
117std::unique_ptr<::mlir::Pass>
119 return std::make_unique<DynamicSizeNoImplicitBroadcastPass>();
120}
121
122//============================================================================//
123//====================== Main Pipeline Configuration =========================//
124//============================================================================//
125
127 OpPassManager &pm) {
129}
bool isAssumingNoImplicitBroadcastOfDynamicSizes(mlir::Block *block)
std::unique_ptr<::mlir::Pass > createDynamicSizeNoImplicitBroadcastPass()
void buildDynamicSizeNoImplicitBroadcastPass(mlir::OpPassManager &pm)
LogicalResult matchAndRewrite(Operation *op, PatternRewriter &rewriter) const override