CIRCT 24.0.0git
Loading...
Searching...
No Matches
MapArithToComb.cpp
Go to the documentation of this file.
1//===- MapArithToComb.cpp - Arith-to-comb mapping pass ----------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Contains the definitions of the MapArithToComb pass.
10//
11//===----------------------------------------------------------------------===//
12
17#include "mlir/Dialect/Arith/IR/Arith.h"
18#include "mlir/Pass/Pass.h"
19#include "mlir/Transforms/DialectConversion.h"
20
21namespace circt {
22#define GEN_PASS_DEF_MAPARITHTOCOMBPASS
23#include "circt/Transforms/Passes.h.inc"
24} // namespace circt
25
26using namespace mlir;
27using namespace circt;
28
29namespace {
30
31// A type converter which legalizes integer types, thus ensuring that vector
32// types are illegal.
33class MapArithTypeConverter : public mlir::TypeConverter {
34public:
35 MapArithTypeConverter() {
36 addConversion([](Type type) {
37 if (hw::isHWValueType(type))
38 return type;
39
40 return Type();
41 });
42 }
43};
44
45template <typename TFrom, typename TTo>
46class OneToOnePattern : public OpConversionPattern<TFrom> {
47public:
48 using OpConversionPattern<TFrom>::OpConversionPattern;
49 using OpAdaptor = typename TFrom::Adaptor;
50
51 LogicalResult
52 matchAndRewrite(TFrom op, OpAdaptor adaptor,
53 ConversionPatternRewriter &rewriter) const override {
54 typename TTo::Properties properties{};
55 TTo::populateDefaultProperties(
56 OperationName(TTo::getOperationName(), rewriter.getContext()),
57 properties);
58 auto newOp =
59 TTo::create(rewriter, op.getLoc(), adaptor.getOperands(), properties);
60 rewriter.replaceOp(op, newOp);
61 return success();
62 }
63};
64
65class ExtSConversionPattern : public OpConversionPattern<arith::ExtSIOp> {
66public:
67 using OpConversionPattern<arith::ExtSIOp>::OpConversionPattern;
68 using OpAdaptor = typename arith::ExtSIOp::Adaptor;
69
70 LogicalResult
71 matchAndRewrite(arith::ExtSIOp op, OpAdaptor adaptor,
72 ConversionPatternRewriter &rewriter) const override {
73 size_t outWidth = op.getType().getIntOrFloatBitWidth();
74 rewriter.replaceOp(
75 op, comb::createOrFoldSExt(rewriter, op.getLoc(), op.getOperand(),
76 rewriter.getIntegerType(outWidth)));
77 return success();
78 }
79};
80
81class ExtZConversionPattern : public OpConversionPattern<arith::ExtUIOp> {
82public:
83 using OpConversionPattern<arith::ExtUIOp>::OpConversionPattern;
84 using OpAdaptor = typename arith::ExtUIOp::Adaptor;
85
86 LogicalResult
87 matchAndRewrite(arith::ExtUIOp op, OpAdaptor adaptor,
88 ConversionPatternRewriter &rewriter) const override {
89 auto loc = op.getLoc();
90 size_t outWidth = op.getOut().getType().getIntOrFloatBitWidth();
91 size_t inWidth = adaptor.getIn().getType().getIntOrFloatBitWidth();
92
93 rewriter.replaceOp(op, comb::ConcatOp::create(
94 rewriter, loc,
96 rewriter, loc, APInt(outWidth - inWidth, 0)),
97 adaptor.getIn()));
98 return success();
99 }
100};
101
102class TruncateConversionPattern : public OpConversionPattern<arith::TruncIOp> {
103public:
104 using OpConversionPattern<arith::TruncIOp>::OpConversionPattern;
105 using OpAdaptor = typename arith::TruncIOp::Adaptor;
106
107 LogicalResult
108 matchAndRewrite(arith::TruncIOp op, OpAdaptor adaptor,
109 ConversionPatternRewriter &rewriter) const override {
110 size_t outWidth = op.getType().getIntOrFloatBitWidth();
111 rewriter.replaceOpWithNewOp<comb::ExtractOp>(op, adaptor.getIn(), 0,
112 outWidth);
113 return success();
114 }
115};
116
117class CompConversionPattern : public OpConversionPattern<arith::CmpIOp> {
118public:
119 using OpConversionPattern<arith::CmpIOp>::OpConversionPattern;
120 using OpAdaptor = typename arith::CmpIOp::Adaptor;
121
122 static comb::ICmpPredicate
123 arithToCombPredicate(arith::CmpIPredicate predicate) {
124 switch (predicate) {
125 case arith::CmpIPredicate::eq:
126 return comb::ICmpPredicate::eq;
127 case arith::CmpIPredicate::ne:
128 return comb::ICmpPredicate::ne;
129 case arith::CmpIPredicate::slt:
130 return comb::ICmpPredicate::slt;
131 case arith::CmpIPredicate::ult:
132 return comb::ICmpPredicate::ult;
133 case arith::CmpIPredicate::sle:
134 return comb::ICmpPredicate::sle;
135 case arith::CmpIPredicate::ule:
136 return comb::ICmpPredicate::ule;
137 case arith::CmpIPredicate::sgt:
138 return comb::ICmpPredicate::sgt;
139 case arith::CmpIPredicate::ugt:
140 return comb::ICmpPredicate::ugt;
141 case arith::CmpIPredicate::sge:
142 return comb::ICmpPredicate::sge;
143 case arith::CmpIPredicate::uge:
144 return comb::ICmpPredicate::uge;
145 }
146 llvm_unreachable("Unknown predicate");
147 }
148
149 LogicalResult
150 matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor,
151 ConversionPatternRewriter &rewriter) const override {
152 rewriter.replaceOpWithNewOp<comb::ICmpOp>(
153 op, arithToCombPredicate(op.getPredicate()), adaptor.getLhs(),
154 adaptor.getRhs());
155 return success();
156 }
157};
158
159struct ConstantConversionPattern
160 : public OpConversionPattern<arith::ConstantOp> {
161 using OpConversionPattern::OpConversionPattern;
162
163 LogicalResult
164 matchAndRewrite(arith::ConstantOp op, OpAdaptor adaptor,
165 ConversionPatternRewriter &rewriter) const override {
166 // `hw.constant` only supports integers.
167 if (!isa<IntegerType>(op.getType()))
168 return failure();
169
170 rewriter.replaceOpWithNewOp<hw::ConstantOp>(
171 op, cast<IntegerAttr>(adaptor.getValue()));
172 return success();
173 }
174};
175
176// Pattern for arith min/max operations.
177// These lower to: cmp + mux
178template <typename ArithOp, comb::ICmpPredicate pred>
179class MinMaxConversionPattern : public OpConversionPattern<ArithOp> {
180public:
181 using OpConversionPattern<ArithOp>::OpConversionPattern;
182 using OpAdaptor = typename ArithOp::Adaptor;
183
184 LogicalResult
185 matchAndRewrite(ArithOp op, OpAdaptor adaptor,
186 ConversionPatternRewriter &rewriter) const override {
187 // max(a, b) = mux(cmp(a, b), a, b)
188 // min(a, b) = mux(cmp(a, b), a, b)
189 auto cmp = comb::ICmpOp::create(rewriter, op.getLoc(), pred,
190 adaptor.getLhs(), adaptor.getRhs());
191 rewriter.replaceOpWithNewOp<comb::MuxOp>(op, cmp, adaptor.getLhs(),
192 adaptor.getRhs());
193 return success();
194 }
195};
196
197struct MapArithToCombPass
198 : public circt::impl::MapArithToCombPassBase<MapArithToCombPass> {
199public:
200 MapArithToCombPass(bool enableBestEffortLowering) {
201 this->enableBestEffortLowering = enableBestEffortLowering;
202 }
203
204 void runOnOperation() override {
205 auto *ctx = &getContext();
206
207 ConversionTarget target(*ctx);
208 target.addLegalDialect<comb::CombDialect, hw::HWDialect>();
209 if (!enableBestEffortLowering) {
210 target.addIllegalDialect<arith::ArithDialect>();
211 } else {
212 // We make all arith operations with a potential lowering here (as
213 // specified in circt::populateArithToCombPatterns) illegal
214 target.addIllegalOp<arith::AddIOp>();
215 target.addIllegalOp<arith::SubIOp>();
216 target.addIllegalOp<arith::MulIOp>();
217 target.addIllegalOp<arith::DivSIOp>();
218 target.addIllegalOp<arith::DivUIOp>();
219 target.addIllegalOp<arith::RemSIOp>();
220 target.addIllegalOp<arith::RemUIOp>();
221 target.addIllegalOp<arith::AndIOp>();
222 target.addIllegalOp<arith::OrIOp>();
223 target.addIllegalOp<arith::XOrIOp>();
224 target.addIllegalOp<arith::ShLIOp>();
225 target.addIllegalOp<arith::ShRSIOp>();
226 target.addIllegalOp<arith::ShRUIOp>();
227 target.addIllegalOp<arith::ExtSIOp>();
228 target.addIllegalOp<arith::ExtUIOp>();
229 target.addIllegalOp<arith::TruncIOp>();
230 target.addIllegalOp<arith::CmpIOp>();
231 target.addIllegalOp<arith::MaxSIOp>();
232 target.addIllegalOp<arith::MaxUIOp>();
233 target.addIllegalOp<arith::MinSIOp>();
234 target.addIllegalOp<arith::MinUIOp>();
235
236 // Force integer constants to be mapped to `hw.constant`.
237 target.addDynamicallyLegalOp<arith::ConstantOp>([](Operation *op) {
238 return !isa<IntegerType>(op->getResult(0).getType());
239 });
240
241 target.addDynamicallyLegalOp<arith::SelectOp>(
242 [](arith::SelectOp op) { return !hw::isHWValueType(op.getType()); });
243 }
244 MapArithTypeConverter typeConverter;
245 RewritePatternSet patterns(ctx);
246 populateArithToCombPatterns(patterns, typeConverter);
247
248 if (failed(applyPartialConversion(getOperation(), target,
249 std::move(patterns))))
250 signalPassFailure();
251 }
252};
253
254} // namespace
255
256void circt::populateArithToCombPatterns(mlir::RewritePatternSet &patterns,
257 TypeConverter &typeConverter) {
258 patterns.insert<
259 OneToOnePattern<arith::AddIOp, comb::AddOp>,
260 OneToOnePattern<arith::SubIOp, comb::SubOp>,
261 OneToOnePattern<arith::MulIOp, comb::MulOp>,
262 OneToOnePattern<arith::DivSIOp, comb::DivSOp>,
263 OneToOnePattern<arith::DivUIOp, comb::DivUOp>,
264 OneToOnePattern<arith::RemSIOp, comb::ModSOp>,
265 OneToOnePattern<arith::RemUIOp, comb::ModUOp>,
266 OneToOnePattern<arith::AndIOp, comb::AndOp>,
267 OneToOnePattern<arith::OrIOp, comb::OrOp>,
268 OneToOnePattern<arith::XOrIOp, comb::XorOp>,
269 OneToOnePattern<arith::ShLIOp, comb::ShlOp>,
270 OneToOnePattern<arith::ShRSIOp, comb::ShrSOp>,
271 OneToOnePattern<arith::ShRUIOp, comb::ShrUOp>,
272 OneToOnePattern<arith::SelectOp, comb::MuxOp>,
273 MinMaxConversionPattern<arith::MaxSIOp, comb::ICmpPredicate::sge>,
274 MinMaxConversionPattern<arith::MaxUIOp, comb::ICmpPredicate::uge>,
275 MinMaxConversionPattern<arith::MinSIOp, comb::ICmpPredicate::sle>,
276 MinMaxConversionPattern<arith::MinUIOp, comb::ICmpPredicate::ule>,
277 ExtSConversionPattern, ExtZConversionPattern, TruncateConversionPattern,
278 CompConversionPattern, ConstantConversionPattern>(typeConverter,
279 patterns.getContext());
280}
281
282std::unique_ptr<mlir::Pass>
283circt::createMapArithToCombPass(bool enableBestEffortLowering) {
284 return std::make_unique<MapArithToCombPass>(enableBestEffortLowering);
285}
false return failure()
Parse an optional keyword or string and set instance into 'result'.
return success()
create(data_type, value)
Definition hw.py:433
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::Pass > createMapArithToCombPass(bool enableBestEffortLowering=false)
void populateArithToCombPatterns(mlir::RewritePatternSet &patterns, TypeConverter &typeConverter)