12#include "mlir/Dialect/Arith/IR/Arith.h"
13#include "mlir/Pass/Pass.h"
14#include "mlir/Transforms/DialectConversion.h"
17#define GEN_PASS_DEF_CONVERTCOMBTOARITH
18#include "circt/Conversion/Passes.h.inc"
34 using OpConversionPattern<ReplicateOp>::OpConversionPattern;
37 matchAndRewrite(ReplicateOp op, OpAdaptor adaptor,
38 ConversionPatternRewriter &rewriter)
const override {
40 Type inputType = op.getInput().getType();
41 if (isa<IntegerType>(inputType) && inputType.getIntOrFloatBitWidth() == 1) {
42 Type outType = rewriter.getIntegerType(op.getMultiple());
43 rewriter.replaceOpWithNewOp<ExtSIOp>(op, outType, adaptor.getInput());
47 SmallVector<Value> inputs(op.getMultiple(), adaptor.getInput());
48 rewriter.replaceOpWithNewOp<ConcatOp>(op, inputs);
55 using OpConversionPattern<hw::ConstantOp>::OpConversionPattern;
58 matchAndRewrite(hw::ConstantOp op, OpAdaptor adaptor,
59 ConversionPatternRewriter &rewriter)
const override {
61 rewriter.replaceOpWithNewOp<arith::ConstantOp>(op, adaptor.getValueAttr());
68 using OpConversionPattern<ICmpOp>::OpConversionPattern;
71 matchAndRewrite(ICmpOp op, OpAdaptor adaptor,
72 ConversionPatternRewriter &rewriter)
const override {
75 switch (adaptor.getPredicate()) {
76 case ICmpPredicate::cne:
77 case ICmpPredicate::wne:
78 case ICmpPredicate::ne:
79 pred = CmpIPredicate::ne;
81 case ICmpPredicate::ceq:
82 case ICmpPredicate::weq:
83 case ICmpPredicate::eq:
84 pred = CmpIPredicate::eq;
86 case ICmpPredicate::sge:
87 pred = CmpIPredicate::sge;
89 case ICmpPredicate::sgt:
90 pred = CmpIPredicate::sgt;
92 case ICmpPredicate::sle:
93 pred = CmpIPredicate::sle;
95 case ICmpPredicate::slt:
96 pred = CmpIPredicate::slt;
98 case ICmpPredicate::uge:
99 pred = CmpIPredicate::uge;
101 case ICmpPredicate::ugt:
102 pred = CmpIPredicate::ugt;
104 case ICmpPredicate::ule:
105 pred = CmpIPredicate::ule;
107 case ICmpPredicate::ult:
108 pred = CmpIPredicate::ult;
112 rewriter.replaceOpWithNewOp<CmpIOp>(op, pred, adaptor.getLhs(),
120 using OpConversionPattern<ExtractOp>::OpConversionPattern;
123 matchAndRewrite(ExtractOp op, OpAdaptor adaptor,
124 ConversionPatternRewriter &rewriter)
const override {
126 Value lowBit = arith::ConstantOp::create(
127 rewriter, op.getLoc(),
128 IntegerAttr::get(adaptor.getInput().getType(), adaptor.getLowBit()));
130 ShRUIOp::create(rewriter, op.getLoc(), adaptor.getInput(), lowBit);
131 rewriter.replaceOpWithNewOp<TruncIOp>(op, op.getResult().getType(),
139 using OpConversionPattern<ConcatOp>::OpConversionPattern;
142 matchAndRewrite(ConcatOp op, OpAdaptor adaptor,
143 ConversionPatternRewriter &rewriter)
const override {
144 Type type = op.getResult().getType();
145 Location loc = op.getLoc();
149 if (op.getNumOperands() == 1) {
150 rewriter.replaceOp(op, adaptor.getOperands().back());
158 rewriter.createOrFold<ExtUIOp>(loc, type, adaptor.getOperands().back());
162 unsigned offset = type.getIntOrFloatBitWidth();
163 for (
auto operand : adaptor.getOperands().drop_back()) {
164 offset -= operand.getType().getIntOrFloatBitWidth();
165 auto offsetConst = arith::ConstantOp::create(
166 rewriter, loc, IntegerAttr::get(type, offset));
167 auto extended = rewriter.createOrFold<ExtUIOp>(loc, type, operand);
168 auto shifted = rewriter.createOrFold<ShLIOp>(loc, extended, offsetConst);
169 aggregate = rewriter.createOrFold<OrIOp>(loc, aggregate, shifted);
172 rewriter.replaceOp(op, aggregate);
178template <
typename SourceOp,
typename TargetOp>
180 using OpConversionPattern<SourceOp>::OpConversionPattern;
181 using OpAdaptor =
typename SourceOp::Adaptor;
184 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
185 ConversionPatternRewriter &rewriter)
const override {
187 typename TargetOp::Properties properties{};
188 TargetOp::populateDefaultProperties(
189 OperationName(TargetOp::getOperationName(), rewriter.getContext()),
191 rewriter.replaceOpWithNewOp<TargetOp>(op,
192 TypeRange{op.getResult().getType()},
193 adaptor.getOperands(), properties);
200template <
typename SourceOp,
typename TargetOp>
202 using OpConversionPattern<SourceOp>::OpConversionPattern;
203 using OpAdaptor =
typename SourceOp::Adaptor;
206 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
207 ConversionPatternRewriter &rewriter)
const override {
212 Location loc = op.getLoc();
213 Value zero = arith::ConstantOp::create(
214 rewriter, loc, rewriter.getIntegerAttr(adaptor.getRhs().getType(), 0));
215 Value one = arith::ConstantOp::create(
216 rewriter, loc, rewriter.getIntegerAttr(adaptor.getRhs().getType(), 1));
217 Value isZero = arith::CmpIOp::create(rewriter, loc, CmpIPredicate::eq,
218 adaptor.getRhs(), zero);
220 arith::SelectOp::create(rewriter, loc, isZero, one, adaptor.getRhs());
221 rewriter.replaceOpWithNewOp<TargetOp>(op, adaptor.getLhs(), divisor);
228template <
typename SourceOp,
typename TargetOp,
bool IsRem>
231 using OpConversionPattern<SourceOp>::OpConversionPattern;
232 using OpAdaptor =
typename SourceOp::Adaptor;
235 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
236 ConversionPatternRewriter &rewriter)
const override {
237 Value dividend = adaptor.getLhs();
238 Value divisor = adaptor.getRhs();
239 Type ty = op.getType();
252 ImplicitLocOpBuilder b(op.getLoc(), rewriter);
253 auto eq = [&](Value lhs, Value rhs) {
254 return arith::CmpIOp::create(b, CmpIPredicate::eq, lhs, rhs);
256 auto and_ = [&](Value lhs, Value rhs) {
257 return arith::AndIOp::create(b, lhs, rhs);
259 auto or_ = [&](Value lhs, Value rhs) {
260 return arith::OrIOp::create(b, lhs, rhs);
263 int bitwidth = ty.getIntOrFloatBitWidth();
264 Value zero = arith::ConstantOp::create(b, rewriter.getIntegerAttr(ty, 0));
265 Value one = arith::ConstantOp::create(b, rewriter.getIntegerAttr(ty, 1));
266 Value int_min = arith::ConstantOp::create(
267 b, rewriter.getIntegerAttr(ty, APInt::getSignedMinValue(bitwidth)));
268 Value minus_one = arith::ConstantOp::create(
269 b, rewriter.getIntegerAttr(ty, APInt::getAllOnes(bitwidth)));
271 Value isZero = eq(divisor, zero);
272 Value isOverflow = and_(eq(dividend, int_min), eq(divisor, minus_one));
273 Value pred = or_(isZero, isOverflow);
274 Value safeDivisor = arith::SelectOp::create(b, pred, one, divisor);
275 auto newOp = TargetOp::create(b, dividend, safeDivisor);
277 Value resultIfOverflow = IsRem ? zero : int_min;
279 arith::SelectOp::create(b, isOverflow, resultIfOverflow, newOp);
280 rewriter.replaceOp(op, result);
286template <
typename SourceOp,
typename TargetOp>
288 using OpConversionPattern<SourceOp>::OpConversionPattern;
289 using OpAdaptor =
typename SourceOp::Adaptor;
292 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
293 ConversionPatternRewriter &rewriter)
const override {
296 ValueRange operands = adaptor.getOperands();
297 Value runner = operands[0];
299 llvm::make_range(operands.begin() + 1, operands.end())) {
300 runner = TargetOp::create(rewriter, op.getLoc(), runner, operand);
302 rewriter.replaceOp(op, runner);
314template <
typename SourceOp,
typename TargetOp>
316 using OpConversionPattern<SourceOp>::OpConversionPattern;
317 using OpAdaptor =
typename SourceOp::Adaptor;
320 matchAndRewrite(SourceOp op, OpAdaptor adaptor,
321 ConversionPatternRewriter &rewriter)
const override {
322 unsigned shifteeWidth =
323 hw::type_cast<IntegerType>(adaptor.getLhs().getType())
324 .getIntOrFloatBitWidth();
325 auto zeroConstOp = arith::ConstantOp::create(
326 rewriter, op.getLoc(), IntegerAttr::get(adaptor.getLhs().getType(), 0));
327 auto maxShamtConstOp = arith::ConstantOp::create(
328 rewriter, op.getLoc(),
329 IntegerAttr::get(adaptor.getLhs().getType(), shifteeWidth));
330 auto shiftOp = rewriter.createOrFold<TargetOp>(
331 op.getLoc(), adaptor.getLhs(), adaptor.getRhs());
332 auto isAllZeroOp = rewriter.createOrFold<CmpIOp>(
333 op.getLoc(), CmpIPredicate::uge, adaptor.getRhs(),
334 maxShamtConstOp.getResult());
335 rewriter.replaceOpWithNewOp<SelectOp>(op, isAllZeroOp, zeroConstOp,
343 using OpConversionPattern<ShrSOp>::OpConversionPattern;
346 matchAndRewrite(ShrSOp op, OpAdaptor adaptor,
347 ConversionPatternRewriter &rewriter)
const override {
348 unsigned shifteeWidth =
349 hw::type_cast<IntegerType>(adaptor.getLhs().getType())
350 .getIntOrFloatBitWidth();
352 auto maxShamtMinusOneConstOp = arith::ConstantOp::create(
353 rewriter, op.getLoc(),
354 IntegerAttr::get(adaptor.getLhs().getType(), shifteeWidth - 1));
355 auto shamtOp = rewriter.createOrFold<MinUIOp>(op.getLoc(), adaptor.getRhs(),
356 maxShamtMinusOneConstOp);
357 rewriter.replaceOpWithNewOp<ShRSIOp>(op, adaptor.getLhs(), shamtOp);
369struct ConvertCombToArithPass
370 :
public circt::impl::ConvertCombToArithBase<ConvertCombToArithPass> {
371 void runOnOperation()
override;
376 TypeConverter &converter, mlir::RewritePatternSet &
patterns) {
378 CombReplicateOpConversion, HWConstantOpConversion, IcmpOpConversion,
379 ExtractOpConversion, ConcatOpConversion, ShrSOpConversion,
380 LogicalShiftConversion<ShlOp, ShLIOp>,
381 LogicalShiftConversion<ShrUOp, ShRUIOp>,
382 BinaryOpConversion<SubOp, SubIOp>,
383 DivSOpConversion<
DivSOp, DivSIOp,
false>,
384 DivUOpConversion<DivUOp, DivUIOp>,
385 DivSOpConversion<
ModSOp, RemSIOp,
true>,
386 DivUOpConversion<ModUOp, RemUIOp>, BinaryOpConversion<MuxOp, SelectOp>,
387 VariadicOpConversion<AddOp, AddIOp>, VariadicOpConversion<MulOp, MulIOp>,
388 VariadicOpConversion<AndOp, AndIOp>, VariadicOpConversion<OrOp, OrIOp>,
389 VariadicOpConversion<XorOp, XOrIOp>>(converter,
patterns.getContext());
392void ConvertCombToArithPass::runOnOperation() {
393 ConversionTarget target(getContext());
394 target.addIllegalDialect<comb::CombDialect>();
395 target.addIllegalOp<hw::ConstantOp>();
396 target.addLegalDialect<ArithDialect>();
400 target.addLegalOp<comb::ParityOp>();
402 target.addLegalOp<comb::ReverseOp>();
407 target.markUnknownOpDynamicallyLegal([](Operation *) {
return true; });
408 RewritePatternSet patterns(&getContext());
409 TypeConverter converter;
410 converter.addConversion([](Type type) {
return type; });
414 ConversionConfig config;
415 config.allowPatternRollback =
false;
416 if (failed(mlir::applyPartialConversion(getOperation(), target,
417 std::move(patterns), config)))
422 return std::make_unique<ConvertCombToArithPass>();
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
void populateCombToArithConversionPatterns(TypeConverter &converter, RewritePatternSet &patterns)
std::unique_ptr< Pass > createConvertCombToArithPass()