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