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