20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-Wcovered-switch-default"
23#include <nlohmann/json.hpp>
25#pragma GCC diagnostic pop
38 friend class ::esi::Manifest;
46 std::optional<ModuleInfo>
getModInfo(
const nlohmann::json &)
const;
51 ServiceTable &)
const;
53 void createEngine(AcceleratorConnection &, AppIDPath appID,
54 const nlohmann::json &)
const;
59 services::Service *
getService(AppIDPath idPath, AcceleratorConnection &,
60 const nlohmann::json &,
61 ServiceTable &activeServices,
62 bool isEngine =
false)
const;
66 std::vector<services::Service *>
67 getServices(AppIDPath idPath, AcceleratorConnection &,
const nlohmann::json &,
68 ServiceTable &activeServices)
const;
72 std::vector<std::unique_ptr<BundlePort>>
74 const ServiceTable &activeServices,
75 const nlohmann::json &instJson)
const;
79 std::vector<std::unique_ptr<Instance>>
81 const ServiceTable &activeServices,
82 const nlohmann::json &instJson)
const;
86 std::unique_ptr<Instance>
88 ServiceTable activeServices,
89 const nlohmann::json &childJson)
const;
99 std::unique_ptr<Accelerator>
102 const Type *
parseType(
const nlohmann::json &typeJson);
112 std::optional<const Type *>
getType(Type::ID
id)
const {
113 return ctxt.getType(
id);
116 std::any
getAny(
const nlohmann::json &value)
const;
130static std::optional<AppID>
parseID(
const nlohmann::json &jsonID) {
131 if (!jsonID.is_object())
133 std::optional<uint32_t> idx;
134 if (jsonID.contains(
"index"))
135 idx = jsonID.at(
"index").get<uint32_t>();
136 if (jsonID.contains(
"name") && jsonID.size() <= 2)
137 return AppID(jsonID.at(
"name").get<std::string>(), idx);
142 std::optional<AppID>
id =
parseID(jsonID);
144 throw std::runtime_error(
"Malformed manifest: invalid appID");
149 for (
auto &idJson : jsonIDPath)
155 return ServicePortDesc{jsonPort.at(
"serviceName").get<std::string>(),
156 jsonPort.at(
"port").get<std::string>()};
162 auto getObject = [
this](
const nlohmann::json &
json) -> std::any {
163 std::map<std::string, std::any> ret;
164 for (
auto &e :
json.items())
165 ret[e.key()] =
getAny(e.value());
168 if (ret.size() != 2 || !ret.contains(
"type") || !ret.contains(
"value"))
170 std::any value = ret.at(
"value");
171 std::any typeID = ret.at(
"type");
172 if (typeID.type() !=
typeid(std::string))
174 std::optional<const Type *> type =
175 getType(std::any_cast<std::string>(type));
180 return Constant{value, type};
183 auto getArray = [
this](
const nlohmann::json &
json) -> std::any {
184 std::vector<std::any> ret;
190 auto getValue = [&](
const nlohmann::json &innerValue) -> std::any {
191 if (innerValue.is_string())
192 return innerValue.get<std::string>();
193 else if (innerValue.is_number_unsigned())
194 return innerValue.get<uint64_t>();
195 else if (innerValue.is_number_integer())
196 return innerValue.get<int64_t>();
197 else if (innerValue.is_number_float())
198 return innerValue.get<
double>();
199 else if (innerValue.is_boolean())
200 return innerValue.get<
bool>();
201 else if (innerValue.is_null())
202 return innerValue.get<std::nullptr_t>();
203 else if (innerValue.is_object())
204 return getObject(innerValue);
205 else if (innerValue.is_array())
206 return getArray(innerValue);
208 throw std::runtime_error(
"Unknown type in manifest: " +
212 std::optional<AppID> appid =
parseID(value);
215 if (!value.is_object() || !value.contains(
"type") || !value.contains(
"value"))
216 return getValue(value);
217 return Constant{getValue(value.at(
"value")),
getType(value.at(
"type"))};
221 const nlohmann::json &mod)
const {
222 for (
auto &extra : mod.items())
223 if (extra.key() !=
"name" && extra.key() !=
"summary" &&
224 extra.key() !=
"version" && extra.key() !=
"repo" &&
225 extra.key() !=
"commitHash")
226 info.extra[extra.key()] = getAny(extra.value());
228 auto value = [&](
const std::string &key) -> std::optional<std::string> {
229 auto f = mod.find(key);
234 info.name = value(
"name");
235 info.summary = value(
"summary");
236 info.version = value(
"version");
237 info.repo = value(
"repo");
238 info.commitHash = value(
"commitHash");
242 const nlohmann::json &mod)
const {
243 for (
auto &item : mod.items()) {
244 std::any value = getAny(item.value());
245 auto *c = std::any_cast<Constant>(&value);
247 info.constants[item.key()] = *c;
250 info.constants[item.key()] = Constant{value, std::nullopt};
260 manifestJson = nlohmann::ordered_json::parse(manifestStr);
263 if (!version.is_number_unsigned() || version != ExpectedVersionNumber)
264 throw std::runtime_error(
"Unsupported ESI ABI version: " + version.dump() +
266 std::to_string(ExpectedVersionNumber) +
")");
275 if (mod.contains(
"symInfo"))
277 if (mod.contains(
"symConsts"))
281 }
catch (
const std::exception &e) {
282 std::string msg =
"malformed manifest: " + std::string(e.what());
283 throw std::runtime_error(msg);
287std::unique_ptr<Accelerator>
289 ServiceTable activeSvcs;
291 auto designJson = manifestJson.at(
"design");
295 auto enginesIter = designJson.find(
"engines");
296 if (enginesIter != designJson.end())
297 for (
auto &engineDesc : enginesIter.value())
298 createEngine(acc, {}, engineDesc);
301 auto svcDecls = manifestJson.at(
"serviceDeclarations");
302 scanServiceDecls(acc, svcDecls, activeSvcs);
305 std::vector<services::Service *> services =
306 getServices({}, acc, designJson, activeSvcs);
309 auto ports = getBundlePorts(acc, {}, activeSvcs, designJson);
311 return std::make_unique<Accelerator>(
312 getModInfo(designJson),
313 getChildInstances({}, acc, activeSvcs, designJson), services,
317std::optional<ModuleInfo>
319 auto instOfIter =
json.find(
"instanceOf");
320 if (instOfIter ==
json.end())
322 auto f = symbolInfoCache.find(instOfIter.value());
323 if (f != symbolInfoCache.end())
331 const nlohmann::json &eng)
const {
333 getService(idPath, acc, eng, dummy,
true);
337 const nlohmann::json &svcDecls,
338 ServiceTable &activeServices)
const {
339 for (
auto &svcDecl : svcDecls) {
341 ServiceImplDetails svcDetails;
342 for (
auto &
detail : svcDecl.items())
346 auto serviceNameIter = svcDecl.find(
"serviceName");
347 std::string serviceName;
348 if (serviceNameIter != svcDecl.end())
349 serviceName = serviceNameIter.value();
350 services::Service::Type svcId =
351 services::ServiceRegistry::lookupServiceType(serviceName);
352 auto svc = acc.getService(svcId, {},
"",
355 activeServices[svcDecl.at(
"symbol")] = svc;
359std::vector<std::unique_ptr<Instance>>
361 const ServiceTable &activeServices,
362 const nlohmann::json &instJson)
const {
363 std::vector<std::unique_ptr<Instance>> ret;
364 auto childrenIter = instJson.find(
"children");
365 if (childrenIter == instJson.end())
367 for (
auto &child : childrenIter.value())
368 ret.emplace_back(getChildInstance(idPath, acc, activeServices, child));
372std::unique_ptr<Instance>
374 ServiceTable activeServices,
375 const nlohmann::json &child)
const {
377 idPath.push_back(childID);
379 std::vector<services::Service *> services =
380 getServices(idPath, acc, child, activeServices);
382 auto children = getChildInstances(idPath, acc, activeServices, child);
383 auto ports = getBundlePorts(acc, idPath, activeServices, child);
384 return std::make_unique<Instance>(
parseIDChecked(child.at(
"appID")),
385 getModInfo(child), std::move(children),
386 services, std::move(ports));
390 AcceleratorConnection &acc,
391 const nlohmann::json &svcJson,
392 ServiceTable &activeServices,
393 bool isEngine)
const {
396 idPath.push_back(
id);
399 HWClientDetails clientDetails;
400 for (
auto &client : svcJson.at(
"clientDetails")) {
401 HWClientDetail clientDetail;
402 for (
auto &
detail : client.items()) {
403 if (
detail.key() ==
"relAppIDPath")
405 else if (
detail.key() ==
"servicePort")
407 else if (
detail.key() ==
"channelAssignments") {
408 for (
auto &chan :
detail.value().items()) {
409 ChannelAssignment chanAssign;
410 for (
auto &assign : chan.value().items())
411 if (assign.key() ==
"type")
412 chanAssign.type = assign.value();
414 chanAssign.implOptions[assign.key()] = getAny(assign.value());
415 clientDetail.channelAssignments[chan.key()] = chanAssign;
418 clientDetail.implOptions[
detail.key()] = getAny(
detail.value());
420 clientDetails.push_back(clientDetail);
424 ServiceImplDetails svcDetails;
425 std::string implName;
427 for (
auto &
detail : svcJson.items()) {
428 if (
detail.key() ==
"appID" ||
detail.key() ==
"clientDetails")
430 if (
detail.key() ==
"serviceImplName")
431 implName =
detail.value();
432 else if (
detail.key() ==
"service")
433 service =
detail.value().get<std::string>();
439 services::Service *svc =
nullptr;
440 auto activeServiceIter = activeServices.find(service);
441 if (activeServiceIter != activeServices.end()) {
442 services::Service::Type svcType =
443 services::ServiceRegistry::lookupServiceType(
444 activeServiceIter->second->getServiceSymbol());
445 svc = activeServiceIter->second->getChildService(svcType, idPath, implName,
446 svcDetails, clientDetails);
448 services::Service::Type svcType =
449 services::ServiceRegistry::lookupServiceType(service);
451 acc.createEngine(implName, idPath, svcDetails, clientDetails);
454 acc.getService(svcType, idPath, implName, svcDetails, clientDetails);
459 activeServices[service] = svc;
463std::vector<services::Service *>
465 const nlohmann::json &svcsJson,
466 ServiceTable &activeServices)
const {
467 std::vector<services::Service *> ret;
468 auto svcsIter = svcsJson.find(
"services");
469 if (svcsIter == svcsJson.end())
472 for (
auto &svc : svcsIter.value())
473 ret.emplace_back(getService(idPath, acc, svc, activeServices));
477std::vector<std::unique_ptr<BundlePort>>
479 const ServiceTable &activeServices,
480 const nlohmann::json &instJson)
const {
481 std::vector<std::unique_ptr<BundlePort>> ret;
482 auto clientPortsIter = instJson.find(
"clientPorts");
483 if (clientPortsIter == instJson.end())
486 for (
auto &content : clientPortsIter.value()) {
488 std::string serviceName =
"";
489 if (
auto f = content.find(
"servicePort"); f != content.end())
491 auto svcIter = activeServices.find(serviceName);
492 if (svcIter == activeServices.end()) {
495 if (svcIter = activeServices.find(
""); svcIter == activeServices.end())
496 throw std::runtime_error(
497 "Malformed manifest: could not find active service '" +
500 services::Service *svc = svcIter->second;
502 std::string typeName = content.at(
"typeID");
503 auto type = getType(typeName);
505 throw std::runtime_error(
506 "Malformed manifest: could not find port type '" + typeName +
"'");
507 const BundleType *bundleType =
dynamic_cast<const BundleType *
>(*type);
509 throw std::runtime_error(
"Malformed manifest: type '" + typeName +
510 "' is not a bundle type");
514 BundlePort *svcPort = svc->getPort(idPath, bundleType);
516 ret.emplace_back(svcPort);
527BundleType *parseBundleType(
const nlohmann::json &typeJson,
Context &cache) {
528 assert(typeJson.at(
"mnemonic") ==
"bundle");
530 std::vector<std::tuple<std::string, BundleType::Direction, const Type *>>
532 for (
auto &chanJson : typeJson[
"channels"]) {
533 std::string dirStr = chanJson.at(
"direction");
534 BundleType::Direction dir;
536 dir = BundleType::Direction::To;
537 else if (dirStr ==
"from")
538 dir = BundleType::Direction::From;
540 throw std::runtime_error(
"Malformed manifest: unknown direction '" +
542 channels.emplace_back(chanJson.at(
"name"), dir,
545 return new BundleType(typeJson.at(
"id"), channels);
548ChannelType *parseChannelType(
const nlohmann::json &typeJson,
Context &cache) {
549 assert(typeJson.at(
"mnemonic") ==
"channel");
550 return new ChannelType(typeJson.at(
"id"),
554Type *parseInt(
const nlohmann::json &typeJson,
Context &cache) {
555 assert(typeJson.at(
"mnemonic") ==
"int");
556 std::string sign = typeJson.at(
"signedness");
557 uint64_t width = typeJson.at(
"hwBitwidth");
558 Type::ID
id = typeJson.at(
"id");
560 if (sign ==
"signed")
561 return new SIntType(
id, width);
562 else if (sign ==
"unsigned")
563 return new UIntType(
id, width);
564 else if (sign ==
"signless" && width == 0)
566 return new VoidType(
id);
567 else if (sign ==
"signless" && width > 0)
568 return new BitsType(
id, width);
570 throw std::runtime_error(
"Malformed manifest: unknown sign '" + sign +
"'");
573StructType *parseStruct(
const nlohmann::json &typeJson,
Context &cache) {
574 assert(typeJson.at(
"mnemonic") ==
"struct");
575 std::vector<std::pair<std::string, const Type *>> fields;
576 for (
auto &fieldJson : typeJson[
"fields"])
577 fields.emplace_back(fieldJson.at(
"name"),
579 return new StructType(typeJson.at(
"id"), fields);
582UnionType *parseUnion(
const nlohmann::json &typeJson,
Context &cache) {
583 assert(typeJson.at(
"mnemonic") ==
"union");
584 std::vector<std::pair<std::string, const Type *>> fields;
585 for (
auto &fieldJson : typeJson[
"fields"])
586 fields.emplace_back(fieldJson.at(
"name"),
588 return new UnionType(typeJson.at(
"id"), fields);
591ArrayType *parseArray(
const nlohmann::json &typeJson,
Context &cache) {
592 assert(typeJson.at(
"mnemonic") ==
"array");
593 uint64_t size = typeJson.at(
"size");
594 return new ArrayType(typeJson.at(
"id"),
595 parseType(typeJson.at(
"element"), cache), size);
598WindowType *parseWindow(
const nlohmann::json &typeJson,
Context &cache) {
599 assert(typeJson.at(
"mnemonic") ==
"window");
600 std::string name = typeJson.at(
"name");
601 const Type *intoType =
parseType(typeJson.at(
"into"), cache);
602 const Type *loweredType =
parseType(typeJson.at(
"loweredType"), cache);
605 std::vector<WindowType::Frame> frames;
606 for (
auto &frameJson : typeJson.at(
"frames")) {
607 WindowType::Frame frame;
608 frame.name = frameJson.at(
"name");
609 for (
auto &fieldJson : frameJson.at(
"fields")) {
610 WindowType::Field field;
611 field.name = fieldJson.at(
"name");
612 if (fieldJson.contains(
"numItems"))
613 field.numItems = fieldJson.at(
"numItems");
614 if (fieldJson.contains(
"bulkCountWidth"))
615 field.bulkCountWidth = fieldJson.at(
"bulkCountWidth");
616 frame.fields.push_back(field);
618 frames.push_back(frame);
621 return new WindowType(typeJson.at(
"id"), name, intoType, loweredType, frames);
624ListType *parseList(
const nlohmann::json &typeJson,
Context &cache) {
625 assert(typeJson.at(
"mnemonic") ==
"list");
626 return new ListType(typeJson.at(
"id"),
627 parseType(typeJson.at(
"element"), cache));
630TypeAliasType *parseTypeAlias(
const nlohmann::json &typeJson,
Context &cache) {
631 assert(typeJson.at(
"mnemonic") ==
"alias");
632 std::string
id = typeJson.at(
"id");
633 std::string name = typeJson.value(
"name",
"");
636 if (typeJson.contains(
"inner"))
639 throw std::runtime_error(
"typealias missing inner type");
644 return new TypeAliasType(
id, name, innerType);
647using TypeParser = std::function<Type *(
const nlohmann::json &,
Context &)>;
648const std::map<std::string_view, TypeParser> typeParsers = {
649 {
"bundle", parseBundleType},
650 {
"channel", parseChannelType},
651 {
"std::any", [](
const nlohmann::json &typeJson,
652 Context &cache) {
return new AnyType(typeJson.at(
"id")); }},
654 {
"alias", parseTypeAlias},
655 {
"struct", parseStruct},
656 {
"union", parseUnion},
657 {
"array", parseArray},
658 {
"window", parseWindow},
666 if (typeJson.is_string())
667 id = typeJson.get<std::string>();
669 id = typeJson.at(
"id");
670 if (std::optional<const Type *> t = cache.getType(
id))
672 if (typeJson.is_string())
673 throw std::runtime_error(
"malformed manifest: unknown type '" +
id +
"'");
676 std::string mnemonic = typeJson.at(
"mnemonic");
677 auto f = typeParsers.find(mnemonic);
678 if (f != typeParsers.end())
679 t = f->second(typeJson, cache);
686 if (typeJson.contains(
"hwBitwidth"))
687 t->setHWBitwidth(typeJson.at(
"hwBitwidth").get<std::ptrdiff_t>());
690 cache.registerType(t);
696 return ::parseType(typeJson, ctxt);
700 for (
auto &typeJson : typesJson)
701 _typeTable.push_back(
parseType(typeJson));
708Manifest::Manifest(
Context &ctxt,
const std::string &jsonManifest)
709 : impl(new
Impl(ctxt, jsonManifest)) {}
711Manifest::~Manifest() {
delete impl; }
713uint32_t Manifest::getApiVersion()
const {
714 return impl->at(
"apiVersion").get<uint32_t>();
717std::vector<ModuleInfo> Manifest::getModuleInfos()
const {
718 std::vector<ModuleInfo> ret;
719 for (
auto &[symbol, info] : impl->getSymbolInfo())
724Accelerator *Manifest::buildAccelerator(AcceleratorConnection &acc)
const {
726 return acc.takeOwnership(impl->buildAccelerator(acc));
727 }
catch (
const std::exception &e) {
728 std::string msg =
"malformed manifest: " + std::string(e.what());
729 throw std::runtime_error(msg);
733const std::vector<const Type *> &Manifest::getTypeTable()
const {
734 return impl->getTypeTable();
743 auto printAny = [&os](std::any a) {
744 if (std::any_cast<Constant>(&a))
745 a = std::any_cast<Constant>(a).value;
747 const std::type_info &t = a.type();
748 if (t ==
typeid(std::string))
749 os << std::any_cast<std::string>(a);
750 else if (t ==
typeid(int64_t))
751 os << std::any_cast<int64_t>(a);
752 else if (t ==
typeid(uint64_t))
753 os << std::any_cast<uint64_t>(a);
754 else if (t ==
typeid(
double))
755 os << std::any_cast<double>(a);
756 else if (t ==
typeid(
bool))
757 os << std::any_cast<bool>(a);
758 else if (t ==
typeid(std::nullptr_t))
765 os << *m.name <<
" ";
767 os << *m.version <<
" ";
768 if (m.name || m.version)
770 if (m.repo || m.commitHash) {
771 os <<
" Version control: ";
775 os <<
"@" << *m.commitHash;
779 os <<
" " << *m.summary;
782 if (!m.constants.empty()) {
783 os <<
" Constants:\n";
784 for (
auto &e : m.constants) {
785 os <<
" " << e.first <<
": ";
791 if (!m.extra.empty()) {
792 os <<
" Extra metadata:\n";
793 for (
auto &e : m.extra) {
794 os <<
" " << e.first <<
": ";
805 ret.insert(ret.end(), b.begin(), b.end());
816std::string AppIDPath::toStr()
const {
817 std::ostringstream os;
828 if (a.size() != b.size())
829 return a.size() < b.size();
830 for (
size_t i = 0, e = a.size(); i < e; ++i)
839 os <<
"[" << *
id.idx <<
"]";
843 for (
size_t i = 0, e = path.size(); i < e; ++i) {
assert(baseType &&"element must be base type")
static ParseResult parseType(Type &result, StringRef name, AsmParser &parser)
Parse a type defined by this dialect.
static std::optional< AppID > parseID(const nlohmann::json &jsonID)
static AppIDPath parseIDPath(const nlohmann::json &jsonIDPath)
static AppID parseIDChecked(const nlohmann::json &jsonID)
static ServicePortDesc parseServicePort(const nlohmann::json &jsonPort)
nlohmann::json json
Get a JSON representation of a type.
static llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const bool a)
This class provides a thread-safe interface to access the analysis results.
const std::vector< const Type * > & getTypeTable() const
Get the ordered list of types from the manifest.
std::optional< const Type * > getType(Type::ID id) const
const Type * parseType(const nlohmann::json &typeJson)
auto at(const std::string &key) const
void populateTypes(const nlohmann::json &typesJson)
Parse all the types and populate the types table.
std::optional< ModuleInfo > getModInfo(const nlohmann::json &) const
void createEngine(AcceleratorConnection &, AppIDPath appID, const nlohmann::json &) const
TODO: Hack.
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'.
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.
nlohmann::json manifestJson
std::vector< services::Service * > getServices(AppIDPath idPath, AcceleratorConnection &, const nlohmann::json &, ServiceTable &activeServices) const
Get all the services in the description of an instance.
std::map< std::string, const ModuleInfo > symbolInfoCache
services::Service * getService(AppIDPath idPath, AcceleratorConnection &, const nlohmann::json &, ServiceTable &activeServices, bool isEngine=false) const
Get a Service for the service specified in 'json'.
const std::map< std::string, const ModuleInfo > & getSymbolInfo() const
std::any getAny(const nlohmann::json &value) const
Convert the json value to a 'std::any', which can be exposed outside of this file.
void parseModuleMetadata(ModuleInfo &info, const nlohmann::json &mod) const
std::unique_ptr< Accelerator > buildAccelerator(AcceleratorConnection &acc) const
Build a dynamic API for the Accelerator connection 'acc' based on the manifest stored herein.
void parseModuleConsts(ModuleInfo &info, const nlohmann::json &mod) const
void scanServiceDecls(AcceleratorConnection &, const nlohmann::json &, ServiceTable &) const
Go through the "service_decls" section of the manifest and populate the services table as appropriate...
std::vector< const Type * > _typeTable
std::unique_ptr< Instance > getChildInstance(AppIDPath idPath, AcceleratorConnection &acc, ServiceTable activeServices, const nlohmann::json &childJson) const
Get a single child instance.
Impl(Context &ctxt, int port)
mlir::Type innerType(mlir::Type type)
std::optional< uint32_t > idx