[CombToAIG] Add CombToAIG conversion pass (#7740)

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.
This commit is contained in:
Hideto Ueno 2024-10-26 20:57:00 +09:00 committed by GitHub
parent 4f0edf4cfe
commit 5b8b18e9e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 194 additions and 0 deletions

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -7,6 +7,7 @@ add_circt_public_c_api_library(CIRCTCAPIConversion
CIRCTCalyxToFSM
CIRCTCalyxToHW
CIRCTCalyxNative
CIRCTCombToAIG
CIRCTCombToArith
CIRCTCombToLLVM
CIRCTCombToSMT

View File

@ -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)

View File

@ -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
)

View File

@ -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();
}

View File

@ -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
}