diff --git a/integration_test/circt-synth/comb-lowering-lec.mlir b/integration_test/circt-synth/comb-lowering-lec.mlir index 3c7e047ec792..65be8dec0157 100644 --- a/integration_test/circt-synth/comb-lowering-lec.mlir +++ b/integration_test/circt-synth/comb-lowering-lec.mlir @@ -14,6 +14,13 @@ hw.module @bit_logical(in %arg0: i32, in %arg1: i32, in %arg2: i32, in %arg3: i3 hw.output %0, %1, %2, %3 : i32, i32, i32, i32 } +// RUN: circt-lec %t.mlir %s -c1=parity -c2=parity --shared-libs=%libz3 | FileCheck %s --check-prefix=COMB_PARITY +// COMB_PARITY: c1 == c2 +hw.module @parity(in %arg0: i4, out out: i1) { + %0 = comb.parity %arg0 : i4 + hw.output %0 : i1 +} + // RUN: circt-lec %t.mlir %s -c1=add -c2=add --shared-libs=%libz3 | FileCheck %s --check-prefix=COMB_ADD // COMB_ADD: c1 == c2 hw.module @add(in %arg0: i4, in %arg1: i4, in %arg2: i4, out add: i4) { diff --git a/lib/Conversion/ArcToLLVM/CMakeLists.txt b/lib/Conversion/ArcToLLVM/CMakeLists.txt index 213b31f38883..4544210ea80e 100644 --- a/lib/Conversion/ArcToLLVM/CMakeLists.txt +++ b/lib/Conversion/ArcToLLVM/CMakeLists.txt @@ -11,6 +11,7 @@ add_circt_conversion_library(CIRCTArcToLLVM CIRCTArc CIRCTComb CIRCTSeq + CIRCTCombToArith CIRCTCombToLLVM CIRCTHWToLLVM MLIRArithToLLVM diff --git a/lib/Conversion/ArcToLLVM/LowerArcToLLVM.cpp b/lib/Conversion/ArcToLLVM/LowerArcToLLVM.cpp index cf1c758e1ad1..8d8f80c17941 100644 --- a/lib/Conversion/ArcToLLVM/LowerArcToLLVM.cpp +++ b/lib/Conversion/ArcToLLVM/LowerArcToLLVM.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "circt/Conversion/ArcToLLVM.h" +#include "circt/Conversion/CombToArith.h" #include "circt/Conversion/CombToLLVM.h" #include "circt/Conversion/HWToLLVM.h" #include "circt/Dialect/Arc/ArcOps.h" @@ -259,8 +260,21 @@ struct ClockGateOpLowering : public OpConversionPattern { LogicalResult matchAndRewrite(seq::ClockGateOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const final { - rewriter.replaceOpWithNewOp(op, adaptor.getInput(), - adaptor.getEnable(), true); + rewriter.replaceOpWithNewOp(op, adaptor.getInput(), + adaptor.getEnable()); + return success(); + } +}; + +/// Lower 'seq.clock_inv x' to 'llvm.xor x true' +struct ClockInvOpLowering : public OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + LogicalResult + matchAndRewrite(seq::ClockInverterOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const final { + auto constTrue = rewriter.create(op->getLoc(), + rewriter.getI1Type(), 1); + rewriter.replaceOpWithNewOp(op, adaptor.getInput(), constTrue); return success(); } }; @@ -635,6 +649,7 @@ void LowerArcToLLVMPass::runOnOperation() { populateHWToLLVMConversionPatterns(converter, patterns, globals, constAggregateGlobalsMap); populateHWToLLVMTypeConversions(converter); + populateCombToArithConversionPatterns(converter, patterns); populateCombToLLVMConversionPatterns(converter, patterns); // Arc patterns. @@ -646,6 +661,7 @@ void LowerArcToLLVMPass::runOnOperation() { AllocStateLikeOpLowering, AllocStorageOpLowering, ClockGateOpLowering, + ClockInvOpLowering, MemoryReadOpLowering, MemoryWriteOpLowering, ModelOpLowering, diff --git a/lib/Conversion/CombToAIG/CombToAIG.cpp b/lib/Conversion/CombToAIG/CombToAIG.cpp index a54e1a01d3be..6548bfa9b949 100644 --- a/lib/Conversion/CombToAIG/CombToAIG.cpp +++ b/lib/Conversion/CombToAIG/CombToAIG.cpp @@ -437,7 +437,18 @@ struct CombICmpOpConversion : OpConversionPattern { sameSignResult); return success(); } - } +}; + +struct CombParityOpConversion : OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(ParityOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + // Parity is the XOR of all bits. + rewriter.replaceOpWithNewOp( + op, extractBits(rewriter, adaptor.getInput()), true); + return success(); } }; @@ -460,7 +471,7 @@ static void populateCombToAIGConversionPatterns(RewritePatternSet &patterns) { patterns.add< // Bitwise Logical Ops CombAndOpConversion, CombOrOpConversion, CombXorOpConversion, - CombMuxOpConversion, + CombMuxOpConversion, CombParityOpConversion, // Arithmetic Ops CombAddOpConversion, CombSubOpConversion, CombMulOpConversion, CombICmpOpConversion, diff --git a/test/Conversion/ArcToLLVM/lower-arc-to-llvm.mlir b/test/Conversion/ArcToLLVM/lower-arc-to-llvm.mlir index cacdf64a6238..7ad14ed5e0d8 100644 --- a/test/Conversion/ArcToLLVM/lower-arc-to-llvm.mlir +++ b/test/Conversion/ArcToLLVM/lower-arc-to-llvm.mlir @@ -179,12 +179,17 @@ func.func @seqClocks(%clk1: !seq.clock, %clk2: !seq.clock) -> !seq.clock { %1 = seq.from_clock %clk2 %2 = arith.xori %0, %1 : i1 %3 = seq.to_clock %2 - return %3 : !seq.clock + %4 = seq.clock_inv %3 + %5 = seq.clock_gate %4, %0 + return %5 : !seq.clock } // CHECK-LABEL: llvm.func @seqClocks // CHECK-SAME: ([[CLK1:%.+]]: i1, [[CLK2:%.+]]: i1) // CHECK: [[RES:%.+]] = llvm.xor [[CLK1]], [[CLK2]] -// CHECK: llvm.return [[RES]] : i1 +// CHECK: [[TRUE:%.+]] = llvm.mlir.constant(true) : i1 +// CHECK: [[RES1:%.+]] = llvm.xor [[RES]], [[TRUE]] : i1 +// CHECK: [[RES2:%.+]] = llvm.and [[RES1]], [[CLK1]] : i1 +// CHECK: llvm.return [[RES2]] : i1 // CHECK-LABEL: llvm.func @ReadAggregates( // CHECK-SAME: %arg0: !llvm.ptr diff --git a/test/Conversion/CombToAIG/comb-to-aig-arith.mlir b/test/Conversion/CombToAIG/comb-to-aig-arith.mlir index d97012e21f9f..2c45ed60115a 100644 --- a/test/Conversion/CombToAIG/comb-to-aig-arith.mlir +++ b/test/Conversion/CombToAIG/comb-to-aig-arith.mlir @@ -2,6 +2,18 @@ // RUN: circt-opt %s --pass-pipeline="builtin.module(hw.module(convert-comb-to-aig{additional-legal-ops=comb.xor,comb.or,comb.and,comb.mux,comb.add},cse))" | FileCheck %s --check-prefix=ALLOW_ADD +// CHECK-LABEL: @parity +hw.module @parity(in %arg0: i4, out out: i1) { + // CHECK-NEXT: %[[ext0:.+]] = comb.extract %arg0 from 0 : (i4) -> i1 + // CHECK-NEXT: %[[ext1:.+]] = comb.extract %arg0 from 1 : (i4) -> i1 + // CHECK-NEXT: %[[ext2:.+]] = comb.extract %arg0 from 2 : (i4) -> i1 + // CHECK-NEXT: %[[ext3:.+]] = comb.extract %arg0 from 3 : (i4) -> i1 + // CHECK-NEXT: %[[xor:.+]] = comb.xor bin %[[ext0]], %[[ext1]], %[[ext2]], %[[ext3]] : i1 + // CHECK-NEXT: hw.output %[[xor]] : i1 + %0 = comb.parity %arg0 : i4 + hw.output %0 : i1 +} + // CHECK-LABEL: @add hw.module @add(in %lhs: i2, in %rhs: i2, out out: i2) { // CHECK: %[[lhs0:.*]] = comb.extract %lhs from 0 : (i2) -> i1 @@ -34,11 +46,11 @@ hw.module @sub(in %lhs: i4, in %rhs: i4, out out: i4) { // ALLOW_ADD-NEXT: %[[EXT_0:.+]] = comb.extract %lhs from 0 : (i2) -> i1 // ALLOW_ADD-NEXT: %[[EXT_1:.+]] = comb.extract %lhs from 1 : (i2) -> i1 // ALLOW_ADD-NEXT: %c0_i2 = hw.constant 0 : i2 -// ALLOW_ADD-NEXT: %[[MUX_0:.+]] = comb.mux %0, %rhs, %c0_i2 : i2 -// ALLOW_ADD-NEXT: %[[MUX_1:.+]] = comb.mux %1, %rhs, %c0_i2 : i2 -// ALLOW_ADD-NEXT: %[[EXT_MUX_1:.+]] = comb.extract %3 from 0 : (i2) -> i1 +// ALLOW_ADD-NEXT: %[[MUX_0:.+]] = comb.mux %[[EXT_0]], %rhs, %c0_i2 : i2 +// ALLOW_ADD-NEXT: %[[MUX_1:.+]] = comb.mux %[[EXT_1]], %rhs, %c0_i2 : i2 +// ALLOW_ADD-NEXT: %[[EXT_MUX_1:.+]] = comb.extract %[[MUX_1]] from 0 : (i2) -> i1 // ALLOW_ADD-NEXT: %false = hw.constant false -// ALLOW_ADD-NEXT: %[[SHIFT:.+]] = comb.concat %4, %false : i1, i1 +// ALLOW_ADD-NEXT: %[[SHIFT:.+]] = comb.concat %[[EXT_MUX_1]], %false : i1, i1 // ALLOW_ADD-NEXT: %[[ADD:.+]] = comb.add bin %[[MUX_0]], %[[SHIFT]] : i2 // ALLOW_ADD-NEXT: hw.output %[[ADD]] : i2 // ALLOW_ADD-NEXT: } diff --git a/tools/arcilator/arcilator.cpp b/tools/arcilator/arcilator.cpp index 9f092e800a86..47b1918bb0fe 100644 --- a/tools/arcilator/arcilator.cpp +++ b/tools/arcilator/arcilator.cpp @@ -355,7 +355,6 @@ static void populateArcToLLVMPipeline(PassManager &pm) { // Lower the arcs and update functions to LLVM. if (untilReached(UntilLLVMLowering)) return; - pm.addPass(createConvertCombToArithPass()); pm.addPass(createLowerArcToLLVMPass()); pm.addPass(createCSEPass()); pm.addPass(arc::createArcCanonicalizerPass());