Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AIGToComb] [circt-synth] Add a AIG to Comb conversion pass #7742

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading