Skip to content
Closed
2 changes: 1 addition & 1 deletion include/circt/Dialect/AIG/AIGOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ include "mlir/Interfaces/SideEffectInterfaces.td"
class AIGOp<string mnemonic, list<Trait> traits = []> :
Op<AIG_Dialect, mnemonic, traits>;

def AndInverterOp : AIGOp<"and_inv", [SameOperandsAndResultType, Pure]> {
def AndInverterOp : AIGOp<"and_inv", [SameOperandsAndResultType, Pure, Commutative]> {
let summary = "AIG dialect AND operation";
let description = [{
The `aig.and_inv` operation represents an And-Inverter in the AIG dialect.
Expand Down
8 changes: 8 additions & 0 deletions include/circt/Dialect/AIG/AIGPasses.td
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,17 @@ def LowerVariadic : Pass<"aig-lower-variadic", "hw::HWModuleOp"> {
let summary = "Lower variadic AndInverter operations to binary AndInverter";
}

def BalanceVariadic : Pass<"aig-balance-variadic", "hw::HWModuleOp"> {
let summary = "Lower variadic AndInverter operations to binary AndInverter";
}

def LowerWordToBits : Pass<"aig-lower-word-to-bits", "hw::HWModuleOp"> {
let summary = "Lower multi-bit AndInverter to single-bit ones";
let dependentDialects = ["comb::CombDialect"];
}

def MaximumAndCover : Pass<"maximum-and-cover", "hw::HWModuleOp"> {
let summary = "Maximum And Cover";
}

#endif // CIRCT_DIALECT_AIG_AIGPASSES_TD
60 changes: 60 additions & 0 deletions include/circt/Dialect/AIG/Analysis/OpDepthAnalysis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//===- OpDepthAnalysis.h - operation depth analyses -----------------------===//
//
// 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 header file defines AIG operation depth analysis.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_ANALYSIS_OPDEPTH_ANALYSIS_H
#define CIRCT_ANALYSIS_OPDEPTH_ANALYSIS_H

#include "circt/Dialect/AIG/AIGOps.h"
#include "circt/Dialect/HW/HWOps.h"

namespace mlir {
class AnalysisManager;
} // namespace mlir
namespace circt {
namespace aig {
namespace analysis {

class OpDepthAnalysis {
public:
OpDepthAnalysis(hw::HWModuleOp moduleOp, mlir::AnalysisManager &am);

/// Get the depth of operations of a specific name
size_t getOpDepth(AndInverterOp op) const { return opDepths.at(op); }

bool isOnCriticalPath(AndInverterOp op) const {
return criticalPath.count(op);
}

const DenseMap<AndInverterOp, size_t> &getOpDepthMap() const {
return opDepths;
}

size_t updateLevel(AndInverterOp op, bool isRoot = false);
void updateAllLevel();

SmallVector<AndInverterOp> getPOs();

private:
void setCriticalPath(AndInverterOp op);

private:
DenseMap<AndInverterOp, size_t> opDepths;
SetVector<AndInverterOp> criticalPath;
size_t currDepth = 0;
hw::HWModuleOp module;
};

} // namespace analysis
} // namespace aig
} // namespace circt

#endif // CIRCT_ANALYSIS_OPDEPTH_ANALYSIS_H
33 changes: 33 additions & 0 deletions integration_test/circt-synth/aig-balancing-lec.mlir
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// REQUIRES: libz3
// REQUIRES: circt-lec-jit

// RUN: circt-opt %s --cse --convert-aig-to-comb -o %t1.mlir
// RUN: circt-opt %s --maximum-and-cover --aig-balance-variadic --cse --convert-aig-to-comb -o %t2.mlir

// RUN: circt-lec %t1.mlir %t2.mlir -c1=aig -c2=aig --shared-libs=%libz3 | FileCheck %s --check-prefix=COMB_AIG
// COMB_AIG: c1 == c2
hw.module @aig(in %a: i1, in %b: i1, in %c: i1, in %d: i1, out o1: i1, out o2: i1, out o3: i1) {
%0 = aig.and_inv %a, %b : i1
%1 = aig.and_inv %0, %c : i1
%2 = aig.and_inv %b, %c : i1
%3 = aig.and_inv %2, %d : i1

%4 = aig.and_inv %c, %d : i1
%5 = aig.and_inv %b, %4 : i1
%6 = aig.and_inv %a, %5 : i1

hw.output %1, %3, %6 : i1, i1, i1
}

// RUN: circt-lec %t1.mlir %t2.mlir -c1=aig2 -c2=aig2 --shared-libs=%libz3 | FileCheck %s --check-prefix=COMB_AIG2
// COMB_AIG2: c1 == c2
hw.module @aig2(in %a: i1, in %b: i1, in %c: i1, in %d: i1, in %e: i1, in %f: i1, in %g: i1, out o1: i1) {
%1 = aig.and_inv %a, not %b : i1
%2 = aig.and_inv %d, not %e : i1
%3 = aig.and_inv not %2, %f : i1
%4 = aig.and_inv not %c, %3 : i1
%5 = aig.and_inv %1, not %4 : i1
%6 = aig.and_inv %5, %g : i1

hw.output %6 : i1
}
6 changes: 6 additions & 0 deletions lib/Dialect/AIG/Analysis/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_circt_dialect_library(CIRCTAIGAnalysis
OpDepthAnalysis.cpp

LINK_LIBS PUBLIC
CIRCTAIG
)
84 changes: 84 additions & 0 deletions lib/Dialect/AIG/Analysis/OpDepthAnalysis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//===- OpCountAnalysis.cpp - operation count analyses -----------*- 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 file defines the op depth (level) analysis.
//
//===----------------------------------------------------------------------===//

#include "circt/Dialect/AIG/Analysis/OpDepthAnalysis.h"

using namespace circt;
using namespace aig;
using namespace analysis;

OpDepthAnalysis::OpDepthAnalysis(hw::HWModuleOp moduleOp,
mlir::AnalysisManager &am)
: module(moduleOp) {
// llvm::dbgs() << "OpDepthAnalysis Init\n";
// updateAllLevel();
}

SmallVector<AndInverterOp> OpDepthAnalysis::getPOs() {
SmallVector<AndInverterOp> po;
for (auto op : module.getOps<AndInverterOp>()) {
bool isPO = true;
for (auto *user : op->getUsers()) {
if (isa<AndInverterOp>(user)) {
isPO = false;
break;
}
}
if (isPO)
po.push_back(op);
}
return po;
}

void OpDepthAnalysis::updateAllLevel() {
auto po = getPOs();
for (auto &op : po) {
currDepth = std::max(currDepth, updateLevel(op));
}

for (auto &op : po) {
if (auto it = opDepths.find(op);
it != opDepths.end() && it->second == currDepth) {
setCriticalPath(op);
break;
}
}
}

size_t OpDepthAnalysis::updateLevel(AndInverterOp op, bool isRoot) {
if (auto it = opDepths.find(op); !isRoot && it != opDepths.end()) {
return it->second;
}

/// PI is level 0, so the minimum level of an AndInverterOp is 1
size_t maxDepth = 1;
for (auto fanin : op.getOperands()) {
auto faninOp = fanin.getDefiningOp<AndInverterOp>();
if (faninOp) {
size_t faninDepth = updateLevel(faninOp);
maxDepth = std::max(maxDepth, faninDepth + 1);
}
}
opDepths[op] = maxDepth;
return maxDepth;
}

void OpDepthAnalysis::setCriticalPath(AndInverterOp op) {
size_t clevel = opDepths[op];
for (auto fanin : op.getOperands()) {
auto faninOp = fanin.getDefiningOp<AndInverterOp>();
if (faninOp && opDepths[faninOp] + 1 == clevel) {
setCriticalPath(faninOp);
// break; // TODO: Should break when there are multiple critical paths?
}
}
}
1 change: 1 addition & 0 deletions lib/Dialect/AIG/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ add_circt_dialect_library(CIRCTAIG
)

add_subdirectory(Transforms)
add_subdirectory(Analysis)
Loading