Skip to content

Commit

Permalink
[AIG] Add an AIG dialect
Browse files Browse the repository at this point in the history
  • Loading branch information
uenoku committed Oct 23, 2024
1 parent bed6836 commit 1d15913
Show file tree
Hide file tree
Showing 42 changed files with 1,866 additions and 2 deletions.
33 changes: 33 additions & 0 deletions docs/Dialects/AIG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# 'aig' Dialect

This document outlines the rationale of the AIG dialect, a dialect used for representing and transforming And-Inverter Graphs.

[TOC]

## Rationale

# Why use the AIG dialect instead of the `comb` dialect?

And-Inverter Graphs have proven to be a scalable approach for logic synthesis, serving as the underlying data structure for ABC, one of the most performant open-source logic synthesis tools.

While it's technically possible to represent `aig.and_inv` using a combination of `comb.and`, `comb.xor`, and `hw.constant`, the ability to represent everything with `aig.and_inv` offers significant advantages. This unified representation simplifies complex analyses such as path retiming and area analysis, as well as logic mappings. Moreover, it allows for direct application of existing AIG research results and tools, further enhancing its utility in the synthesis process.

# Operations
## aig.and_inv

The `aig.and_inv` operation directly represents an And-Node in the AIG. Traditionally, an And-Node in AIG has two operands. However, `aig.and_inv` extends this concept by allowing variadic operands and non-i1 integer types. Although the final stage of the pipeline requires lowering everything to i1-binary operands, it's more efficient to progressively lower the variadic multibit operations.

Variadic operands have demonstrated their utility in low-level optimizations within the `comb` dialect. Furthermore, in synthesis, it's common practice to re-balance the logic path. Variadic operands enable the compiler to select more efficient solutions without the need to traverse binary trees multiple times.

The ability to represent multibit operations during synthesis is crucial for scalable logic optimization. This approach enables a form of vectorization, allowing for batch processing of logic synthesis when multibit operations are constructed in a similar manner. Such vectorization can significantly improve the efficiency and performance of the synthesis process.

## aig.cut

The `aig.cut` operation represents a "cut" in the logic tree. This operation possesses the `IsolatedAbove` trait and contains a single block. Its input operands represent the input edges, while the returned value represents the output edges.

This operation proves particularly useful for progressive LUT mapping. For instance, a k-input cut can be readily mapped to a k-input LUT. Consequently, the subsequent stages of the pipeline can concentrate on replacing combinational logic with k-input Cut operations, simplifying the overall process.


## Operations

[include "Dialects/AIGOps.md"]
25 changes: 25 additions & 0 deletions include/circt/Conversion/CombToAIG.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===- 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 {
namespace hw {
class HWModuleOp;
}

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

} // namespace circt

#endif // CIRCT_CONVERSION_COMBTOARITH_H
1 change: 1 addition & 0 deletions include/circt/Conversion/Passes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
12 changes: 12 additions & 0 deletions include/circt/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -790,4 +790,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
25 changes: 25 additions & 0 deletions include/circt/Dialect/AIG/AIG.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===- AIG.td - AIG Definitions ----------*- tablegen -*-===//
//
// 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_AIG_DIALECT_TD
#define CIRCT_AIG_DIALECT_TD

include "mlir/IR/DialectBase.td"
include "mlir/IR/OpBase.td"

def AIG_Dialect : Dialect {
let name = "aig";
let cppNamespace = "::circt::aig";
let summary = "Representation of AIGs";

let usePropertiesForAttributes = 0;
}

include "circt/Dialect/AIG/AIGOps.td"

#endif // CIRCT_AIG_DIALECT_TD
22 changes: 22 additions & 0 deletions include/circt/Dialect/AIG/AIGDialect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===- AIGDialect.h - AIG Definitions --------------------------*- 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 AIG CIRCT dialect.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_AIG_AIGDIALECT_H
#define CIRCT_DIALECT_AIG_AIGDIALECT_H

#include "circt/Support/LLVM.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/Dialect.h"

#include "circt/Dialect/AIG/AIGDialect.h.inc"

#endif // CIRCT_DIALECT_AIG_AIGDIALECT_H
31 changes: 31 additions & 0 deletions include/circt/Dialect/AIG/AIGOps.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//===- AIGOps.h - AIG Op Definitions ---------------------------*- 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_DIALECT_AIG_AIGOPS_H
#define CIRCT_DIALECT_AIG_AIGOPS_H

#include "circt/Support/LLVM.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinOps.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Dialect.h"
#include "mlir/IR/OpDefinition.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/Operation.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

#include "circt/Dialect/AIG/AIGDialect.h"

#define GET_OP_CLASSES
#include "circt/Dialect/AIG/AIG.h.inc"

#endif // CIRCT_DIALECT_AIG_AIGOPS_H
120 changes: 120 additions & 0 deletions include/circt/Dialect/AIG/AIGOps.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
//===- AIGOps.td - AIG Op Definitions -------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// AIG Ops are defined in tablegen.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_AIG_OPS_TD
#define CIRCT_DIALECT_AIG_OPS_TD

include "circt/Dialect/AIG/AIG.td"
include "mlir/IR/OpBase.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/Interfaces/SideEffectInterfaces.td"


class AIGOp<string mnemonic, list<Trait> traits = []> :
Op<AIG_Dialect, mnemonic, traits>;

def AndInverterOp : AIGOp<"and_inv", [SameOperandsAndResultType, Pure]> {
let summary = "AIG dialect AND operation";
let description = [{
The `aig.and_inv` operation represents an And-Inverter in the AIG dialect.
Unlike comb.and, operands can be inverted respectively.

Example:
```mlir
%r1 = aig.and_inv %a, %b: i3
%r2 = aig.and_inv not %a, %b, not %c : i3
%r3 = aig.and_inv not %a : i3
```
}];
// TODO: Restrict to HWIntegerType.
let arguments = (ins Variadic<AnyType>:$inputs, DenseBoolArrayAttr:$inverted);
let results = (outs AnyType:$result);

// NOTE: Custom assembly format is needed to pretty print the `inverted`
// attribute.
let hasCustomAssemblyFormat = 1;

let builders = [
OpBuilder<(ins "Value":$input, CArg<"bool", "false">:$invert), [{
SmallVector<bool> inverted {invert};
return build($_builder, $_state, {input}, inverted);
}]>,
OpBuilder<(ins "Value":$lhs, "Value":$rhs, CArg<"bool", "false">:$invertLhs,
CArg<"bool", "false">:$invertRhs), [{
SmallVector<bool> inverted {invertLhs, invertRhs};
return build($_builder, $_state, {lhs, rhs}, inverted);
}]>
];

let extraClassDeclaration = [{
// Evaluate the operation with the given input values.
APInt evaluate(ArrayRef<APInt> inputs);

// Check if the input is inverted.
bool isInverted(size_t idx) {
return getInverted()[idx];
}
}];
let hasFolder = 1;
let hasCanonicalizeMethod = 1;
}

def CutOp : AIGOp<"cut", [IsolatedFromAbove, SingleBlock]> {
let summary = "AIG dialect Cut operation";
let description = [{
The `aig.cut` operation represents a cut in the And-Inverter-Graph.
This operation is variadic and can take multiple inputs and outputs,
which corresponds to the input and output edges in AIG conceptually.

```mlir
%0, %1 = aig.cut %a, %b, %c, %d : (i1, i1, i1, i1) -> (i1, i1) {
^bb0(%arg0: i1, %arg1: i1, %arg2: i1, %arg3: i1):
%0 = aig.and_inv not %arg0, %arg1 : i1
%1 = aig.and_inv %arg1, %arg3 : i1
aig.output %0, %1 : i1
}
```

}];
let arguments = (ins Variadic<AnyType>:$inputs);
let results = (outs Variadic<AnyType>:$results);
let regions = (region SizedRegion<1>:$body);
let assemblyFormat = [{
$inputs attr-dict `:` functional-type($inputs, $results) $body
}];

let builders = [
OpBuilder<(ins
CArg<"TypeRange", "{}">:$resultTypes,
CArg<"ValueRange", "{}">:$inputs,
CArg<"std::function<void()>", "{}">:$ctor)>
];

let extraClassDeclaration = [{
Block *getBodyBlock() { return &getBody().front(); }
}];
}

def OutputOp : AIGOp<"output", [Terminator,
ReturnLike, ParentOneOf<["CutOp"]>]> {
let summary = "AIG dialect Output operation";
let description = [{
The `aig.output` operation represents out edges of a cut.
}];
let arguments = (ins Variadic<AnyType>:$outputs);
let assemblyFormat = [{
attr-dict ($outputs^ `:` qualified(type($outputs)))?
}];
}

#endif // CIRCT_DIALECT_AIG_OPS_TD
40 changes: 40 additions & 0 deletions include/circt/Dialect/AIG/AIGPasses.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===- AIGPasses.h - AIG dialect passes -----------------------------------===//
//
// 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_DIALECT_AIG_AIGPASSES_H
#define CIRCT_DIALECT_AIG_AIGPASSES_H

#include "mlir/Pass/Pass.h"
#include <memory>
#include <optional>

namespace mlir {
class Pass;
} // namespace mlir

#include "circt/Dialect/AIG/AIGPassesEnums.h.inc"

namespace circt {
namespace aig {

#define GEN_PASS_DECL
#include "circt/Dialect/AIG/AIGPasses.h.inc"

std::unique_ptr<mlir::Pass> createLowerCutToLUTPass();
std::unique_ptr<mlir::Pass> createLowerVariadicPass();
std::unique_ptr<mlir::Pass> createLowerWordToBitsPass();
std::unique_ptr<mlir::Pass>
createGreedyCutDecompPass(const GreedyCutDecompOptions &options = {});

#define GEN_PASS_REGISTRATION
#include "circt/Dialect/AIG/AIGPasses.h.inc"

} // namespace aig
} // namespace circt

#endif // CIRCT_DIALECT_AIG_AIGPASSES_H
41 changes: 41 additions & 0 deletions include/circt/Dialect/AIG/AIGPasses.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===- ArcPasses.td - Arc dialect passes -------------------*- tablegen -*-===//
//
// 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_DIALECT_ARC_ARCPASSES_TD
#define CIRCT_DIALECT_ARC_ARCPASSES_TD

include "mlir/Pass/PassBase.td"

def LowerCutToLUT : Pass<"aig-lower-cut-to-lut", "hw::HWModuleOp"> {
let summary = "Lower a cut to a LUT";
let dependentDialects = ["comb::CombDialect"];
let constructor = "circt::aig::createLowerCutToLUTPass()";
}

def LowerVariadic : Pass<"aig-lower-variadic", "hw::HWModuleOp"> {
let summary = "Lower variadic AndInverter operations to binary AndInverter";
let constructor = "circt::aig::createLowerVariadicPass()";
}

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

def GreedyCutDecomp : Pass<"aig-greedy-cut-decomp", "hw::HWModuleOp"> {
let summary = "Decompose AIGs into k-feasible Cuts using a greedy algorithm";
let dependentDialects = ["comb::CombDialect"];
let constructor = "circt::aig::createGreedyCutDecompPass()";
let options = [
Option<"cutSizes", "cut-sizes", "uint32_t", "6",
"The sizes of the cuts to decompose">,
];
}

#endif // CIRCT_DIALECT_ARC_ARCPASSES_TD
9 changes: 9 additions & 0 deletions include/circt/Dialect/AIG/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
add_circt_dialect(AIG aig)
add_circt_dialect_doc(AIG aig)

set(LLVM_TARGET_DEFINITIONS AIGPasses.td)
mlir_tablegen(AIGPasses.h.inc -gen-pass-decls)
mlir_tablegen(AIGPassesEnums.h.inc -gen-enum-decls)
mlir_tablegen(AIGPassesEnums.cpp.inc -gen-enum-defs)
add_public_tablegen_target(CIRCTAIGTransformsIncGen)
add_circt_doc(AIGPasses AIGPasses -gen-pass-doc)
1 change: 1 addition & 0 deletions include/circt/Dialect/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
##
##===----------------------------------------------------------------------===//

add_subdirectory(AIG)
add_subdirectory(Arc)
add_subdirectory(Calyx)
add_subdirectory(Comb)
Expand Down
Loading

0 comments on commit 1d15913

Please sign in to comment.