CIRCT  20.0.0git
Manifest.cpp
Go to the documentation of this file.
1 //===- Manifest.cpp - Metadata on the accelerator -------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // DO NOT EDIT!
10 // This file is distributed as part of an ESI package. The source for this file
11 // should always be modified within CIRCT (lib/dialect/ESI/runtime/cpp/).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "esi/Manifest.h"
16 #include "esi/Accelerator.h"
17 #include "esi/Services.h"
18 
19 #include <nlohmann/json.hpp>
20 #include <sstream>
21 
22 using namespace ::esi;
24 
25 // This is a proxy class to the manifest JSON. It is used to avoid having to
26 // include the JSON parser in the header. Forward references don't work since
27 // nlohmann::json is a rather complex template.
28 //
29 // Plus, it allows us to hide some implementation functions from the header
30 // file.
32  friend class ::esi::Manifest;
33 
34 public:
35  Impl(Context &ctxt, const std::string &jsonManifest);
36 
37  auto at(const std::string &key) const { return manifestJson.at(key); }
38 
39  // Get the module info (if any) for the module instance in 'json'.
40  std::optional<ModuleInfo> getModInfo(const nlohmann::json &) const;
41 
42  /// Go through the "service_decls" section of the manifest and populate the
43  /// services table as appropriate.
44  void scanServiceDecls(AcceleratorConnection &, const nlohmann::json &,
45  ServiceTable &) const;
46 
47  /// Get a Service for the service specified in 'json'. Update the
48  /// activeServices table.
49  services::Service *getService(AppIDPath idPath, AcceleratorConnection &,
50  const nlohmann::json &,
51  ServiceTable &activeServices) const;
52 
53  /// Get all the services in the description of an instance. Update the active
54  /// services table.
55  std::vector<services::Service *>
56  getServices(AppIDPath idPath, AcceleratorConnection &, const nlohmann::json &,
57  ServiceTable &activeServices) const;
58 
59  /// Get the bundle ports for the instance at 'idPath' and specified in
60  /// 'instJson'. Look them up in 'activeServies'.
61  std::vector<std::unique_ptr<BundlePort>>
62  getBundlePorts(AcceleratorConnection &acc, AppIDPath idPath,
63  const ServiceTable &activeServices,
64  const nlohmann::json &instJson) const;
65 
66  /// Build the set of child instances (recursively) for the module instance
67  /// description.
68  std::vector<std::unique_ptr<Instance>>
69  getChildInstances(AppIDPath idPath, AcceleratorConnection &acc,
70  const ServiceTable &activeServices,
71  const nlohmann::json &instJson) const;
72 
73  /// Get a single child instance. Implicitly copy the active services table so
74  /// that it can be safely updated for the child's branch of the tree.
75  std::unique_ptr<Instance>
76  getChildInstance(AppIDPath idPath, AcceleratorConnection &acc,
77  ServiceTable activeServices,
78  const nlohmann::json &childJson) const;
79 
80  /// Parse all the types and populate the types table.
81  void populateTypes(const nlohmann::json &typesJson);
82 
83  /// Get the ordered list of types from the manifest.
84  const std::vector<const Type *> &getTypeTable() const { return _typeTable; }
85 
86  /// Build a dynamic API for the Accelerator connection 'acc' based on the
87  /// manifest stored herein.
88  std::unique_ptr<Accelerator>
89  buildAccelerator(AcceleratorConnection &acc) const;
90 
91  const Type *parseType(const nlohmann::json &typeJson);
92 
93  const std::map<std::string, const ModuleInfo> &getSymbolInfo() const {
94  return symbolInfoCache;
95  }
96 
97 private:
98  Context &ctxt;
99  std::vector<const Type *> _typeTable;
100 
101  std::optional<const Type *> getType(Type::ID id) const {
102  return ctxt.getType(id);
103  }
104 
105  std::any getAny(const nlohmann::json &value) const;
106  void parseModuleMetadata(ModuleInfo &info, const nlohmann::json &mod) const;
107  void parseModuleConsts(ModuleInfo &info, const nlohmann::json &mod) const;
108 
109  // The parsed json.
110  nlohmann::json manifestJson;
111  // Cache the module info for each symbol.
112  std::map<std::string, const ModuleInfo> symbolInfoCache;
113 };
114 
115 //===----------------------------------------------------------------------===//
116 // Simple JSON -> object parsers.
117 //===----------------------------------------------------------------------===//
118 
119 static std::optional<AppID> parseID(const nlohmann::json &jsonID) {
120  if (!jsonID.is_object())
121  return std::nullopt;
122  std::optional<uint32_t> idx;
123  if (jsonID.contains("index"))
124  idx = jsonID.at("index").get<uint32_t>();
125  if (jsonID.contains("name") && jsonID.size() <= 2)
126  return AppID(jsonID.at("name").get<std::string>(), idx);
127  return std::nullopt;
128 }
129 
130 static AppID parseIDChecked(const nlohmann::json &jsonID) {
131  std::optional<AppID> id = parseID(jsonID);
132  if (!id)
133  throw std::runtime_error("Malformed manifest: invalid appID");
134  return *id;
135 }
136 static AppIDPath parseIDPath(const nlohmann::json &jsonIDPath) {
137  AppIDPath ret;
138  for (auto &idJson : jsonIDPath)
139  ret.push_back(parseIDChecked(idJson));
140  return ret;
141 }
142 
143 static ServicePortDesc parseServicePort(const nlohmann::json &jsonPort) {
144  return ServicePortDesc{jsonPort.at("serviceName").get<std::string>(),
145  jsonPort.at("port").get<std::string>()};
146 }
147 
148 /// Convert the json value to a 'std::any', which can be exposed outside of this
149 /// file.
150 std::any Manifest::Impl::getAny(const nlohmann::json &value) const {
151  auto getObject = [this](const nlohmann::json &json) -> std::any {
152  std::map<std::string, std::any> ret;
153  for (auto &e : json.items())
154  ret[e.key()] = getAny(e.value());
155 
156  // If this can be converted to a constant, do so.
157  if (ret.size() != 2 || !ret.contains("type") || !ret.contains("value"))
158  return ret;
159  std::any value = ret.at("value");
160  std::any typeID = ret.at("type");
161  if (typeID.type() != typeid(std::string))
162  return ret;
163  std::optional<const Type *> type =
164  getType(std::any_cast<std::string>(type));
165  if (!type)
166  return ret;
167  // TODO: Check or guide the conversion of the value to the type based on the
168  // type.
169  return Constant{value, type};
170  };
171 
172  auto getArray = [this](const nlohmann::json &json) -> std::any {
173  std::vector<std::any> ret;
174  for (auto &e : json)
175  ret.push_back(getAny(e));
176  return ret;
177  };
178 
179  auto getValue = [&](const nlohmann::json &innerValue) -> std::any {
180  if (innerValue.is_string())
181  return innerValue.get<std::string>();
182  else if (innerValue.is_number_unsigned())
183  return innerValue.get<uint64_t>();
184  else if (innerValue.is_number_integer())
185  return innerValue.get<int64_t>();
186  else if (innerValue.is_number_float())
187  return innerValue.get<double>();
188  else if (innerValue.is_boolean())
189  return innerValue.get<bool>();
190  else if (innerValue.is_null())
191  return innerValue.get<std::nullptr_t>();
192  else if (innerValue.is_object())
193  return getObject(innerValue);
194  else if (innerValue.is_array())
195  return getArray(innerValue);
196  else
197  throw std::runtime_error("Unknown type in manifest: " +
198  innerValue.dump(2));
199  };
200 
201  std::optional<AppID> appid = parseID(value);
202  if (appid)
203  return *appid;
204  if (!value.is_object() || !value.contains("type") || !value.contains("value"))
205  return getValue(value);
206  return Constant{getValue(value.at("value")), getType(value.at("type"))};
207 }
208 
210  const nlohmann::json &mod) const {
211  for (auto &extra : mod.items())
212  if (extra.key() != "name" && extra.key() != "summary" &&
213  extra.key() != "version" && extra.key() != "repo" &&
214  extra.key() != "commitHash")
215  info.extra[extra.key()] = getAny(extra.value());
216 
217  auto value = [&](const std::string &key) -> std::optional<std::string> {
218  auto f = mod.find(key);
219  if (f == mod.end())
220  return std::nullopt;
221  return f.value();
222  };
223  info.name = value("name");
224  info.summary = value("summary");
225  info.version = value("version");
226  info.repo = value("repo");
227  info.commitHash = value("commitHash");
228 }
229 
231  const nlohmann::json &mod) const {
232  for (auto &item : mod.items()) {
233  std::any value = getAny(item.value());
234  auto *c = std::any_cast<Constant>(&value);
235  if (c)
236  info.constants[item.key()] = *c;
237  else
238  // If the value isn't a "proper" constant, present it as one with no type.
239  info.constants[item.key()] = Constant{value, std::nullopt};
240  }
241 }
242 
243 //===----------------------------------------------------------------------===//
244 // Manifest::Impl class implementation.
245 //===----------------------------------------------------------------------===//
246 
247 Manifest::Impl::Impl(Context &ctxt, const std::string &manifestStr)
248  : ctxt(ctxt) {
249  manifestJson = nlohmann::ordered_json::parse(manifestStr);
250 
251  try {
252  // Populate the types table first since anything else might need it.
253  populateTypes(manifestJson.at("types"));
254 
255  // Populate the symbol info cache.
256  for (auto &mod : manifestJson.at("modules")) {
257  ModuleInfo info;
258  if (mod.contains("symInfo"))
259  parseModuleMetadata(info, mod.at("symInfo"));
260  if (mod.contains("symConsts"))
261  parseModuleConsts(info, mod.at("symConsts"));
262  symbolInfoCache.insert(make_pair(mod.at("symbol"), info));
263  }
264  } catch (const std::exception &e) {
265  std::string msg = "malformed manifest: " + std::string(e.what());
266  if (manifestJson.at("apiVersion") == 0)
267  msg += " (schema version 0 is not considered stable)";
268  throw std::runtime_error(msg);
269  }
270 }
271 
272 std::unique_ptr<Accelerator>
273 Manifest::Impl::buildAccelerator(AcceleratorConnection &acc) const {
274  ServiceTable activeSvcs;
275 
276  // Get the initial active services table. Update it as we descend down.
277  auto svcDecls = manifestJson.at("serviceDeclarations");
278  scanServiceDecls(acc, svcDecls, activeSvcs);
279 
280  // Get the services instantiated at the top level.
281  auto designJson = manifestJson.at("design");
282  std::vector<services::Service *> services =
283  getServices({}, acc, designJson, activeSvcs);
284 
285  // Get the ports at the top level.
286  auto ports = getBundlePorts(acc, {}, activeSvcs, designJson);
287 
288  return std::make_unique<Accelerator>(
289  getModInfo(designJson),
290  getChildInstances({}, acc, activeSvcs, designJson), services, ports);
291 }
292 
293 std::optional<ModuleInfo>
294 Manifest::Impl::getModInfo(const nlohmann::json &json) const {
295  auto instOfIter = json.find("instOf");
296  if (instOfIter == json.end())
297  return std::nullopt;
298  auto f = symbolInfoCache.find(instOfIter.value());
299  if (f != symbolInfoCache.end())
300  return f->second;
301  return std::nullopt;
302 }
303 
304 void Manifest::Impl::scanServiceDecls(AcceleratorConnection &acc,
305  const nlohmann::json &svcDecls,
306  ServiceTable &activeServices) const {
307  for (auto &svcDecl : svcDecls) {
308  if (auto f = svcDecl.find("serviceName"); f != svcDecl.end()) {
309  // Get the implementation details.
310  ServiceImplDetails svcDetails;
311  for (auto &detail : svcDecl.items())
312  svcDetails[detail.key()] = getAny(detail.value());
313 
314  // Create the service.
315  services::Service::Type svcId =
316  services::ServiceRegistry::lookupServiceType(f.value());
317  auto svc = acc.getService(svcId, /*id=*/{}, /*implName=*/"",
318  /*details=*/svcDetails, /*clients=*/{});
319  if (svc)
320  activeServices[svcDecl.at("symbol")] = svc;
321  }
322  }
323 }
324 
325 std::vector<std::unique_ptr<Instance>>
326 Manifest::Impl::getChildInstances(AppIDPath idPath, AcceleratorConnection &acc,
327  const ServiceTable &activeServices,
328  const nlohmann::json &instJson) const {
329  std::vector<std::unique_ptr<Instance>> ret;
330  auto childrenIter = instJson.find("children");
331  if (childrenIter == instJson.end())
332  return ret;
333  for (auto &child : childrenIter.value())
334  ret.emplace_back(getChildInstance(idPath, acc, activeServices, child));
335  return ret;
336 }
337 
338 std::unique_ptr<Instance>
339 Manifest::Impl::getChildInstance(AppIDPath idPath, AcceleratorConnection &acc,
340  ServiceTable activeServices,
341  const nlohmann::json &child) const {
342  AppID childID = parseIDChecked(child.at("appID"));
343  idPath.push_back(childID);
344 
345  std::vector<services::Service *> services =
346  getServices(idPath, acc, child, activeServices);
347 
348  auto children = getChildInstances(idPath, acc, activeServices, child);
349  auto ports = getBundlePorts(acc, idPath, activeServices, child);
350  return std::make_unique<Instance>(parseIDChecked(child.at("appID")),
351  getModInfo(child), std::move(children),
352  services, ports);
353 }
354 
355 services::Service *
356 Manifest::Impl::getService(AppIDPath idPath, AcceleratorConnection &acc,
357  const nlohmann::json &svcJson,
358  ServiceTable &activeServices) const {
359 
360  AppID id = parseIDChecked(svcJson.at("appID"));
361  idPath.push_back(id);
362 
363  // Get all the client info, including the implementation details.
364  HWClientDetails clientDetails;
365  for (auto &client : svcJson.at("clientDetails")) {
366  HWClientDetail clientDetail;
367  for (auto &detail : client.items()) {
368  if (detail.key() == "relAppIDPath")
369  clientDetail.relPath = parseIDPath(detail.value());
370  else if (detail.key() == "servicePort")
371  clientDetail.port = parseServicePort(detail.value());
372  else if (detail.key() == "channelAssignments") {
373  for (auto &chan : detail.value().items()) {
374  ChannelAssignment chanAssign;
375  for (auto &assign : chan.value().items())
376  if (assign.key() == "type")
377  chanAssign.type = assign.value();
378  else
379  chanAssign.implOptions[assign.key()] = getAny(assign.value());
380  clientDetail.channelAssignments[chan.key()] = chanAssign;
381  }
382  } else
383  clientDetail.implOptions[detail.key()] = getAny(detail.value());
384  }
385  clientDetails.push_back(clientDetail);
386  }
387 
388  // Get the implementation details.
389  ServiceImplDetails svcDetails;
390  std::string implName;
391  std::string service;
392  for (auto &detail : svcJson.items()) {
393  if (detail.key() == "appID" || detail.key() == "clientDetails")
394  continue;
395  if (detail.key() == "serviceImplName")
396  implName = detail.value();
397  else if (detail.key() == "service")
398  service = detail.value().get<std::string>();
399  else
400  svcDetails[detail.key()] = getAny(detail.value());
401  }
402 
403  // Create the service.
404  services::Service *svc = nullptr;
405  auto activeServiceIter = activeServices.find(service);
406  if (activeServiceIter != activeServices.end()) {
407  services::Service::Type svcType =
408  services::ServiceRegistry::lookupServiceType(
409  activeServiceIter->second->getServiceSymbol());
410  svc = activeServiceIter->second->getChildService(
411  &acc, svcType, idPath, implName, svcDetails, clientDetails);
412  } else {
413  services::Service::Type svcType =
414  services::ServiceRegistry::lookupServiceType(service);
415  svc = acc.getService(svcType, idPath, implName, svcDetails, clientDetails);
416  }
417 
418  if (svc)
419  // Update the active services table.
420  activeServices[service] = svc;
421  return svc;
422 }
423 
424 std::vector<services::Service *>
425 Manifest::Impl::getServices(AppIDPath idPath, AcceleratorConnection &acc,
426  const nlohmann::json &svcsJson,
427  ServiceTable &activeServices) const {
428  std::vector<services::Service *> ret;
429  auto svcsIter = svcsJson.find("services");
430  if (svcsIter == svcsJson.end())
431  return ret;
432 
433  for (auto &svc : svcsIter.value())
434  ret.emplace_back(getService(idPath, acc, svc, activeServices));
435  return ret;
436 }
437 
438 std::vector<std::unique_ptr<BundlePort>>
439 Manifest::Impl::getBundlePorts(AcceleratorConnection &acc, AppIDPath idPath,
440  const ServiceTable &activeServices,
441  const nlohmann::json &instJson) const {
442  std::vector<std::unique_ptr<BundlePort>> ret;
443  auto clientPortsIter = instJson.find("clientPorts");
444  if (clientPortsIter == instJson.end())
445  return ret;
446 
447  for (auto &content : clientPortsIter.value()) {
448  // Lookup the requested service in the active services table.
449  std::string serviceName = "";
450  if (auto f = content.find("servicePort"); f != content.end())
451  serviceName = parseServicePort(f.value()).name;
452  auto svcIter = activeServices.find(serviceName);
453  if (svcIter == activeServices.end()) {
454  // If a specific service isn't found, search for the default service
455  // (typically provided by a BSP).
456  if (svcIter = activeServices.find(""); svcIter == activeServices.end())
457  throw std::runtime_error(
458  "Malformed manifest: could not find active service '" +
459  serviceName + "'");
460  }
461  services::Service *svc = svcIter->second;
462 
463  std::string typeName = content.at("typeID");
464  auto type = getType(typeName);
465  if (!type)
466  throw std::runtime_error(
467  "Malformed manifest: could not find port type '" + typeName + "'");
468  const BundleType *bundleType = dynamic_cast<const BundleType *>(*type);
469  if (!bundleType)
470  throw std::runtime_error("Malformed manifest: type '" + typeName +
471  "' is not a bundle type");
472 
473  idPath.push_back(parseIDChecked(content.at("appID")));
474  std::map<std::string, ChannelPort &> portChannels =
475  acc.requestChannelsFor(idPath, bundleType, activeServices);
476 
477  services::ServicePort *svcPort =
478  svc->getPort(idPath, bundleType, portChannels, acc);
479  if (svcPort)
480  ret.emplace_back(svcPort);
481  else
482  ret.emplace_back(new BundlePort(idPath.back(), portChannels));
483  // Since we share idPath between iterations, pop the last element before the
484  // next iteration.
485  idPath.pop_back();
486  }
487  return ret;
488 }
489 
490 namespace {
491 const Type *parseType(const nlohmann::json &typeJson, Context &ctxt);
492 
493 BundleType *parseBundleType(const nlohmann::json &typeJson, Context &cache) {
494  assert(typeJson.at("mnemonic") == "bundle");
495 
496  std::vector<std::tuple<std::string, BundleType::Direction, const Type *>>
497  channels;
498  for (auto &chanJson : typeJson["channels"]) {
499  std::string dirStr = chanJson.at("direction");
501  if (dirStr == "to")
502  dir = BundleType::Direction::To;
503  else if (dirStr == "from")
504  dir = BundleType::Direction::From;
505  else
506  throw std::runtime_error("Malformed manifest: unknown direction '" +
507  dirStr + "'");
508  channels.emplace_back(chanJson.at("name"), dir,
509  parseType(chanJson["type"], cache));
510  }
511  return new BundleType(typeJson.at("id"), channels);
512 }
513 
514 ChannelType *parseChannelType(const nlohmann::json &typeJson, Context &cache) {
515  assert(typeJson.at("mnemonic") == "channel");
516  return new ChannelType(typeJson.at("id"),
517  parseType(typeJson.at("inner"), cache));
518 }
519 
520 Type *parseInt(const nlohmann::json &typeJson, Context &cache) {
521  assert(typeJson.at("mnemonic") == "int");
522  std::string sign = typeJson.at("signedness");
523  uint64_t width = typeJson.at("hwBitwidth");
524  Type::ID id = typeJson.at("id");
525 
526  if (sign == "signed")
527  return new SIntType(id, width);
528  else if (sign == "unsigned")
529  return new UIntType(id, width);
530  else if (sign == "signless" && width == 0)
531  // By convention, a zero-width signless integer is a void type.
532  return new VoidType(id);
533  else if (sign == "signless" && width > 0)
534  return new BitsType(id, width);
535  else
536  throw std::runtime_error("Malformed manifest: unknown sign '" + sign + "'");
537 }
538 
539 StructType *parseStruct(const nlohmann::json &typeJson, Context &cache) {
540  assert(typeJson.at("mnemonic") == "struct");
541  std::vector<std::pair<std::string, const Type *>> fields;
542  for (auto &fieldJson : typeJson["fields"])
543  fields.emplace_back(fieldJson.at("name"),
544  parseType(fieldJson["type"], cache));
545  return new StructType(typeJson.at("id"), fields);
546 }
547 
548 ArrayType *parseArray(const nlohmann::json &typeJson, Context &cache) {
549  assert(typeJson.at("mnemonic") == "array");
550  uint64_t size = typeJson.at("size");
551  return new ArrayType(typeJson.at("id"),
552  parseType(typeJson.at("element"), cache), size);
553 }
554 
555 using TypeParser = std::function<Type *(const nlohmann::json &, Context &)>;
556 const std::map<std::string_view, TypeParser> typeParsers = {
557  {"bundle", parseBundleType},
558  {"channel", parseChannelType},
559  {"std::any", [](const nlohmann::json &typeJson,
560  Context &cache) { return new AnyType(typeJson.at("id")); }},
561  {"int", parseInt},
562  {"struct", parseStruct},
563  {"array", parseArray},
564 
565 };
566 
567 // Parse a type if it doesn't already exist in the cache.
568 const Type *parseType(const nlohmann::json &typeJson, Context &cache) {
569  std::string id;
570  if (typeJson.is_string())
571  id = typeJson.get<std::string>();
572  else
573  id = typeJson.at("id");
574  if (std::optional<const Type *> t = cache.getType(id))
575  return *t;
576  if (typeJson.is_string())
577  throw std::runtime_error("malformed manifest: unknown type '" + id + "'");
578 
579  Type *t;
580  std::string mnemonic = typeJson.at("mnemonic");
581  auto f = typeParsers.find(mnemonic);
582  if (f != typeParsers.end())
583  t = f->second(typeJson, cache);
584  else
585  // Types we don't know about are opaque.
586  t = new Type(id);
587 
588  // Insert into the cache.
589  cache.registerType(t);
590  return t;
591 }
592 } // namespace
593 
594 const Type *Manifest::Impl::parseType(const nlohmann::json &typeJson) {
595  return ::parseType(typeJson, ctxt);
596 }
597 
598 void Manifest::Impl::populateTypes(const nlohmann::json &typesJson) {
599  for (auto &typeJson : typesJson)
600  _typeTable.push_back(parseType(typeJson));
601 }
602 
603 //===----------------------------------------------------------------------===//
604 // Manifest class implementation.
605 //===----------------------------------------------------------------------===//
606 
607 Manifest::Manifest(Context &ctxt, const std::string &jsonManifest)
608  : impl(new Impl(ctxt, jsonManifest)) {}
609 
610 Manifest::~Manifest() { delete impl; }
611 
612 uint32_t Manifest::getApiVersion() const {
613  return impl->at("apiVersion").get<uint32_t>();
614 }
615 
616 std::vector<ModuleInfo> Manifest::getModuleInfos() const {
617  std::vector<ModuleInfo> ret;
618  for (auto &[symbol, info] : impl->getSymbolInfo())
619  ret.push_back(info);
620  return ret;
621 }
622 
623 Accelerator *Manifest::buildAccelerator(AcceleratorConnection &acc) const {
624  try {
625  return acc.takeOwnership(impl->buildAccelerator(acc));
626  } catch (const std::exception &e) {
627  std::string msg = "malformed manifest: " + std::string(e.what());
628  if (getApiVersion() == 0)
629  msg += " (schema version 0 is not considered stable)";
630  throw std::runtime_error(msg);
631  }
632 }
633 
634 const std::vector<const Type *> &Manifest::getTypeTable() const {
635  return impl->getTypeTable();
636 }
637 
638 //===----------------------------------------------------------------------===//
639 // POCO helpers.
640 //===----------------------------------------------------------------------===//
641 
642 // Print a module info, including the extra metadata.
643 std::ostream &operator<<(std::ostream &os, const ModuleInfo &m) {
644  auto printAny = [&os](std::any a) {
645  if (auto *c = std::any_cast<Constant>(&a))
646  a = std::any_cast<Constant>(a).value;
647 
648  const std::type_info &t = a.type();
649  if (t == typeid(std::string))
650  os << std::any_cast<std::string>(a);
651  else if (t == typeid(int64_t))
652  os << std::any_cast<int64_t>(a);
653  else if (t == typeid(uint64_t))
654  os << std::any_cast<uint64_t>(a);
655  else if (t == typeid(double))
656  os << std::any_cast<double>(a);
657  else if (t == typeid(bool))
658  os << std::any_cast<bool>(a);
659  else if (t == typeid(std::nullptr_t))
660  os << "null";
661  else
662  os << "unknown";
663  };
664 
665  if (m.name)
666  os << *m.name << " ";
667  if (m.version)
668  os << *m.version << " ";
669  if (m.repo || m.commitHash) {
670  os << "(";
671  if (m.repo)
672  os << *m.repo;
673  if (m.commitHash)
674  os << "@" << *m.commitHash;
675  os << ")";
676  }
677  if (m.summary)
678  os << ": " << *m.summary;
679  os << "\n";
680 
681  if (!m.constants.empty()) {
682  os << " Constants:\n";
683  for (auto &e : m.constants) {
684  os << " " << e.first << ": ";
685  printAny(e.second);
686  os << "\n";
687  }
688  }
689 
690  if (!m.extra.empty()) {
691  os << " Extra metadata:\n";
692  for (auto &e : m.extra) {
693  os << " " << e.first << ": ";
694  printAny(e.second);
695  os << "\n";
696  }
697  }
698  return os;
699 }
700 
701 namespace esi {
703  AppIDPath ret = *this;
704  ret.insert(ret.end(), b.begin(), b.end());
705  return ret;
706 }
707 
708 std::string AppIDPath::toStr() const {
709  std::ostringstream os;
710  os << *this;
711  return os.str();
712 }
713 
714 bool operator<(const AppID &a, const AppID &b) {
715  if (a.name != b.name)
716  return a.name < b.name;
717  return a.idx < b.idx;
718 }
719 bool operator<(const AppIDPath &a, const AppIDPath &b) {
720  if (a.size() != b.size())
721  return a.size() < b.size();
722  for (size_t i = 0, e = a.size(); i < e; ++i)
723  if (a[i] != b[i])
724  return a[i] < b[i];
725  return false;
726 }
727 } // namespace esi
728 
729 std::ostream &operator<<(std::ostream &os, const AppID &id) {
730  os << id.name;
731  if (id.idx)
732  os << "[" << *id.idx << "]";
733  return os;
734 }
735 std::ostream &operator<<(std::ostream &os, const AppIDPath &path) {
736  for (size_t i = 0, e = path.size(); i < e; ++i) {
737  if (i > 0)
738  os << '.';
739  os << path[i];
740  }
741  return os;
742 }
assert(baseType &&"element must be base type")
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
AcceleratorConnection::ServiceTable ServiceTable
Definition: Manifest.cpp:23
static AppIDPath parseIDPath(const nlohmann::json &jsonIDPath)
Definition: Manifest.cpp:136
std::ostream & operator<<(std::ostream &os, const ModuleInfo &m)
Definition: Manifest.cpp:643
static AppID parseIDChecked(const nlohmann::json &jsonID)
Definition: Manifest.cpp:130
static std::optional< AppID > parseID(const nlohmann::json &jsonID)
Definition: Manifest.cpp:119
static ServicePortDesc parseServicePort(const nlohmann::json &jsonPort)
Definition: Manifest.cpp:143
Impl(Context &ctxt, const std::string &jsonManifest)
Definition: Manifest.cpp:247
const Type * parseType(const nlohmann::json &typeJson)
Definition: Manifest.cpp:594
auto at(const std::string &key) const
Definition: Manifest.cpp:37
void populateTypes(const nlohmann::json &typesJson)
Parse all the types and populate the types table.
Definition: Manifest.cpp:598
std::optional< ModuleInfo > getModInfo(const nlohmann::json &) const
Definition: Manifest.cpp:294
std::vector< std::unique_ptr< BundlePort > > getBundlePorts(AcceleratorConnection &acc, AppIDPath idPath, const ServiceTable &activeServices, const nlohmann::json &instJson) const
Get the bundle ports for the instance at 'idPath' and specified in 'instJson'.
Definition: Manifest.cpp:439
std::vector< std::unique_ptr< Instance > > getChildInstances(AppIDPath idPath, AcceleratorConnection &acc, const ServiceTable &activeServices, const nlohmann::json &instJson) const
Build the set of child instances (recursively) for the module instance description.
Definition: Manifest.cpp:326
nlohmann::json manifestJson
Definition: Manifest.cpp:110
const std::vector< const Type * > & getTypeTable() const
Get the ordered list of types from the manifest.
Definition: Manifest.cpp:84
std::vector< services::Service * > getServices(AppIDPath idPath, AcceleratorConnection &, const nlohmann::json &, ServiceTable &activeServices) const
Get all the services in the description of an instance.
Definition: Manifest.cpp:425
std::map< std::string, const ModuleInfo > symbolInfoCache
Definition: Manifest.cpp:112
std::any getAny(const nlohmann::json &value) const
Convert the json value to a 'std::any', which can be exposed outside of this file.
Definition: Manifest.cpp:150
void parseModuleMetadata(ModuleInfo &info, const nlohmann::json &mod) const
Definition: Manifest.cpp:209
std::unique_ptr< Accelerator > buildAccelerator(AcceleratorConnection &acc) const
Build a dynamic API for the Accelerator connection 'acc' based on the manifest stored herein.
Definition: Manifest.cpp:273
void parseModuleConsts(ModuleInfo &info, const nlohmann::json &mod) const
Definition: Manifest.cpp:230
services::Service * getService(AppIDPath idPath, AcceleratorConnection &, const nlohmann::json &, ServiceTable &activeServices) const
Get a Service for the service specified in 'json'.
Definition: Manifest.cpp:356
void scanServiceDecls(AcceleratorConnection &, const nlohmann::json &, ServiceTable &) const
Go through the "service_decls" section of the manifest and populate the services table as appropriate...
Definition: Manifest.cpp:304
std::optional< const Type * > getType(Type::ID id) const
Definition: Manifest.cpp:101
const std::map< std::string, const ModuleInfo > & getSymbolInfo() const
Definition: Manifest.cpp:93
Context & ctxt
Definition: Manifest.cpp:98
std::vector< const Type * > _typeTable
Definition: Manifest.cpp:99
std::unique_ptr< Instance > getChildInstance(AppIDPath idPath, AcceleratorConnection &acc, ServiceTable activeServices, const nlohmann::json &childJson) const
Get a single child instance.
Definition: Manifest.cpp:339
Direction
The direction of a Component or Cell port.
Definition: CalyxOps.h:76
bool operator<(const DictEntry &entry, const DictEntry &other)
Definition: RTGTypes.h:25
FVInt operator+(uint64_t a, const FVInt &b)
Definition: FVInt.h:635
Definition: esi.py:1
std::map< std::string, std::any > ServiceImplDetails
Definition: Common.h:98
std::vector< HWClientDetail > HWClientDetails
Definition: Common.h:97
std::string name
Definition: Common.h:35
std::optional< uint32_t > idx
Definition: Common.h:36