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