Skip to content
Merged
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
6 changes: 6 additions & 0 deletions include/circt/Dialect/Synth/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ add_circt_interface(SynthOpInterfaces)
add_subdirectory(Transforms)

set(LLVM_TARGET_DEFINITIONS Synth.td)

mlir_tablegen(SynthEnums.h.inc -gen-enum-decls)
mlir_tablegen(SynthEnums.cpp.inc -gen-enum-defs)
add_public_tablegen_target(CIRCTSynthEnumsIncGen)
add_dependencies(circt-headers CIRCTSynthEnumsIncGen)

mlir_tablegen(SynthAttributes.h.inc -gen-attrdef-decls -attrdefs-dialect=synth)
mlir_tablegen(SynthAttributes.cpp.inc -gen-attrdef-defs -attrdefs-dialect=synth)
add_public_tablegen_target(CIRCTSynthAttrIncGen)
Expand Down
1 change: 1 addition & 0 deletions include/circt/Dialect/Synth/Synth.td
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def Synth_Dialect : Dialect {
let useDefaultAttributePrinterParser = 1;
}

include "circt/Dialect/Synth/SynthEnums.td"
include "circt/Dialect/Synth/SynthAttributes.td"
include "circt/Dialect/Synth/SynthOps.td"

Expand Down
1 change: 1 addition & 0 deletions include/circt/Dialect/Synth/SynthAttributes.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#ifndef CIRCT_DIALECT_SYNTH_SYNTHATTRIBUTES_H
#define CIRCT_DIALECT_SYNTH_SYNTHATTRIBUTES_H

#include "circt/Dialect/Synth/SynthEnums.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinAttributes.h"

Expand Down
38 changes: 38 additions & 0 deletions include/circt/Dialect/Synth/SynthAttributes.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

include "mlir/IR/AttrTypeBase.td"
include "mlir/IR/DialectBase.td"
include "mlir/IR/EnumAttr.td"
include "circt/Dialect/Synth/SynthEnums.td"

// A single resolved 2D NLDM lookup table. Values are stored in row-major order
// with dimensions index1.size x index2.size.
Expand Down Expand Up @@ -45,5 +47,41 @@ def NLDMTimingArcAttr : AttrDef<Synth_Dialect, "NLDMTimingArc"> {
"$riseTransition `,` $fallTransition `>`";
}

def PolarityAttr : AttrDef<Synth_Dialect, "Polarity"> {
let mnemonic = "polarity";
let summary = "Timing arc polarity";
let parameters = (ins
"PolarityKind":$value
);
let assemblyFormat = "`<` $value `>`";
}

def LinearTimingArcAttr : AttrDef<Synth_Dialect, "LinearTimingArc"> {
let mnemonic = "linear_timing_arc";
let summary = "A single simplified linear timing arc";
let parameters = (ins
"::mlir::StringAttr":$pin,
"::mlir::StringAttr":$relatedPin,
"int64_t":$intrinsic,
"int64_t":$sensitivity,
"PolarityAttr":$polarity
);
let assemblyFormat =
"`<` $pin `,` $relatedPin `,` $intrinsic `,` $sensitivity `,` "
"$polarity `>`";
}

def MappingCostAttr : AttrDef<Synth_Dialect, "MappingCost"> {
let mnemonic = "mapping_cost";
let summary = "Simplified timing and area cost for tech mapping";
let parameters = (ins
"::mlir::FloatAttr":$area,
"::mlir::ArrayAttr":$arcs,
Comment thread
uenoku marked this conversation as resolved.
"::mlir::DictionaryAttr":$inputCaps
);
let assemblyFormat =
"`<` `area` `=` $area `,` `arcs` `=` $arcs `,` "
"`input_caps` `=` $inputCaps `>`";
}

#endif // CIRCT_DIALECT_SYNTH_SYNTHATTRIBUTES_TD
17 changes: 17 additions & 0 deletions include/circt/Dialect/Synth/SynthEnums.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//===----------------------------------------------------------------------===//
//
// 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_SYNTH_SYNTHENUMS_H
#define CIRCT_DIALECT_SYNTH_SYNTHENUMS_H

#include "mlir/IR/BuiltinAttributes.h"
#include "llvm/ADT/StringRef.h"

#include "circt/Dialect/Synth/SynthEnums.h.inc"

#endif // CIRCT_DIALECT_SYNTH_SYNTHENUMS_H
28 changes: 28 additions & 0 deletions include/circt/Dialect/Synth/SynthEnums.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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 Synth dialect specific enums.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_SYNTH_SYNTHENUMS_TD
#define CIRCT_DIALECT_SYNTH_SYNTHENUMS_TD

include "mlir/IR/EnumAttr.td"

let cppNamespace = "circt::synth" in {

def Polarity_Positive : I32EnumAttrCase<"Positive", 0, "positive">;
def Polarity_Negative : I32EnumAttrCase<"Negative", 1, "negative">;

def PolarityKindAttr : I32EnumAttr<"PolarityKind", "timing arc polarity",
[Polarity_Positive, Polarity_Negative]>;

}

#endif // CIRCT_DIALECT_SYNTH_SYNTHENUMS_TD
10 changes: 5 additions & 5 deletions integration_test/circt-synth/mapping-lec.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,29 @@
// COMB_MUL_LUT: c1 == c2

// Set delay for binary and inv op to 5 so that others will be prioritized
hw.module @and_inv(in %a : i1, in %b : i1, out result : i1) attributes {hw.techlib.info = {area = 1.0 : f64, delay = [[5], [5]]}} {
hw.module @and_inv(in %a : i1, in %b : i1, out result : i1) attributes {synth.mapping_cost = #synth.mapping_cost<area = 1.0 : f64, arcs = [#synth.linear_timing_arc<"result", "a", 5, 0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 5, 0, #synth.polarity<positive>>], input_caps = {}>} {
%0 = synth.aig.and_inv %a, %b : i1
hw.output %0 : i1
}

hw.module @and_inv_n(in %a : i1, in %b : i1, out result : i1) attributes {hw.techlib.info = {area = 1.0 : f64, delay = [[5], [5]]}} {
hw.module @and_inv_n(in %a : i1, in %b : i1, out result : i1) attributes {synth.mapping_cost = #synth.mapping_cost<area = 1.0 : f64, arcs = [#synth.linear_timing_arc<"result", "a", 5, 0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 5, 0, #synth.polarity<positive>>], input_caps = {}>} {
%0 = synth.aig.and_inv not %a, %b : i1
hw.output %0 : i1
}

hw.module @and_inv_nn(in %a : i1, in %b : i1, out result : i1) attributes {hw.techlib.info = {area = 1.0 : f64, delay = [[5], [5]]}} {
hw.module @and_inv_nn(in %a : i1, in %b : i1, out result : i1) attributes {synth.mapping_cost = #synth.mapping_cost<area = 1.0 : f64, arcs = [#synth.linear_timing_arc<"result", "a", 5, 0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 5, 0, #synth.polarity<positive>>], input_caps = {}>} {
%0 = synth.aig.and_inv not %a, not %b : i1
hw.output %0 : i1
}

hw.module @nand_nand(in %a : i1, in %b : i1, in %c : i1, in %d: i1, out result : i1) attributes {hw.techlib.info = {area = 3.0 : f64, delay = [[1], [1], [1], [1]]}} {
hw.module @nand_nand(in %a : i1, in %b : i1, in %c : i1, in %d: i1, out result : i1) attributes {synth.mapping_cost = #synth.mapping_cost<area = 3.0 : f64, arcs = [#synth.linear_timing_arc<"result", "a", 1, 0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 1, 0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "c", 1, 0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "d", 1, 0, #synth.polarity<positive>>], input_caps = {}>} {
%0 = synth.aig.and_inv %a, %b : i1
%1 = synth.aig.and_inv %c, %d : i1
%2 = synth.aig.and_inv not %0, not %1 : i1
hw.output %2 : i1
}

hw.module @some(in %a : i1, in %b : i1, out result : i1) attributes {hw.techlib.info = {area = 1.0 : f64, delay = [[1], [1]]}} {
hw.module @some(in %a : i1, in %b : i1, out result : i1) attributes {synth.mapping_cost = #synth.mapping_cost<area = 1.0 : f64, arcs = [#synth.linear_timing_arc<"result", "a", 1, 0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 1, 0, #synth.polarity<positive>>], input_caps = {}>} {
%0 = synth.aig.and_inv not %a, not %b : i1
%1 = synth.aig.and_inv %a, %b : i1
%2 = synth.aig.and_inv not %0, not %1 : i1
Expand Down
1 change: 1 addition & 0 deletions lib/Dialect/Synth/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_circt_dialect_library(CIRCTSynth
DEPENDS
MLIRSynthIncGen
MLIRSynthOpInterfacesIncGen
CIRCTSynthEnumsIncGen
CIRCTSynthAttrIncGen

LINK_COMPONENTS
Expand Down
3 changes: 3 additions & 0 deletions lib/Dialect/Synth/SynthDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "circt/Dialect/Synth/SynthDialect.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/Synth/SynthAttributes.h"
#include "circt/Dialect/Synth/SynthEnums.h"
#include "circt/Dialect/Synth/SynthOps.h"
#include "mlir/IR/DialectImplementation.h"

Expand Down Expand Up @@ -41,3 +42,5 @@ Operation *SynthDialect::materializeConstant(OpBuilder &builder,

#define GET_ATTRDEF_CLASSES
#include "circt/Dialect/Synth/SynthAttributes.cpp.inc"

#include "circt/Dialect/Synth/SynthEnums.cpp.inc"
104 changes: 76 additions & 28 deletions lib/Dialect/Synth/Transforms/TechMapper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,20 @@
//
// The pass uses a cut-based algorithm with priority cuts and NPN canonical
// forms for efficient pattern matching. It processes HWModuleOp instances with
// "hw.techlib.info" attributes as technology library patterns and maps
// "synth.mapping_cost" attributes as technology library patterns and maps
// non-library modules to optimal gate implementations based on area and timing
// optimization strategies.
//
//===----------------------------------------------------------------------===//

#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/Synth/SynthAttributes.h"
#include "circt/Dialect/Synth/Transforms/CutRewriter.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/Threading.h"
#include "mlir/Support/WalkResult.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Support/Debug.h"
#include <atomic>
Expand Down Expand Up @@ -188,48 +190,94 @@ struct TechMapperPass : public impl::TechMapperBase<TechMapperPass> {
SmallVector<std::unique_ptr<CutRewritePattern>> libraryPatterns;

unsigned maxInputSize = 0;
// Consider modules with the "hw.techlib.info" attribute as library
// Consider modules with the "synth.mapping_cost" attribute as library
// modules.
// TODO: This attribute should be replaced with a more structured
// representation of technology library information. Specifically, we should
// have a dedicated operation for technology library.
SmallVector<hw::HWModuleOp> nonLibraryModules;
for (auto hwModule : module.getOps<hw::HWModuleOp>()) {
auto techInfo =
hwModule->getAttrOfType<DictionaryAttr>("hw.techlib.info");
if (!techInfo) {
// If the module does not have the techlib info, it is not a library
// TODO: Run mapping only when the module is under the specific
// hierarchy.

auto mappingCost =
hwModule->getAttrOfType<MappingCostAttr>("synth.mapping_cost");
if (!mappingCost) {
nonLibraryModules.push_back(hwModule);
continue;
}

// Get area and delay attributes
auto areaAttr = techInfo.getAs<FloatAttr>("area");
auto delayAttr = techInfo.getAs<ArrayAttr>("delay");
if (!areaAttr || !delayAttr) {
mlir::emitError(hwModule.getLoc())
<< "Library module " << hwModule.getModuleName()
<< " must have 'area'(float) and 'delay' (2d array to represent "
"input-output pair delay) attributes";
double area = mappingCost.getArea().getValue().convertToDouble();

StringAttr outputName;
hw::ModulePortInfo ports(hwModule.getPortList());
for (const auto &port : ports.getOutputs()) {
if (outputName) {
hwModule.emitError(
"Modules with multiple outputs are not supported yet");
signalPassFailure();
return;
}
outputName = port.name;
}
if (!outputName) {
hwModule.emitError("expected library module to have an output");
signalPassFailure();
return;
}

double area = areaAttr.getValue().convertToDouble();
llvm::DenseMap<StringAttr, DelayType> delayByInput;
for (auto attr : mappingCost.getArcs()) {
auto arc = cast<LinearTimingArcAttr>(attr);
if (!arc) {
hwModule.emitError(
"expected synth.linear_timing_arc in synth.mapping_cost arcs");
signalPassFailure();
return;
}

if (arc.getPin() != outputName) {
hwModule.emitError("mapping cost arc output '")
<< arc.getPin().getValue() << "' does not match module output '"
<< outputName.getValue() << "'";
signalPassFailure();
return;
}

int64_t intrinsicDelay = arc.getIntrinsic();

// TechMapper currently preserves the old integer per-pin delay model.
// The sensitivity, polarity, and input capacitance fields are carried
// in the attribute for future load-aware mapping.
if (!delayByInput
.try_emplace(arc.getRelatedPin(),
static_cast<DelayType>(intrinsicDelay))
.second) {
hwModule.emitError("duplicate mapping cost arc for input '")
<< arc.getRelatedPin().getValue() << "'";
signalPassFailure();
return;
}
}

SmallVector<DelayType> delay;
for (auto delayValue : delayAttr) {
auto delayArray = cast<ArrayAttr>(delayValue);
for (auto delayElement : delayArray) {
// FIXME: Currently we assume delay is given as integer attributes,
// this should be replaced once we have a proper cell op with
// dedicated timing attributes with units.
delay.push_back(
cast<mlir::IntegerAttr>(delayElement).getValue().getZExtValue());
for (const auto &port : hwModule.getPortList()) {
if (!port.isInput())
continue;

auto it = delayByInput.find(port.name);
if (it == delayByInput.end()) {
hwModule.emitError("missing mapping cost arc for input '")
<< port.name.getValue() << "'";
signalPassFailure();
return;
}

delay.push_back(it->second);
}

if (delay.size() != delayByInput.size()) {
hwModule.emitError(
"synth.mapping_cost arcs do not match module inputs");
signalPassFailure();
return;
}

// Compute NPN Class for the module.
auto npnClass = getNPNClassFromModule(hwModule);
if (failed(npnClass)) {
Expand Down
Loading
Loading