9 #include "../PassDetails.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/TypeSwitch.h"
20 #include "llvm/Support/Compression.h"
21 #include "llvm/Support/JSON.h"
23 using namespace circt;
27 struct ESIBuildManifestPass
28 :
public ESIBuildManifestBase<ESIBuildManifestPass> {
29 void runOnOperation()
override;
33 void gatherFilters(Operation *);
34 void gatherFilters(Attribute);
37 llvm::json::Value
json(Operation *errorOp,
Type);
39 llvm::json::Value
json(Operation *errorOp, Attribute);
42 void emitNode(llvm::json::OStream &, AppIDHierNodeOp nodeOp);
44 void emitBlock(llvm::json::OStream &, Block &block);
46 AppIDHierRootOp appidRoot;
52 void addType(
Type type) {
53 if (typeLookup.count(type))
55 typeLookup[type] = types.size();
56 types.push_back(type);
58 SmallVector<Type, 8> types;
59 DenseMap<Type, size_t> typeLookup;
62 DenseSet<SymbolRefAttr> symbols;
64 hw::HWSymbolCache symCache;
68 void ESIBuildManifestPass::runOnOperation() {
69 MLIRContext *
ctxt = &getContext();
70 Operation *mod = getOperation();
71 symCache.addDefinitions(mod);
75 for (
auto root : mod->getRegion(0).front().getOps<AppIDHierRootOp>())
76 if (root.getTopModuleRef() == top)
83 appidRoot->walk([&](Operation *op) { gatherFilters(op); });
86 std::string jsonManifest =
json();
89 llvm::raw_fd_ostream os(
"esi_system_manifest.json", ec);
91 mod->emitError() <<
"Failed to open file for writing: " << ec.message();
94 os << jsonManifest <<
"\n";
98 SmallVector<uint8_t, 10 * 1024> compressedManifest;
99 if (llvm::compression::zlib::isAvailable()) {
101 llvm::compression::zlib::compress(
102 ArrayRef((uint8_t *)jsonManifest.data(), jsonManifest.length()),
103 compressedManifest, llvm::compression::zlib::BestSizeCompression);
105 llvm::raw_fd_ostream bos(
"esi_system_manifest.json.zlib", ec);
107 mod->emitError() <<
"Failed to open compressed file for writing: "
111 bos.write((
char *)compressedManifest.data(), compressedManifest.size());
114 OpBuilder b(symCache.getDefinition(appidRoot.getTopModuleRefAttr())
118 b.create<CompressedManifestOp>(b.getUnknownLoc(),
122 <<
"zlib not available but required for manifest support";
126 void ESIBuildManifestPass::emitNode(llvm::json::OStream &j,
127 AppIDHierNodeOp nodeOp) {
129 j.attribute(
"app_id",
json(nodeOp, nodeOp.getAppIDAttr()));
130 j.attribute(
"inst_of",
json(nodeOp, nodeOp.getModuleRefAttr()));
131 j.attributeArray(
"contents",
132 [&]() { emitBlock(j, nodeOp.getChildren().front()); });
133 j.attributeArray(
"children", [&]() {
134 for (auto nodeOp : nodeOp.getChildren().front().getOps<AppIDHierNodeOp>())
140 void ESIBuildManifestPass::emitBlock(llvm::json::OStream &j, Block &block) {
141 for (
auto manifestData : block.getOps<IsManifestData>())
143 j.attribute(
"class", manifestData.getManifestClass());
144 SmallVector<NamedAttribute, 4> attrs;
145 manifestData.getDetails(attrs);
146 for (
auto attr : attrs)
147 j.attribute(attr.getName().getValue(),
148 json(manifestData, attr.getValue()));
152 std::string ESIBuildManifestPass::json() {
153 auto mod = getOperation();
154 std::string jsonStrBuffer;
155 llvm::raw_string_ostream os(jsonStrBuffer);
156 llvm::json::OStream j(os, 2);
161 j.attributeArray(
"symbols", [&]() {
162 for (
auto symInfo : mod.getBody()->getOps<SymbolMetadataOp>()) {
163 if (!symbols.contains(symInfo.getSymbolRefAttr()))
166 SmallVector<NamedAttribute, 4> attrs;
167 symInfo.getDetails(attrs);
168 for (auto attr : attrs)
169 j.attribute(attr.getName().getValue(),
170 json(symInfo, attr.getValue()));
175 j.attributeObject(
"design", [&]() {
176 j.attribute(
"inst_of",
json(appidRoot, appidRoot.getTopModuleRefAttr()));
177 j.attributeArray(
"contents",
178 [&]() { emitBlock(j, appidRoot.getChildren().front()); });
179 j.attributeArray(
"children", [&]() {
181 appidRoot.getChildren().front().getOps<AppIDHierNodeOp>())
186 j.attributeArray(
"service_decls", [&]() {
187 for (
auto svcDecl : mod.getBody()->getOps<ServiceDeclOpInterface>()) {
189 if (!symbols.contains(sym))
192 j.attribute(
"symbol", sym.getValue());
193 std::optional<StringRef> typeName = svcDecl.getTypeName();
195 j.attribute(
"type_name", *typeName);
196 llvm::SmallVector<ServicePortInfo, 8> ports;
197 svcDecl.getPortList(ports);
198 j.attributeArray(
"ports", [&]() {
199 for (auto port : ports) {
201 j.attribute(
"name", port.port.getName().getValue());
202 j.attribute(
"type", json(svcDecl, TypeAttr::get(port.type)));
210 j.attributeArray(
"types", [&]() {
211 for (
auto type : types) {
212 j.value(
json(mod, type));
217 return jsonStrBuffer;
220 void ESIBuildManifestPass::gatherFilters(Operation *op) {
221 for (
auto oper : op->getOperands())
222 addType(oper.getType());
223 for (
auto res : op->getResults())
224 addType(res.getType());
228 SmallVector<NamedAttribute> attrs;
229 if (
auto manifestData = dyn_cast<IsManifestData>(op))
230 manifestData.getDetails(attrs);
232 llvm::append_range(attrs, op->getAttrs());
233 for (
auto attr : attrs)
234 gatherFilters(attr.getValue());
238 void ESIBuildManifestPass::gatherFilters(Attribute attr) {
240 TypeSwitch<Attribute>(attr)
241 .Case([&](TypeAttr a) { addType(a.getValue()); })
242 .Case([&](FlatSymbolRefAttr a) { symbols.insert(a); })
243 .Case([&](hw::InnerRefAttr a) { symbols.insert(a.getModuleRef()); })
244 .Case([&](ArrayAttr a) {
248 .Case([&](DictionaryAttr a) {
249 for (
const auto &entry : a.getValue())
250 gatherFilters(entry.getValue());
256 llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp,
Type type) {
257 using llvm::json::Array;
259 using llvm::json::Value;
264 TypeSwitch<Type, Object>(type)
269 .Case([&](ChannelBundleType t) {
272 for (
auto field : t.getChannels())
273 channels.push_back(
Object(
274 {{
"name", field.name.getValue()},
275 {
"direction", stringifyChannelDirection(field.direction)},
276 {
"type",
json(errorOp, field.type)}}));
277 return Object({{
"channels", Value(std::move(channels))}});
283 .Case([&](ListType t) {
285 return Object({{
"element",
json(errorOp, t.getElementType())}});
287 .Case([&](hw::ArrayType t) {
289 return Object({{
"size", t.getNumElements()},
290 {
"element",
json(errorOp, t.getElementType())}});
292 .Case([&](hw::StructType t) {
295 for (
auto field : t.getElements())
296 fields.push_back(
Object({{
"name", field.name.getValue()},
297 {
"type",
json(errorOp, field.type)}}));
298 return Object({{
"fields", Value(std::move(fields))}});
300 .Case([&](hw::TypeAliasType t) {
302 return Object({{
"name", t.getTypeDecl(symCache).getPreferredName()},
303 {
"inner",
json(errorOp, t.getInnerType())}});
307 StringRef signedness =
308 t.isSigned() ?
"signed"
309 : (t.isUnsigned() ?
"unsigned" :
"signless");
310 return Object({{
"signedness", signedness}});
312 .Default([&](
Type t) {
313 errorOp->emitWarning()
314 <<
"ESI system manifest: unknown type: " << t;
319 std::string circtName;
320 llvm::raw_string_ostream(circtName) << type;
321 o[
"circt_name"] = circtName;
324 if (
auto chanType = dyn_cast<ChannelType>(type))
327 o[
"hw_bitwidth"] =
width;
329 o[
"dialect"] = type.getDialect().getNamespace();
337 llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp,
340 using llvm::json::Value;
341 return TypeSwitch<Attribute, Value>(attr)
342 .Case([&](StringAttr a) {
return a.getValue(); })
343 .Case([&](IntegerAttr a) {
return a.getValue().getLimitedValue(); })
344 .Case([&](TypeAttr a) {
345 Type t = a.getValue();
348 if (typeLookup.contains(t)) {
353 llvm::raw_string_ostream(buff) << a;
354 typeMD[
"circt_name"] = buff;
358 typeMD[
"type"] =
json(errorOp, t);
361 .Case([&](ArrayAttr a) {
362 return llvm::json::Array(
363 llvm::map_range(a, [&](Attribute a) {
return json(errorOp, a); }));
365 .Case([&](DictionaryAttr a) {
367 for (
const auto &entry : a.getValue())
368 dict[entry.getName().getValue()] =
json(errorOp, entry.getValue());
371 .Case([&](hw::InnerRefAttr ref) {
373 dict[
"outer_sym"] = ref.getModule().getValue();
374 dict[
"inner"] = ref.getName().getValue();
377 .Case([&](AppIDAttr appid) {
379 dict[
"name"] = appid.getName().getValue();
380 auto idx = appid.getIndex();
382 dict[
"index"] = *idx;
385 .Default([&](Attribute a) {
387 llvm::raw_string_ostream(buff) << a;
392 std::unique_ptr<OperationPass<ModuleOp>>
394 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
Every time we implement a breaking change in the schema generation, increment this number.
std::unique_ptr< OperationPass< ModuleOp > > createESIBuildManifestPass()
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
evaluator::ObjectValue Object
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.