diff --git a/include/circt/Conversion/CombToAIG.h b/include/circt/Conversion/CombToAIG.h new file mode 100644 index 000000000000..1c642130fab8 --- /dev/null +++ b/include/circt/Conversion/CombToAIG.h @@ -0,0 +1,22 @@ +//===- CombToAIG.h - Comb to AIG dialect conversion -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef CIRCT_CONVERSION_COMBTOAIG_H +#define CIRCT_CONVERSION_COMBTOAIG_H + +#include "circt/Support/LLVM.h" +#include + +namespace circt { + +#define GEN_PASS_DECL_CONVERTCOMBTOAIG +#include "circt/Conversion/Passes.h.inc" + +} // namespace circt + +#endif // CIRCT_CONVERSION_COMBTOAIG_H diff --git a/include/circt/Conversion/Passes.h b/include/circt/Conversion/Passes.h index 9d6b2d2aacc2..887da277f8aa 100644 --- a/include/circt/Conversion/Passes.h +++ b/include/circt/Conversion/Passes.h @@ -19,6 +19,7 @@ #include "circt/Conversion/CalyxNative.h" #include "circt/Conversion/CalyxToFSM.h" #include "circt/Conversion/CalyxToHW.h" +#include "circt/Conversion/CombToAIG.h" #include "circt/Conversion/CombToArith.h" #include "circt/Conversion/CombToSMT.h" #include "circt/Conversion/ConvertToArcs.h" diff --git a/include/circt/Conversion/Passes.td b/include/circt/Conversion/Passes.td index dd55af253b80..71fee748a6b2 100644 --- a/include/circt/Conversion/Passes.td +++ b/include/circt/Conversion/Passes.td @@ -796,4 +796,16 @@ def LowerSimToSV: Pass<"lower-sim-to-sv", "mlir::ModuleOp"> { ]; } +//===----------------------------------------------------------------------===// +// ConvertCombToAIG +//===----------------------------------------------------------------------===// + +def ConvertCombToAIG: Pass<"convert-comb-to-aig", "hw::HWModuleOp"> { + let summary = "Lower Comb ops to AIG ops."; + let dependentDialects = [ + "circt::comb::CombDialect", + "circt::aig::AIGDialect", + ]; +} + #endif // CIRCT_CONVERSION_PASSES_TD diff --git a/lib/CAPI/Conversion/CMakeLists.txt b/lib/CAPI/Conversion/CMakeLists.txt index 385ede3bef18..8f6176f027a6 100644 --- a/lib/CAPI/Conversion/CMakeLists.txt +++ b/lib/CAPI/Conversion/CMakeLists.txt @@ -7,6 +7,7 @@ add_circt_public_c_api_library(CIRCTCAPIConversion CIRCTCalyxToFSM CIRCTCalyxToHW CIRCTCalyxNative + CIRCTCombToAIG CIRCTCombToArith CIRCTCombToLLVM CIRCTCombToSMT diff --git a/lib/Conversion/CMakeLists.txt b/lib/Conversion/CMakeLists.txt index 04bc5bfa9d71..27bff3679ec4 100644 --- a/lib/Conversion/CMakeLists.txt +++ b/lib/Conversion/CMakeLists.txt @@ -2,6 +2,7 @@ add_subdirectory(AffineToLoopSchedule) add_subdirectory(ArcToLLVM) add_subdirectory(CalyxToFSM) add_subdirectory(CalyxToHW) +add_subdirectory(CombToAIG) add_subdirectory(CombToArith) add_subdirectory(CombToLLVM) add_subdirectory(CombToSMT) diff --git a/lib/Conversion/CombToAIG/CMakeLists.txt b/lib/Conversion/CombToAIG/CMakeLists.txt new file mode 100644 index 000000000000..5add2ed5198a --- /dev/null +++ b/lib/Conversion/CombToAIG/CMakeLists.txt @@ -0,0 +1,18 @@ +add_circt_conversion_library(CIRCTCombToAIG + CombToAIG.cpp + + ADDITIONAL_HEADER_DIRS + ${CIRCT_MAIN_INCLUDE_DIR}/circt/Conversion/CombToAIG + + DEPENDS + CIRCTConversionPassIncGen + + LINK_LIBS PUBLIC + CIRCTHW + CIRCTComb + CIRCTAIG + MLIRIR + MLIRPass + MLIRSupport + MLIRTransforms +) diff --git a/lib/Conversion/CombToAIG/CombToAIG.cpp b/lib/Conversion/CombToAIG/CombToAIG.cpp new file mode 100644 index 000000000000..0c0c82af05b5 --- /dev/null +++ b/lib/Conversion/CombToAIG/CombToAIG.cpp @@ -0,0 +1,123 @@ +//===- CombToAIG.cpp - Comb to AIG Conversion Pass --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the main Comb to AIG Conversion Pass Implementation. +// +//===----------------------------------------------------------------------===// + +#include "circt/Conversion/CombToAIG.h" +#include "circt/Dialect/AIG/AIGOps.h" +#include "circt/Dialect/Comb/CombOps.h" +#include "circt/Dialect/HW/HWOps.h" +#include "mlir/Pass/Pass.h" +#include "mlir/Transforms/DialectConversion.h" + +namespace circt { +#define GEN_PASS_DEF_CONVERTCOMBTOAIG +#include "circt/Conversion/Passes.h.inc" +} // namespace circt + +using namespace circt; +using namespace comb; + +//===----------------------------------------------------------------------===// +// Conversion patterns +//===----------------------------------------------------------------------===// + +namespace { + +/// Lower a comb::AndOp operation to aig::AndInverterOp +struct CombAndOpConversion : OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(AndOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + SmallVector nonInverts(adaptor.getInputs().size(), false); + rewriter.replaceOpWithNewOp(op, adaptor.getInputs(), + nonInverts); + return success(); + } +}; + +/// Lower a comb::OrOp operation to aig::AndInverterOp with invert flags +struct CombOrOpConversion : OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(OrOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + // Implement Or using And and invert flags: a | b = ~(~a & ~b) + SmallVector allInverts(adaptor.getInputs().size(), true); + auto andOp = rewriter.create( + op.getLoc(), adaptor.getInputs(), allInverts); + rewriter.replaceOpWithNewOp(op, andOp, + /*invert=*/true); + return success(); + } +}; + +/// Lower a comb::XorOp operation to AIG operations +struct CombXorOpConversion : OpConversionPattern { + using OpConversionPattern::OpConversionPattern; + + LogicalResult + matchAndRewrite(XorOp op, OpAdaptor adaptor, + ConversionPatternRewriter &rewriter) const override { + if (op.getNumOperands() != 2) + return failure(); + // Xor using And with invert flags: a ^ b = (a | b) & (~a | ~b) + + // (a | b) = ~(~a & ~b) + // (~a | ~b) = ~(a & b) + auto inputs = adaptor.getInputs(); + SmallVector allInverts(inputs.size(), true); + SmallVector allNotInverts(inputs.size(), false); + + auto notAAndNotB = + rewriter.create(op.getLoc(), inputs, allInverts); + auto aAndB = + rewriter.create(op.getLoc(), inputs, allNotInverts); + + rewriter.replaceOpWithNewOp(op, notAAndNotB, aAndB, + /*lhs_invert=*/true, + /*rhs_invert=*/true); + return success(); + } +}; + +} // namespace + +//===----------------------------------------------------------------------===// +// Convert Comb to AIG pass +//===----------------------------------------------------------------------===// + +namespace { +struct ConvertCombToAIGPass + : public impl::ConvertCombToAIGBase { + void runOnOperation() override; +}; +} // namespace + +static void populateCombToAIGConversionPatterns(RewritePatternSet &patterns) { + patterns.add( + patterns.getContext()); +} + +void ConvertCombToAIGPass::runOnOperation() { + ConversionTarget target(getContext()); + target.addIllegalDialect(); + target.addLegalDialect(); + + RewritePatternSet patterns(&getContext()); + populateCombToAIGConversionPatterns(patterns); + + if (failed(mlir::applyPartialConversion(getOperation(), target, + std::move(patterns)))) + return signalPassFailure(); +} diff --git a/test/Conversion/CombToAIG/comb-to-aig.mlir b/test/Conversion/CombToAIG/comb-to-aig.mlir new file mode 100644 index 000000000000..550bae1569b0 --- /dev/null +++ b/test/Conversion/CombToAIG/comb-to-aig.mlir @@ -0,0 +1,16 @@ +// 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) { + // 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 + %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 +}