Skip to content

Commit 187f4e8

Browse files
authored
[CombToDatapath] Lower comb::SubOp (#9053)
Adds support for lowering comb::SubOp in the CombToDatapath conversion pass by refactoring the SubOp-to-AddOp conversion into a shared utility function that can be reused across multiple conversion passes. This commit extracts the subtraction lowering logic from CombToSynth into a dialect-agnostic utility function `comb::convertSubToAdd` that transforms `sub(lhs, rhs)` into `add(lhs, ~rhs, 1)` using two's complement representation. AIG logic depth improved 29 -> 24 for i128 subtraction
1 parent 81ff229 commit 187f4e8

File tree

6 files changed

+40
-22
lines changed

6 files changed

+40
-22
lines changed

include/circt/Dialect/Comb/CombOps.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ Value createDynamicInject(OpBuilder &builder, Location loc, Value value,
8686
Value createInject(OpBuilder &builder, Location loc, Value value,
8787
unsigned offset, Value replacement);
8888

89+
/// Replace a subtraction with an addition of the two's complement.
90+
LogicalResult convertSubToAdd(comb::SubOp subOp,
91+
mlir::PatternRewriter &rewriter);
92+
8993
/// Enum for mux chain folding styles.
9094
enum MuxChainWithComparisonFoldingStyle { None, BalancedMuxTree, ArrayGet };
9195
/// Mux chain folding that converts chains of muxes with index

lib/Conversion/CombToDatapath/CombToDatapath.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ struct ConvertCombToDatapathPass
9292
static void
9393
populateCombToDatapathConversionPatterns(RewritePatternSet &patterns) {
9494
patterns.add<CombAddOpConversion, CombMulOpConversion>(patterns.getContext());
95+
patterns.add(comb::convertSubToAdd);
9596
}
9697

9798
void ConvertCombToDatapathPass::runOnOperation() {
@@ -106,6 +107,7 @@ void ConvertCombToDatapathPass::runOnOperation() {
106107
// TODO: determine lowering of multi-input multipliers
107108
target.addDynamicallyLegalOp<comb::MulOp>(
108109
[](comb::MulOp op) { return op.getNumOperands() > 2; });
110+
target.addIllegalOp<comb::SubOp>();
109111

110112
RewritePatternSet patterns(&getContext());
111113
populateCombToDatapathConversionPatterns(patterns);

lib/Conversion/CombToSynth/CombToSynth.cpp

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -855,25 +855,6 @@ struct CombAddOpConversion : OpConversionPattern<AddOp> {
855855
}
856856
};
857857

858-
struct CombSubOpConversion : OpConversionPattern<SubOp> {
859-
using OpConversionPattern<SubOp>::OpConversionPattern;
860-
LogicalResult
861-
matchAndRewrite(SubOp op, OpAdaptor adaptor,
862-
ConversionPatternRewriter &rewriter) const override {
863-
auto lhs = op.getLhs();
864-
auto rhs = op.getRhs();
865-
// Since `-rhs = ~rhs + 1` holds, rewrite `sub(lhs, rhs)` to:
866-
// sub(lhs, rhs) => add(lhs, -rhs) => add(lhs, add(~rhs, 1))
867-
// => add(lhs, ~rhs, 1)
868-
auto notRhs = synth::aig::AndInverterOp::create(rewriter, op.getLoc(), rhs,
869-
/*invert=*/true);
870-
auto one = hw::ConstantOp::create(rewriter, op.getLoc(), op.getType(), 1);
871-
replaceOpWithNewOpAndCopyNamehint<comb::AddOp>(
872-
rewriter, op, ValueRange{lhs, notRhs, one}, true);
873-
return success();
874-
}
875-
};
876-
877858
struct CombMulOpConversion : OpConversionPattern<MulOp> {
878859
using OpConversionPattern<MulOp>::OpConversionPattern;
879860
using OpAdaptor = typename OpConversionPattern<MulOp>::OpAdaptor;
@@ -1376,13 +1357,15 @@ populateCombToAIGConversionPatterns(RewritePatternSet &patterns,
13761357
CombAndOpConversion, CombXorOpConversion, CombMuxOpConversion,
13771358
CombParityOpConversion,
13781359
// Arithmetic Ops
1379-
CombSubOpConversion, CombMulOpConversion, CombICmpOpConversion,
1360+
CombMulOpConversion, CombICmpOpConversion,
13801361
// Shift Ops
13811362
CombShlOpConversion, CombShrUOpConversion, CombShrSOpConversion,
13821363
// Variadic ops that must be lowered to binary operations
13831364
CombLowerVariadicOp<XorOp>, CombLowerVariadicOp<AddOp>,
13841365
CombLowerVariadicOp<MulOp>>(patterns.getContext());
13851366

1367+
patterns.add(comb::convertSubToAdd);
1368+
13861369
if (lowerToMIG) {
13871370
patterns.add<CombOrToMIGConversion, CombLowerVariadicOp<OrOp>,
13881371
AndInverterToMIGConversion,

lib/Dialect/Comb/CombOps.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "circt/Dialect/Comb/CombOps.h"
1414
#include "circt/Dialect/HW/HWOps.h"
15+
#include "circt/Support/Naming.h"
1516
#include "mlir/IR/Builders.h"
1617
#include "mlir/IR/ImplicitLocOpBuilder.h"
1718
#include "mlir/IR/Matchers.h"
@@ -217,6 +218,22 @@ Value comb::createInject(OpBuilder &builder, Location loc, Value value,
217218
return builder.createOrFold<comb::ConcatOp>(loc, fragments);
218219
}
219220

221+
llvm::LogicalResult comb::convertSubToAdd(comb::SubOp subOp,
222+
mlir::PatternRewriter &rewriter) {
223+
auto lhs = subOp.getLhs();
224+
auto rhs = subOp.getRhs();
225+
// Since `-rhs = ~rhs + 1` holds, rewrite `sub(lhs, rhs)` to:
226+
// sub(lhs, rhs) => add(lhs, -rhs) => add(lhs, add(~rhs, 1))
227+
// => add(lhs, ~rhs, 1)
228+
auto notRhs =
229+
comb::createOrFoldNot(subOp.getLoc(), rhs, rewriter, subOp.getTwoState());
230+
auto one =
231+
hw::ConstantOp::create(rewriter, subOp.getLoc(), subOp.getType(), 1);
232+
replaceOpWithNewOpAndCopyNamehint<comb::AddOp>(
233+
rewriter, subOp, ValueRange{lhs, notRhs, one}, subOp.getTwoState());
234+
return success();
235+
}
236+
220237
//===----------------------------------------------------------------------===//
221238
// ICmpOp
222239
//===----------------------------------------------------------------------===//

test/Conversion/CombToDatapath/comb-to-datapath.mlir

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,15 @@ hw.module @zero_width(in %arg0: i0, in %arg1: i0, in %arg2: i0) {
2626
// CHECK-NEXT: hw.constant 0 : i0
2727
%0 = comb.add %arg0, %arg1, %arg2 : i0
2828
}
29+
// CHECK-LABEL: @sub
30+
hw.module @sub(in %arg0: i4, in %arg1: i4, out out: i4) {
31+
%0 = comb.sub %arg0, %arg1 : i4
32+
// CHECK-NEXT: %[[C_NEG1:.+]] = hw.constant -1 : i4
33+
// CHECK-NEXT: %[[XOR:.+]] = comb.xor %arg1, %[[C_NEG1]] : i4
34+
// CHECK-NEXT: %[[C1:.+]] = hw.constant 1 : i4
35+
// CHECK-NEXT: %[[COMP:.+]]:2 = datapath.compress %arg0, %[[XOR]], %[[C1]] : i4 [3 -> 2]
36+
// CHECK-NEXT: %[[ADD:.+]] = comb.add bin %[[COMP]]#0, %[[COMP]]#1 : i4
37+
// CHECK-NEXT: hw.output %[[ADD]] : i4
38+
hw.output %0 : i4
39+
}
2940

test/Conversion/CombToSynth/comb-to-aig-arith.mlir

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,10 @@ hw.module @add_64(in %lhs: i64, in %rhs: i64, out out: i64) {
146146

147147
// CHECK-LABEL: @sub
148148
// ALLOW_ADD-LABEL: @sub
149-
// ALLOW_ADD-NEXT: %[[NOT_RHS:.+]] = synth.aig.and_inv not %rhs
149+
// ALLOW_ADD-NEXT: %[[C_NEG1:.+]] = hw.constant -1 : i4
150+
// ALLOW_ADD-NEXT: %[[NOT_RHS:.+]] = comb.xor %rhs, %[[C_NEG1]] : i4
150151
// ALLOW_ADD-NEXT: %[[CONST:.+]] = hw.constant 1 : i4
151-
// ALLOW_ADD-NEXT: %[[ADD:.+]] = comb.add bin %lhs, %[[NOT_RHS]], %[[CONST]] {sv.namehint = "sub"}
152+
// ALLOW_ADD-NEXT: %[[ADD:.+]] = comb.add %lhs, %[[NOT_RHS]], %[[CONST]] {sv.namehint = "sub"}
152153
// ALLOW_ADD-NEXT: hw.output %[[ADD]]
153154
hw.module @sub(in %lhs: i4, in %rhs: i4, out out: i4) {
154155
%0 = comb.sub %lhs, %rhs {sv.namehint = "sub"} : i4

0 commit comments

Comments
 (0)