Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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,
"::mlir::FloatAttr":$intrinsic,
"::mlir::FloatAttr":$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 @@
//===- SynthEnums.td - Enums for Synth dialect -------------------*- tablegen -*-===//
Comment thread
okekayode marked this conversation as resolved.
Outdated
//
// 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, 0.0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 5.0, 0.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, 0.0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 5.0, 0.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, 0.0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 5.0, 0.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, 0.0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 1.0, 0.0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "c", 1.0, 0.0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "d", 1.0, 0.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, 0.0, #synth.polarity<positive>>, #synth.linear_timing_arc<"result", "b", 1.0, 0.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"
109 changes: 81 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,99 @@ 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;
for (const auto &port : hwModule.getPortList()) {
Comment thread
okekayode marked this conversation as resolved.
Outdated
if (!port.isOutput())
continue;
if (outputName)
continue;
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 arcAttr : mappingCost.getArcs()) {
auto arc = dyn_cast<LinearTimingArcAttr>(arcAttr);
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;
}

double intrinsic = arc.getIntrinsic().getValue().convertToDouble();
if (intrinsic !=
static_cast<double>(static_cast<DelayType>(intrinsic))) {
hwModule.emitError("expected integral intrinsic delay for input '")
<< arc.getRelatedPin().getValue()
<< "' until TechMapper supports fractional delays";
signalPassFailure();
return;
}
Comment thread
okekayode marked this conversation as resolved.
Outdated

// 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>(intrinsic))
.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