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;
33 struct ESIBuildManifestPass
34 :
public circt::esi::impl::ESIBuildManifestBase<ESIBuildManifestPass> {
35 void runOnOperation()
override;
39 void gatherFilters(Operation *);
40 void gatherFilters(Attribute);
43 llvm::json::Value
json(Operation *errorOp,
Type);
45 llvm::json::Value
json(Operation *errorOp, Attribute);
48 void emitNode(llvm::json::OStream &, AppIDHierNodeOp nodeOp);
50 void emitBlock(llvm::json::OStream &,
Block &block);
52 AppIDHierRootOp appidRoot;
58 void addType(
Type type) {
59 if (typeLookup.count(type))
61 typeLookup[type] = types.size();
62 types.push_back(type);
64 SmallVector<Type, 8> types;
65 DenseMap<Type, size_t> typeLookup;
68 DenseSet<SymbolRefAttr> symbols;
70 hw::HWSymbolCache symCache;
74 void ESIBuildManifestPass::runOnOperation() {
75 MLIRContext *
ctxt = &getContext();
76 Operation *mod = getOperation();
77 symCache.addDefinitions(mod);
81 for (
auto root : mod->getRegion(0).front().getOps<AppIDHierRootOp>())
82 if (root.getTopModuleRef() == top)
89 appidRoot->walk([&](Operation *op) { gatherFilters(op); });
92 std::string jsonManifest =
json();
95 llvm::raw_fd_ostream os(
"esi_system_manifest.json", ec);
97 mod->emitError() <<
"Failed to open file for writing: " << ec.message();
100 os << jsonManifest <<
"\n";
104 SmallVector<uint8_t, 10 * 1024> compressedManifest;
105 if (llvm::compression::zlib::isAvailable()) {
107 llvm::compression::zlib::compress(
108 ArrayRef((uint8_t *)jsonManifest.data(), jsonManifest.length()),
109 compressedManifest, llvm::compression::zlib::BestSizeCompression);
111 llvm::raw_fd_ostream bos(
"esi_system_manifest.json.zlib", ec);
113 mod->emitError() <<
"Failed to open compressed file for writing: "
117 bos.write((
char *)compressedManifest.data(), compressedManifest.size());
120 OpBuilder b(symCache.getDefinition(appidRoot.getTopModuleRefAttr())
124 b.create<CompressedManifestOp>(b.getUnknownLoc(),
128 <<
"zlib not available but required for manifest support";
132 void ESIBuildManifestPass::emitNode(llvm::json::OStream &j,
133 AppIDHierNodeOp nodeOp) {
135 j.attribute(
"app_id",
json(nodeOp, nodeOp.getAppIDAttr()));
136 j.attribute(
"inst_of",
json(nodeOp, nodeOp.getModuleRefAttr()));
137 j.attributeArray(
"contents",
138 [&]() { emitBlock(j, nodeOp.getChildren().front()); });
139 j.attributeArray(
"children", [&]() {
140 for (auto nodeOp : nodeOp.getChildren().front().getOps<AppIDHierNodeOp>())
146 void ESIBuildManifestPass::emitBlock(llvm::json::OStream &j, Block &block) {
147 for (
auto manifestData : block.getOps<IsManifestData>())
149 j.attribute(
"class", manifestData.getManifestClass());
150 SmallVector<NamedAttribute, 4> attrs;
151 manifestData.getDetails(attrs);
152 for (
auto attr : attrs)
153 j.attribute(attr.getName().getValue(),
154 json(manifestData, attr.getValue()));
158 std::string ESIBuildManifestPass::json() {
159 auto mod = getOperation();
160 std::string jsonStrBuffer;
161 llvm::raw_string_ostream os(jsonStrBuffer);
162 llvm::json::OStream j(os, 2);
167 j.attributeArray(
"symbols", [&]() {
168 for (
auto symInfo : mod.getBody()->getOps<SymbolMetadataOp>()) {
169 if (!symbols.contains(symInfo.getSymbolRefAttr()))
172 SmallVector<NamedAttribute, 4> attrs;
173 symInfo.getDetails(attrs);
174 for (auto attr : attrs)
175 j.attribute(attr.getName().getValue(),
176 json(symInfo, attr.getValue()));
181 j.attributeObject(
"design", [&]() {
182 j.attribute(
"inst_of",
json(appidRoot, appidRoot.getTopModuleRefAttr()));
183 j.attributeArray(
"contents",
184 [&]() { emitBlock(j, appidRoot.getChildren().front()); });
185 j.attributeArray(
"children", [&]() {
187 appidRoot.getChildren().front().getOps<AppIDHierNodeOp>())
192 j.attributeArray(
"service_decls", [&]() {
193 for (
auto svcDecl : mod.getBody()->getOps<ServiceDeclOpInterface>()) {
195 if (!symbols.contains(sym))
198 j.attribute(
"symbol", sym.getValue());
199 std::optional<StringRef> typeName = svcDecl.getTypeName();
201 j.attribute(
"type_name", *typeName);
202 llvm::SmallVector<ServicePortInfo, 8> ports;
203 svcDecl.getPortList(ports);
204 j.attributeArray(
"ports", [&]() {
205 for (auto port : ports) {
207 j.attribute(
"name", port.port.getName().getValue());
208 j.attribute(
"type", json(svcDecl, TypeAttr::get(port.type)));
216 j.attributeArray(
"types", [&]() {
217 for (
auto type : types) {
218 j.value(
json(mod, type));
223 return jsonStrBuffer;
226 void ESIBuildManifestPass::gatherFilters(Operation *op) {
227 for (
auto oper : op->getOperands())
228 addType(oper.getType());
229 for (
auto res : op->getResults())
230 addType(res.getType());
234 SmallVector<NamedAttribute> attrs;
235 if (
auto manifestData = dyn_cast<IsManifestData>(op))
236 manifestData.getDetails(attrs);
238 llvm::append_range(attrs, op->getAttrs());
239 for (
auto attr : attrs)
240 gatherFilters(attr.getValue());
244 void ESIBuildManifestPass::gatherFilters(Attribute attr) {
246 TypeSwitch<Attribute>(attr)
247 .Case([&](TypeAttr a) { addType(a.getValue()); })
248 .Case([&](FlatSymbolRefAttr a) { symbols.insert(a); })
249 .Case([&](hw::InnerRefAttr a) { symbols.insert(a.getModuleRef()); })
250 .Case([&](ArrayAttr a) {
254 .Case([&](DictionaryAttr a) {
255 for (
const auto &entry : a.getValue())
256 gatherFilters(entry.getValue());
262 llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp,
Type type) {
263 using llvm::json::Array;
265 using llvm::json::Value;
270 TypeSwitch<Type, Object>(type)
275 .Case([&](ChannelBundleType t) {
278 for (
auto field : t.getChannels())
279 channels.push_back(
Object(
280 {{
"name", field.name.getValue()},
281 {
"direction", stringifyChannelDirection(field.direction)},
282 {
"type",
json(errorOp, field.type)}}));
283 return Object({{
"channels", Value(std::move(channels))}});
289 .Case([&](ListType t) {
291 return Object({{
"element",
json(errorOp, t.getElementType())}});
293 .Case([&](hw::ArrayType t) {
295 return Object({{
"size", t.getNumElements()},
296 {
"element",
json(errorOp, t.getElementType())}});
298 .Case([&](hw::StructType t) {
301 for (
auto field : t.getElements())
302 fields.push_back(
Object({{
"name", field.name.getValue()},
303 {
"type",
json(errorOp, field.type)}}));
304 return Object({{
"fields", Value(std::move(fields))}});
306 .Case([&](hw::TypeAliasType t) {
308 return Object({{
"name", t.getTypeDecl(symCache).getPreferredName()},
309 {
"inner",
json(errorOp, t.getInnerType())}});
313 StringRef signedness =
314 t.isSigned() ?
"signed"
315 : (t.isUnsigned() ?
"unsigned" :
"signless");
316 return Object({{
"signedness", signedness}});
318 .Default([&](
Type t) {
319 errorOp->emitWarning()
320 <<
"ESI system manifest: unknown type: " << t;
325 std::string circtName;
326 llvm::raw_string_ostream(circtName) << type;
327 o[
"circt_name"] = circtName;
330 if (
auto chanType = dyn_cast<ChannelType>(type))
333 o[
"hw_bitwidth"] =
width;
335 o[
"dialect"] = type.getDialect().getNamespace();
343 llvm::json::Value ESIBuildManifestPass::json(Operation *errorOp,
346 using llvm::json::Value;
347 return TypeSwitch<Attribute, Value>(attr)
348 .Case([&](StringAttr a) {
return a.getValue(); })
349 .Case([&](IntegerAttr a) {
return a.getValue().getLimitedValue(); })
350 .Case([&](TypeAttr a) {
351 Type t = a.getValue();
354 if (typeLookup.contains(t)) {
359 llvm::raw_string_ostream(buff) << a;
360 typeMD[
"circt_name"] = buff;
364 typeMD[
"type"] =
json(errorOp, t);
367 .Case([&](ArrayAttr a) {
368 return llvm::json::Array(
369 llvm::map_range(a, [&](Attribute a) {
return json(errorOp, a); }));
371 .Case([&](DictionaryAttr a) {
373 for (
const auto &entry : a.getValue())
374 dict[entry.getName().getValue()] =
json(errorOp, entry.getValue());
377 .Case([&](hw::InnerRefAttr ref) {
379 dict[
"outer_sym"] = ref.getModule().getValue();
380 dict[
"inner"] = ref.getName().getValue();
383 .Case([&](AppIDAttr appid) {
385 dict[
"name"] = appid.getName().getValue();
386 auto idx = appid.getIndex();
388 dict[
"index"] = *idx;
391 .Default([&](Attribute a) {
393 llvm::raw_string_ostream(buff) << a;
398 std::unique_ptr<OperationPass<ModuleOp>>
400 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()
std::optional< int64_t > getBitWidth(FIRRTLBaseType type, bool ignoreFlip=false)
evaluator::ObjectValue Object
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.