9#include "../PassDetails.h" 
   17#include "llvm/ADT/StringExtras.h" 
   18#include "llvm/ADT/TypeSwitch.h" 
   19#include "llvm/Support/Compression.h" 
   20#include "llvm/Support/JSON.h" 
   24#define GEN_PASS_DEF_ESIBUILDMANIFEST 
   25#include "circt/Dialect/ESI/ESIPasses.h.inc" 
   35struct ESIBuildManifestPass
 
   36    : 
public circt::esi::impl::ESIBuildManifestBase<ESIBuildManifestPass> {
 
   37  void runOnOperation() 
override;
 
   43  llvm::json::Value 
json(Operation *errorOp, 
Type, 
bool useTable = 
true);
 
   46  llvm::json::Value 
json(Operation *errorOp, Attribute, 
bool elideType = 
false);
 
   49  void emitNode(llvm::json::OStream &, AppIDHierNodeOp nodeOp);
 
   51  void emitBlock(llvm::json::OStream &, 
Block &block, StringRef manifestClass);
 
   53  AppIDHierRootOp appidRoot;
 
   59  std::string useType(
Type type) {
 
   61    llvm::raw_string_ostream(typeID) << type;
 
   63    if (typeLookup.count(type))
 
   65    typeLookup[type] = types.size();
 
   66    types.push_back(type);
 
   69  SmallVector<Type, 8> types;
 
   70  DenseMap<Type, size_t> typeLookup;
 
   73  DenseSet<SymbolRefAttr> symbols;
 
   74  DenseSet<SymbolRefAttr> modules;
 
   80void ESIBuildManifestPass::runOnOperation() {
 
   81  MLIRContext *
ctxt = &getContext();
 
   82  Operation *mod = getOperation();
 
   83  symCache.addDefinitions(mod);
 
   87  for (
auto root : mod->getRegion(0).front().getOps<AppIDHierRootOp>())
 
   88    if (root.getTopModuleRef() == top)
 
   94  std::string jsonManifest = 
json();
 
   97  llvm::raw_fd_ostream os(
"esi_system_manifest.json", ec);
 
   99    mod->emitError() << 
"Failed to open file for writing: " << ec.message();
 
  102    os << jsonManifest << 
"\n";
 
  106  SmallVector<uint8_t, 10 * 1024> compressedManifest;
 
  107  if (llvm::compression::zlib::isAvailable()) {
 
  109    llvm::compression::zlib::compress(
 
  110        ArrayRef((uint8_t *)jsonManifest.data(), jsonManifest.length()),
 
  111        compressedManifest, llvm::compression::zlib::BestSizeCompression);
 
  113    llvm::raw_fd_ostream bos(
"esi_system_manifest.json.zlib", ec);
 
  115      mod->emitError() << 
"Failed to open compressed file for writing: " 
  119      bos.write((
char *)compressedManifest.data(), compressedManifest.size());
 
  122    OpBuilder b(symCache.getDefinition(appidRoot.getTopModuleRefAttr())
 
  126    CompressedManifestOp::create(b, b.getUnknownLoc(),
 
  127                                 BlobAttr::get(ctxt, compressedManifest));
 
  130        << 
"zlib not available but required for manifest support";
 
  134void ESIBuildManifestPass::emitNode(llvm::json::OStream &j,
 
  135                                    AppIDHierNodeOp nodeOp) {
 
  136  std::set<StringRef> classesToEmit;
 
  137  for (
auto manifestData : nodeOp.getOps<IsManifestData>())
 
  138    classesToEmit.insert(manifestData.getManifestClass());
 
  140    j.attribute(
"appID", 
json(nodeOp, nodeOp.getAppIDAttr()));
 
  141    j.attribute(
"instanceOf", 
json(nodeOp, nodeOp.getModuleRefAttr()));
 
  142    for (StringRef manifestClass : classesToEmit)
 
  143      j.attributeArray(manifestClass.str() + 
"s", [&]() {
 
  144        emitBlock(j, nodeOp.getChildren().front(), manifestClass);
 
  146    j.attributeArray(
"children", [&]() {
 
  147      for (
auto nodeOp : nodeOp.getChildren().front().getOps<AppIDHierNodeOp>())
 
  153void ESIBuildManifestPass::emitBlock(llvm::json::OStream &j, Block &block,
 
  154                                     StringRef manifestClass) {
 
  155  for (
auto manifestData : block.getOps<IsManifestData>()) {
 
  156    if (manifestData.getManifestClass() != manifestClass)
 
  159      SmallVector<NamedAttribute, 4> attrs;
 
  160      manifestData.getDetails(attrs);
 
  161      for (
auto attr : attrs)
 
  162        j.attribute(attr.
getName().getValue(),
 
  163                    json(manifestData, attr.getValue()));
 
  168std::string ESIBuildManifestPass::json() {
 
  169  auto mod = getOperation();
 
  170  std::string jsonStrBuffer;
 
  171  llvm::raw_string_ostream os(jsonStrBuffer);
 
  172  llvm::json::OStream j(os, 2);
 
  175  j.attribute(
"apiVersion", esiApiVersion);
 
  177  std::set<StringRef> classesToEmit;
 
  178  for (
auto manifestData : appidRoot.getOps<IsManifestData>())
 
  179    classesToEmit.insert(manifestData.getManifestClass());
 
  181  j.attributeObject(
"design", [&]() {
 
  182    j.attribute(
"instanceOf", 
json(appidRoot, appidRoot.getTopModuleRefAttr()));
 
  183    modules.insert(appidRoot.getTopModuleRefAttr());
 
  184    for (StringRef manifestClass : classesToEmit)
 
  185      j.attributeArray(manifestClass.str() + 
"s", [&]() {
 
  186        emitBlock(j, appidRoot.getChildren().front(), manifestClass);
 
  188    j.attributeArray(
"children", [&]() {
 
  190           appidRoot.getChildren().front().getOps<AppIDHierNodeOp>())
 
  195  j.attributeArray(
"serviceDeclarations", [&]() {
 
  196    for (
auto svcDecl : mod.getBody()->getOps<ServiceDeclOpInterface>()) {
 
  197      auto sym = FlatSymbolRefAttr::get(svcDecl);
 
  198      if (!symbols.contains(sym))
 
  201        j.attribute(
"symbol", 
json(svcDecl, sym, 
true));
 
  202        std::optional<StringRef> typeName = svcDecl.getTypeName();
 
  204          j.attribute(
"serviceName", *typeName);
 
  205        llvm::SmallVector<ServicePortInfo, 8> ports;
 
  206        svcDecl.getPortList(ports);
 
  207        j.attributeArray(
"ports", [&]() {
 
  208          for (
auto port : ports) {
 
  210              j.attribute(
"name", port.port.getName().getValue());
 
  211              j.attribute(
"typeID", useType(port.type));
 
  219  j.attributeArray(
"modules", [&]() {
 
  221    llvm::MapVector<SymbolRefAttr, SmallVector<IsManifestData>>
 
  225    for (
auto modSymbol : modules)
 
  226      symbolInfoLookup[modSymbol] = {};
 
  228    for (
auto symInfo : mod.getBody()->getOps<IsManifestData>()) {
 
  229      FlatSymbolRefAttr sym = symInfo.getSymbolRefAttr();
 
  230      if (!sym || !symbols.contains(sym))
 
  232      symbolInfoLookup[sym].push_back(symInfo);
 
  236    for (
const auto &symNameInfo : symbolInfoLookup) {
 
  238        std::string symbolStr;
 
  239        llvm::raw_string_ostream(symbolStr) << symNameInfo.first;
 
  240        j.attribute(
"symbol", symbolStr);
 
  241        for (
auto symInfo : symNameInfo.second) {
 
  242          j.attributeBegin(symInfo.getManifestClass());
 
  244            SmallVector<NamedAttribute, 4> attrs;
 
  245            symInfo.getDetails(attrs);
 
  246            for (
auto attr : attrs) {
 
  247              if (attr.getName().getValue() == 
"symbolRef")
 
  249              j.attribute(attr.getName().getValue(),
 
  250                          json(symInfo, attr.getValue()));
 
  259  j.attributeArray(
"types", [&]() {
 
  260    for (
size_t i = 0; i < types.size(); i++)
 
  261      j.value(
json(mod, types[i], 
false));
 
  266  return jsonStrBuffer;
 
  271llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp, 
Type type,
 
  273  using llvm::json::Array;
 
  274  using llvm::json::Object;
 
  275  using llvm::json::Value;
 
  277  if (useTable && typeLookup.contains(type)) {
 
  281    std::string typeName;
 
  282    llvm::raw_string_ostream(typeName) << type;
 
  289      TypeSwitch<Type, Object>(type)
 
  294          .Case([&](ChannelBundleType t) {
 
  297            for (
auto field : t.getChannels())
 
  298              channels.push_back(
Object(
 
  299                  {{
"name", field.name.getValue()},
 
  300                   {
"direction", stringifyChannelDirection(field.direction)},
 
  301                   {
"type", 
json(errorOp, field.type, useTable)}}));
 
  302            return Object({{
"channels", Value(std::move(channels))}});
 
  308          .Case([&](ListType t) {
 
  311                {{
"element", 
json(errorOp, t.getElementType(), useTable)}});
 
  313          .Case([&](hw::ArrayType t) {
 
  316                {{
"size", t.getNumElements()},
 
  317                 {
"element", 
json(errorOp, t.getElementType(), useTable)}});
 
  319          .Case([&](hw::StructType t) {
 
  322            for (
auto field : t.getElements())
 
  324                  Object({{
"name", field.name.getValue()},
 
  325                          {
"type", 
json(errorOp, field.type, useTable)}}));
 
  326            return Object({{
"fields", Value(std::move(fields))}});
 
  328          .Case([&](hw::TypeAliasType t) {
 
  331                {{
"name", t.getTypeDecl(symCache).getPreferredName()},
 
  332                 {
"inner", 
json(errorOp, t.getInnerType(), useTable)}});
 
  336            StringRef signedness =
 
  337                t.isSigned() ? 
"signed" 
  338                             : (t.isUnsigned() ? 
"unsigned" : 
"signless");
 
  339            return Object({{
"signedness", signedness}});
 
  341          .Default([&](
Type t) {
 
  342            errorOp->emitWarning()
 
  343                << 
"ESI system manifest: unknown type: " << t;
 
  349  llvm::raw_string_ostream(typeID) << type;
 
  352  int64_t width = hw::getBitWidth(type);
 
  353  if (
auto chanType = dyn_cast<ChannelType>(type))
 
  354    width = hw::getBitWidth(chanType.getInner());
 
  356    o[
"hwBitwidth"] = width;
 
  358  o[
"dialect"] = type.getDialect().getNamespace();
 
  366llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp, Attribute attr,
 
  370  using llvm::json::Object;
 
  371  using llvm::json::Value;
 
  373      TypeSwitch<Attribute, Value>(attr)
 
  374          .Case([&](FlatSymbolRefAttr ref) {
 
  377            llvm::raw_string_ostream(value) << ref;
 
  380          .Case([&](StringAttr a) { 
return a.getValue(); })
 
  381          .Case([&](IntegerAttr a) { 
return a.getValue().getLimitedValue(); })
 
  382          .Case([&](TypeAttr a) { 
return useType(a.getValue()); })
 
  383          .Case([&](ArrayAttr a) {
 
  384            return llvm::json::Array(llvm::map_range(
 
  385                a, [&](Attribute a) { 
return json(errorOp, a); }));
 
  387          .Case([&](DictionaryAttr a) {
 
  388            llvm::json::Object dict;
 
  389            for (
const auto &entry : a.getValue())
 
  390              dict[entry.
getName().getValue()] =
 
  391                  json(errorOp, entry.getValue());
 
  394          .Case([&](AppIDAttr appid) {
 
  395            llvm::json::Object dict;
 
  396            dict[
"name"] = appid.getName().getValue();
 
  397            auto idx = appid.getIndex();
 
  399              dict[
"index"] = *idx;
 
  402          .Default([&](Attribute a) {
 
  404            llvm::raw_string_ostream(value) << a;
 
  409  auto typedAttr = llvm::dyn_cast<TypedAttr>(attr);
 
  410  if (elideType || !typedAttr || isa<NoneType>(typedAttr.getType()))
 
  415  dict[
"value"] = value;
 
  416  dict[
"type"] = useType(typedAttr.getType());
 
  420std::unique_ptr<OperationPass<ModuleOp>>
 
  422  return std::make_unique<ESIBuildManifestPass>();
 
 
This stores lookup tables to make manipulating and working with the IR more efficient.
 
The "any" type is a special type which can be used to represent any type, as identified by the type i...
 
Channels are the basic communication primitives.
 
const Type * getInner() const
 
Integers are bit vectors which may be signed or unsigned and are interpreted as numbers.
 
Root class of the ESI type system.
 
std::unique_ptr< OperationPass< ModuleOp > > createESIBuildManifestPass()
 
StringAttr getName(ArrayAttr names, size_t idx)
Return the name at the specified index of the ArrayAttr or null if it cannot be determined.
 
evaluator::ObjectValue Object
 
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.