Skip to content

Commit

Permalink
[CombToAIG] Add a pattern for lowering varidaic operations
Browse files Browse the repository at this point in the history
Some variadic operations (xor, add, mul etc) cannot directly lowered
into varidic AIG operations. So this adds a pattern to pre-lower variadic
operations.
  • Loading branch information
uenoku committed Dec 13, 2024
1 parent b900c38 commit b7a0513
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 11 deletions.
6 changes: 3 additions & 3 deletions integration_test/circt-synth/comb-lowering-lec.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
// COMB_BIT_LOGICAL: c1 == c2
hw.module @bit_logical(in %arg0: i32, in %arg1: i32, in %arg2: i32, in %arg3: i32,
in %cond: i1, out out0: i32, out out1: i32, out out2: i32, out out3: i32) {
%0 = comb.or %arg0, %arg1 : i32
%1 = comb.and %arg0, %arg1 : i32
%2 = comb.xor %arg0, %arg1 : i32
%0 = comb.or %arg0, %arg1, %arg2, %arg3 : i32
%1 = comb.and %arg0, %arg1, %arg2, %arg3 : i32
%2 = comb.xor %arg0, %arg1, %arg2, %arg3 : i32
%3 = comb.mux %cond, %arg0, %arg1 : i32

hw.output %0, %1, %2, %3 : i32, i32, i32, i32
Expand Down
40 changes: 39 additions & 1 deletion lib/Conversion/CombToAIG/CombToAIG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,42 @@ struct CombXorOpConversion : OpConversionPattern<XorOp> {
}
};

template <typename OpTy>
struct CombLowerVariadicOp : OpConversionPattern<OpTy> {
using OpConversionPattern<OpTy>::OpConversionPattern;
using OpAdaptor = typename OpConversionPattern<OpTy>::OpAdaptor;
LogicalResult
matchAndRewrite(OpTy op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
auto result = lowerFullyAssociativeOp(op, op.getOperands(), rewriter);
rewriter.replaceOp(op, result);
return success();
}

static Value lowerFullyAssociativeOp(OpTy op, OperandRange operands,
ConversionPatternRewriter &rewriter) {
Value lhs, rhs;
switch (operands.size()) {
case 0:
assert(false && "cannot be called with empty operand range");
break;
case 1:
return operands[0];
case 2:
lhs = operands[0];
rhs = operands[1];
return rewriter.create<OpTy>(op.getLoc(), ValueRange{lhs, rhs}, true);
default:
auto firstHalf = operands.size() / 2;
lhs =
lowerFullyAssociativeOp(op, operands.take_front(firstHalf), rewriter);
rhs =
lowerFullyAssociativeOp(op, operands.drop_front(firstHalf), rewriter);
return rewriter.create<OpTy>(op.getLoc(), ValueRange{lhs, rhs}, true);
}
}
};

// Lower comb::MuxOp to AIG operations.
struct CombMuxOpConversion : OpConversionPattern<MuxOp> {
using OpConversionPattern<MuxOp>::OpConversionPattern;
Expand Down Expand Up @@ -150,7 +186,9 @@ static void populateCombToAIGConversionPatterns(RewritePatternSet &patterns) {
patterns.add<
// Bitwise Logical Ops
CombAndOpConversion, CombOrOpConversion, CombXorOpConversion,
CombMuxOpConversion>(patterns.getContext());
CombMuxOpConversion,
// Variadic ops that must be lowered to binary operations
CombLowerVariadicOp<XorOp>>(patterns.getContext());
}

void ConvertCombToAIGPass::runOnOperation() {
Expand Down
23 changes: 16 additions & 7 deletions test/Conversion/CombToAIG/comb-to-aig.mlir
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
// RUN: circt-opt %s --convert-comb-to-aig | FileCheck %s

// CHECK-LABEL: @test
hw.module @test(in %arg0: i32, in %arg1: i32, in %arg2: i32, in %arg3: i32, out out0: i32, out out1: i32, out out2: i32) {
hw.module @test(in %arg0: i32, in %arg1: i32, in %arg2: i32, in %arg3: i32, out out0: i32, out out1: i32) {
// CHECK-NEXT: %[[OR_TMP:.+]] = aig.and_inv not %arg0, not %arg1, not %arg2, not %arg3 : i32
// CHECK-NEXT: %[[OR:.+]] = aig.and_inv not %0 : i32
// CHECK-NEXT: %[[AND:.+]] = aig.and_inv %arg0, %arg1, %arg2, %arg3 : i32
// CHECK-NEXT: %[[XOR_NOT_AND:.+]] = aig.and_inv not %arg0, not %arg1 : i32
// CHECK-NEXT: %[[XOR_AND:.+]] = aig.and_inv %arg0, %arg1 : i32
// CHECK-NEXT: %[[XOR:.+]] = aig.and_inv not %[[XOR_NOT_AND]], not %[[XOR_AND]] : i32
// CHECK-NEXT: hw.output %[[OR]], %[[AND]], %[[XOR]] : i32, i32, i32
// CHECK-NEXT: hw.output %[[OR]], %[[AND]] : i32, i32
%0 = comb.or %arg0, %arg1, %arg2, %arg3 : i32
%1 = comb.and %arg0, %arg1, %arg2, %arg3 : i32
%2 = comb.xor %arg0, %arg1 : i32
hw.output %0, %1, %2 : i32, i32, i32
hw.output %0, %1 : i32, i32
}

// CHECK-LABEL: @xor
hw.module @xor(in %arg0: i32, in %arg1: i32, in %arg2: i32, out out0: i32) {
// CHECK-NEXT: %[[RHS_NOT_AND:.+]] = aig.and_inv not %arg1, not %arg2 : i32
// CHECK-NEXT: %[[RHS_AND:.+]] = aig.and_inv %arg1, %arg2 : i32
// CHECK-NEXT: %[[RHS_XOR:.+]] = aig.and_inv not %[[RHS_NOT_AND]], not %[[RHS_AND]] : i32
// CHECK-NEXT: %[[NOT_AND:.+]] = aig.and_inv not %arg0, not %[[RHS_XOR]] : i32
// CHECK-NEXT: %[[AND:.+]] = aig.and_inv %arg0, %[[RHS_XOR]] : i32
// CHECK-NEXT: %[[RESULT:.+]] = aig.and_inv not %[[NOT_AND]], not %[[AND]] : i32
// CHECK-NEXT: hw.output %[[RESULT]]
%0 = comb.xor %arg0, %arg1, %arg2 : i32
hw.output %0 : i32
}

// CHECK-LABEL: @pass
Expand Down

0 comments on commit b7a0513

Please sign in to comment.