Skip to content

Commit

Permalink
[CombToAIG] Add CombToAIG conversion pass (#7740)
Browse files Browse the repository at this point in the history
This adds a conversion pass from Comb to AIG. Currently conversion patterns for variadic `comb.or/and` 
and binary xor are supported. There will be a follow up to implement conversion patterns for arithmetic ops.
  • Loading branch information
uenoku authored Oct 26, 2024
1 parent 4f0edf4 commit 5b8b18e
Show file tree
Hide file tree
Showing 8 changed files with 194 additions and 0 deletions.
22 changes: 22 additions & 0 deletions include/circt/Conversion/CombToAIG.h
Original file line number Diff line number Diff line change
@@ -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 <memory>

namespace circt {

#define GEN_PASS_DECL_CONVERTCOMBTOAIG
#include "circt/Conversion/Passes.h.inc"

} // namespace circt

#endif // CIRCT_CONVERSION_COMBTOAIG_H
1 change: 1 addition & 0 deletions include/circt/Conversion/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
12 changes: 12 additions & 0 deletions include/circt/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions lib/CAPI/Conversion/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ add_circt_public_c_api_library(CIRCTCAPIConversion
CIRCTCalyxToFSM
CIRCTCalyxToHW
CIRCTCalyxNative
CIRCTCombToAIG
CIRCTCombToArith
CIRCTCombToLLVM
CIRCTCombToSMT
Expand Down
1 change: 1 addition & 0 deletions lib/Conversion/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
18 changes: 18 additions & 0 deletions lib/Conversion/CombToAIG/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
123 changes: 123 additions & 0 deletions lib/Conversion/CombToAIG/CombToAIG.cpp
Original file line number Diff line number Diff line change
@@ -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<AndOp> {
using OpConversionPattern<AndOp>::OpConversionPattern;

LogicalResult
matchAndRewrite(AndOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
SmallVector<bool> nonInverts(adaptor.getInputs().size(), false);
rewriter.replaceOpWithNewOp<aig::AndInverterOp>(op, adaptor.getInputs(),
nonInverts);
return success();
}
};

/// Lower a comb::OrOp operation to aig::AndInverterOp with invert flags
struct CombOrOpConversion : OpConversionPattern<OrOp> {
using OpConversionPattern<OrOp>::OpConversionPattern;

LogicalResult
matchAndRewrite(OrOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
// Implement Or using And and invert flags: a | b = ~(~a & ~b)
SmallVector<bool> allInverts(adaptor.getInputs().size(), true);
auto andOp = rewriter.create<aig::AndInverterOp>(
op.getLoc(), adaptor.getInputs(), allInverts);
rewriter.replaceOpWithNewOp<aig::AndInverterOp>(op, andOp,
/*invert=*/true);
return success();
}
};

/// Lower a comb::XorOp operation to AIG operations
struct CombXorOpConversion : OpConversionPattern<XorOp> {
using OpConversionPattern<XorOp>::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<bool> allInverts(inputs.size(), true);
SmallVector<bool> allNotInverts(inputs.size(), false);

auto notAAndNotB =
rewriter.create<aig::AndInverterOp>(op.getLoc(), inputs, allInverts);
auto aAndB =
rewriter.create<aig::AndInverterOp>(op.getLoc(), inputs, allNotInverts);

rewriter.replaceOpWithNewOp<aig::AndInverterOp>(op, notAAndNotB, aAndB,
/*lhs_invert=*/true,
/*rhs_invert=*/true);
return success();
}
};

} // namespace

//===----------------------------------------------------------------------===//
// Convert Comb to AIG pass
//===----------------------------------------------------------------------===//

namespace {
struct ConvertCombToAIGPass
: public impl::ConvertCombToAIGBase<ConvertCombToAIGPass> {
void runOnOperation() override;
};
} // namespace

static void populateCombToAIGConversionPatterns(RewritePatternSet &patterns) {
patterns.add<CombAndOpConversion, CombOrOpConversion, CombXorOpConversion>(
patterns.getContext());
}

void ConvertCombToAIGPass::runOnOperation() {
ConversionTarget target(getContext());
target.addIllegalDialect<comb::CombDialect>();
target.addLegalDialect<aig::AIGDialect>();

RewritePatternSet patterns(&getContext());
populateCombToAIGConversionPatterns(patterns);

if (failed(mlir::applyPartialConversion(getOperation(), target,
std::move(patterns))))
return signalPassFailure();
}
16 changes: 16 additions & 0 deletions test/Conversion/CombToAIG/comb-to-aig.mlir
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 5b8b18e

Please sign in to comment.