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"
29 using namespace circt;
35 struct 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;
76 hw::HWSymbolCache symCache;
80 void 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(),
130 <<
"zlib not available but required for manifest support";
134 void 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>())
153 void 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()));
168 std::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);
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;
271 llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp,
Type type,
273 using llvm::json::Array;
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;
353 if (
auto chanType = dyn_cast<ChannelType>(type))
356 o[
"hwBitwidth"] =
width;
358 o[
"dialect"] = type.getDialect().getNamespace();
366 llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp, Attribute attr,
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) {
389 for (
const auto &entry : a.getValue())
390 dict[entry.getName().getValue()] =
391 json(errorOp, entry.getValue());
394 .Case([&](AppIDAttr appid) {
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());
420 std::unique_ptr<OperationPass<ModuleOp>>
422 return std::make_unique<ESIBuildManifestPass>();
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.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
constexpr uint64_t esiApiVersion
Manifest format version number.
std::unique_ptr< OperationPass< ModuleOp > > createESIBuildManifestPass()
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
evaluator::ObjectValue Object
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.