mirror of https://github.com/llvm/circt.git
[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:
parent
4f0edf4cfe
commit
5b8b18e9e4
|
@ -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
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,6 +7,7 @@ add_circt_public_c_api_library(CIRCTCAPIConversion
|
|||
CIRCTCalyxToFSM
|
||||
CIRCTCalyxToHW
|
||||
CIRCTCalyxNative
|
||||
CIRCTCombToAIG
|
||||
CIRCTCombToArith
|
||||
CIRCTCombToLLVM
|
||||
CIRCTCombToSMT
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
|
@ -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();
|
||||
}
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue