Skip to content

Commit

Permalink
[AIGToComb] [circt-synth] Add a AIG to Comb conversion pass
Browse files Browse the repository at this point in the history
This adds a conversion pass from AIG dialect to Comb dialect.
AndInverterOp can be easily converted into comb.and + comb.xor
+ hw.constant.

This enables us to utilize core dialects tools for synthesis
results without any addition. Primarly use case is running LEC
on IR before and after synthesis.
  • Loading branch information
uenoku committed Oct 27, 2024
1 parent 102447e commit 8acce71
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 1 deletion.
22 changes: 22 additions & 0 deletions include/circt/Conversion/AIGToComb.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===- AIGToComb.h - AIG to Comb 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_AIGTOCOMB_H
#define CIRCT_CONVERSION_AIGTOCOMB_H

#include "circt/Support/LLVM.h"
#include <memory>

namespace circt {

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

} // namespace circt

#endif // CIRCT_CONVERSION_AIGTOCOMB_H
1 change: 1 addition & 0 deletions include/circt/Conversion/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#ifndef CIRCT_CONVERSION_PASSES_H
#define CIRCT_CONVERSION_PASSES_H

#include "circt/Conversion/AIGToComb.h"
#include "circt/Conversion/AffineToLoopSchedule.h"
#include "circt/Conversion/ArcToLLVM.h"
#include "circt/Conversion/CFToHandshake.h"
Expand Down
16 changes: 16 additions & 0 deletions include/circt/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -808,4 +808,20 @@ def ConvertCombToAIG: Pass<"convert-comb-to-aig", "hw::HWModuleOp"> {
];
}

//===----------------------------------------------------------------------===//
// ConvertAIGToComb
//===----------------------------------------------------------------------===//

def ConvertAIGToComb: Pass<"convert-aig-to-comb", "hw::HWModuleOp"> {
let summary = "Lower AIG ops to Comb ops.";
let description = [{
This pass converts AIG operations to Comb operations. This is mostly
used for verifying post-synthesis results.
}];
let dependentDialects = [
"circt::comb::CombDialect", "circt::hw::HWDialect"
];
}


#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 @@ -3,6 +3,7 @@ add_circt_public_c_api_library(CIRCTCAPIConversion

LINK_LIBS PUBLIC
CIRCTAffineToLoopSchedule
CIRCTAIGToComb
CIRCTArcToLLVM
CIRCTCalyxToFSM
CIRCTCalyxToHW
Expand Down
86 changes: 86 additions & 0 deletions lib/Conversion/AIGToComb/AIGToComb.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
//===- AIGToComb.cpp - AIG to Comb 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 AIG to Comb Conversion Pass Implementation.
//
//===----------------------------------------------------------------------===//

#include "circt/Conversion/AIGToComb.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_CONVERTAIGTOCOMB
#include "circt/Conversion/Passes.h.inc"
} // namespace circt

using namespace circt;
using namespace comb;

//===----------------------------------------------------------------------===//
// Conversion patterns
//===----------------------------------------------------------------------===//

namespace {

struct AIGAndInverterOpConversion : OpConversionPattern<aig::AndInverterOp> {
using OpConversionPattern<aig::AndInverterOp>::OpConversionPattern;
LogicalResult
matchAndRewrite(aig::AndInverterOp op, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
// Convert to comb.and + comb.xor + hw.constant
auto width = op.getResult().getType().getIntOrFloatBitWidth();
auto allOnes =
rewriter.create<hw::ConstantOp>(op.getLoc(), APInt::getAllOnes(width));
SmallVector<Value> operands;
operands.reserve(op.getNumOperands());
for (auto [input, inverted] : llvm::zip(op.getOperands(), op.getInverted()))
operands.push_back(inverted ? rewriter.createOrFold<comb::XorOp>(
op.getLoc(), input, allOnes, true)
: input);
// NOTE: Use createOrFold to avoid creating a new operation if possible.
rewriter.replaceOp(
op, rewriter.createOrFold<comb::AndOp>(op.getLoc(), operands, true));
return success();
}
};

} // namespace

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

namespace {
struct ConvertAIGToCombPass
: public impl::ConvertAIGToCombBase<ConvertAIGToCombPass> {

void runOnOperation() override;
using ConvertAIGToCombBase<ConvertAIGToCombPass>::ConvertAIGToCombBase;
};
} // namespace

static void populateAIGToCombConversionPatterns(RewritePatternSet &patterns) {
patterns.add<AIGAndInverterOpConversion>(patterns.getContext());
}

void ConvertAIGToCombPass::runOnOperation() {
ConversionTarget target(getContext());
target.addLegalDialect<comb::CombDialect, hw::HWDialect>();
target.addIllegalDialect<aig::AIGDialect>();

RewritePatternSet patterns(&getContext());
populateAIGToCombConversionPatterns(patterns);

if (failed(mlir::applyPartialConversion(getOperation(), target,
std::move(patterns))))
return signalPassFailure();
}
15 changes: 15 additions & 0 deletions lib/Conversion/AIGToComb/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
add_circt_conversion_library(CIRCTAIGToComb
AIGToComb.cpp

DEPENDS
CIRCTConversionPassIncGen

LINK_LIBS PUBLIC
CIRCTAIG
CIRCTHW
CIRCTComb
MLIRIR
MLIRPass
MLIRSupport
MLIRTransforms
)
1 change: 1 addition & 0 deletions lib/Conversion/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
add_subdirectory(AffineToLoopSchedule)
add_subdirectory(AIGToComb)
add_subdirectory(ArcToLLVM)
add_subdirectory(CalyxToFSM)
add_subdirectory(CalyxToHW)
Expand Down
12 changes: 12 additions & 0 deletions test/Conversion/AIGToComb/aig-to-comb.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: circt-opt %s --convert-aig-to-comb | FileCheck %s

// CHECK-LABEL: @test
hw.module @test(in %a: i32, in %b: i32, in %c: i32, in %d: i32, out out0: i32) {
// CHECK: %c-1_i32 = hw.constant -1 : i32
// CHECK: %[[NOT_A:.+]] = comb.xor bin %a, %c-1_i32 : i32
// CHECK: %[[NOT_C:.+]] = comb.xor bin %c, %c-1_i32 : i32
// CHECK: %[[RESULT:.+]] = comb.and bin %[[NOT_A]], %b, %[[NOT_C]], %d : i32
// CHECK: hw.output %[[RESULT]] : i32
%0 = aig.and_inv not %a, %b, not %c, %d : i32
hw.output %0 : i32
}
5 changes: 4 additions & 1 deletion test/circt-synth/basic.mlir
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// RUN: circt-synth %s | FileCheck %s
// RUN: circt-synth %s --until-before aig-lowering | FileCheck %s --check-prefix=AIG
// RUN: circt-synth %s --until-before aig-lowering --convert-to-comb | FileCheck %s --check-prefix=COMB

// AIG-LABEL: @and
// CHECK-LABEL: @and
// COMB-LABEL: @and
hw.module @and(in %a: i2, in %b: i2, in %c: i2, out and: i2) {
%0 = comb.and %a, %b, %c : i2
// AIG-NEXT: %[[AND_INV:.+]] = aig.and_inv %a, %b, %c : i2
// AIG-NEXT: hw.output %[[AND_INV]] : i2
// CHECK-DAG: %[[B_1:.+]] = comb.extract %b from 1 : (i2) -> i1
Expand All @@ -19,5 +20,7 @@ hw.module @and(in %a: i2, in %b: i2, in %c: i2, out and: i2) {
// CHECK-DAG: %[[AND_INV_3:.+]] = aig.and_inv %[[A_0]], %[[AND_INV_1]] : i1
// CHECK-DAG: %[[CONCAT:.+]] = comb.concat %[[AND_INV_2]], %[[AND_INV_3]] : i1, i1
// CHECK-NEXT: hw.output %[[CONCAT]] : i2
// COMB-NOT: aig.and_inv
%0 = comb.and %a, %b, %c : i2
hw.output %0 : i2
}
1 change: 1 addition & 0 deletions tools/circt-synth/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ add_circt_tool(circt-synth circt-synth.cpp)
target_link_libraries(circt-synth
PRIVATE
CIRCTAIG
CIRCTAIGToComb
CIRCTAIGTransforms
CIRCTComb
CIRCTCombToAIG
Expand Down
16 changes: 16 additions & 0 deletions tools/circt-synth/circt-synth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
///
//===----------------------------------------------------------------------===//

#include "circt/Conversion/AIGToComb.h"
#include "circt/Conversion/CombToAIG.h"
#include "circt/Dialect/AIG/AIGDialect.h"
#include "circt/Dialect/AIG/AIGPasses.h"
Expand All @@ -26,6 +27,7 @@
#include "mlir/Support/FileUtilities.h"
#include "mlir/Support/LogicalResult.h"
#include "mlir/Transforms/Passes.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/PrettyStackTrace.h"
Expand Down Expand Up @@ -77,6 +79,11 @@ static llvm::cl::opt<Until> runUntilAfter(
"until-after", llvm::cl::desc("Stop pipeline after a specified point"),
runUntilValues, llvm::cl::init(UntilEnd), llvm::cl::cat(mainCategory));

static cl::opt<bool>
convertToComb("convert-to-comb",
cl::desc("Convert AIG to Comb at the end of the pipeline"),
cl::init(false), cl::cat(mainCategory));

//===----------------------------------------------------------------------===//
// Main Tool Logic
//===----------------------------------------------------------------------===//
Expand All @@ -90,6 +97,15 @@ static bool untilReached(Until until) {
//===----------------------------------------------------------------------===//

static void populateSynthesisPipeline(PassManager &pm) {
// Add the AIG to Comb at the scope exit if requested.
auto addAIGToComb = llvm::make_scope_exit([&]() {
if (convertToComb) {
auto &mpm = pm.nest<hw::HWModuleOp>();
mpm.addPass(circt::createConvertAIGToComb());
mpm.addPass(createCSEPass());
}
});

auto &mpm = pm.nest<hw::HWModuleOp>();
mpm.addPass(circt::createConvertCombToAIG());
mpm.addPass(createCSEPass());
Expand Down

0 comments on commit 8acce71

Please sign in to comment.