Skip to content

Commit

Permalink
[ESI][Services.json] Add "modules" section (#3775)
Browse files Browse the repository at this point in the history
Matches more closely what the software API builder is going to produce.
Take information out of "top_levels" section as it is now redundant. Also
adds capnp information (if compiled in) to types in modules section.
  • Loading branch information
teqdruid authored Aug 24, 2022
1 parent a118a0e commit 005caec
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 123 deletions.
2 changes: 1 addition & 1 deletion include/circt/Dialect/ESI/ESIServices.td
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ def ServiceHierarchyMetadataOp : ESI_Op<"service.hierarchy.metadata", [
let summary = "Metadata about a service in the service hierarchy";

let arguments = (ins FlatSymbolRefAttr:$service_symbol,
StrArrayAttr:$serverNamePath,
ArrayAttr:$serverNamePath,
StrAttr:$impl_type,
OptionalAttr<DictionaryAttr>:$impl_details,
ArrayAttr:$clients);
Expand Down
127 changes: 87 additions & 40 deletions lib/Dialect/ESI/ESIPasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1410,7 +1410,28 @@ static llvm::json::Value toJSON(Attribute attr) {
return TypeSwitch<Attribute, Value>(attr)
.Case([&](StringAttr a) { return a.getValue(); })
.Case([&](IntegerAttr a) { return a.getValue().getLimitedValue(); })
.Case([&](TypeAttr a) { return toJSON(a.getValue()); })
.Case([&](TypeAttr a) {
Type t = a.getValue();
llvm::json::Object typeMD;
typeMD["type_desc"] = toJSON(t);

std::string buf;
llvm::raw_string_ostream(buf) << t;
typeMD["mlir_name"] = buf;

if (auto chanType = t.dyn_cast<ChannelType>()) {
Type inner = chanType.getInner();
typeMD["hw_bitwidth"] = hw::getBitWidth(inner);
#ifdef CAPNP
capnp::TypeSchema schema(inner);
typeMD["capnp_type_id"] = schema.capnpTypeID();
typeMD["capnp_name"] = schema.name();
#endif
} else {
typeMD["hw_bitwidth"] = hw::getBitWidth(t);
}
return typeMD;
})
.Case([&](ArrayAttr a) {
return llvm::json::Array(
llvm::map_range(a, [](Attribute a) { return toJSON(a); }));
Expand All @@ -1421,6 +1442,12 @@ static llvm::json::Value toJSON(Attribute attr) {
dict[entry.getName().getValue()] = toJSON(entry.getValue());
return dict;
})
.Case([&](InnerRefAttr ref) {
llvm::json::Object dict;
dict["outer_sym"] = ref.getModule().getValue();
dict["inner"] = ref.getName().getValue();
return dict;
})
.Default([&](Attribute a) {
std::string buff;
llvm::raw_string_ostream(buff) << a;
Expand Down Expand Up @@ -1451,45 +1478,21 @@ void ESIEmitCollateralPass::emitServiceJSON() {

// Emit the list of ports of a service declaration.
auto emitPorts = [&](ServiceDeclOp decl) {
j.array([&] {
for (auto *portOp : llvm::make_pointer_range(decl.ports().getOps())) {
j.object([&] {
if (auto port = dyn_cast<ToServerOp>(portOp)) {
j.attribute("name", port.inner_sym());
j.attribute("to-server-type", toJSON(port.type()));
} else if (auto port = dyn_cast<ToClientOp>(portOp)) {
j.attribute("name", port.inner_sym());
j.attribute("to-client-type", toJSON(port.type()));
} else if (auto port = dyn_cast<ServiceDeclInOutOp>(portOp)) {
j.attribute("name", port.inner_sym());
j.attribute("to-client-type", toJSON(port.outType()));
j.attribute("to-server-type", toJSON(port.inType()));
}
});
}
});
};

auto emitServicesForModule = [&](Operation *hwMod) {
// Emit a list of the servers in a design and the clients connected to them.
j.attributeArray("services", [&] {
hwMod->walk([&](ServiceHierarchyMetadataOp metadata) {
j.object([&] {
j.attribute("service", metadata.service_symbol());
j.attributeArray("path", [&] {
for (auto attr : metadata.serverNamePath())
j.value(attr.cast<StringAttr>().getValue());
});
j.attribute("impl_type", metadata.impl_type());
if (metadata.impl_detailsAttr())
j.attribute("impl_details", toJSON(metadata.impl_detailsAttr()));
j.attributeArray("clients", [&] {
for (auto client : metadata.clients())
j.value(toJSON(client));
});
});
for (auto *portOp : llvm::make_pointer_range(decl.ports().getOps())) {
j.object([&] {
if (auto port = dyn_cast<ToServerOp>(portOp)) {
j.attribute("name", port.inner_sym());
j.attribute("to-server-type", toJSON(port.type()));
} else if (auto port = dyn_cast<ToClientOp>(portOp)) {
j.attribute("name", port.inner_sym());
j.attribute("to-client-type", toJSON(port.type()));
} else if (auto port = dyn_cast<ServiceDeclInOutOp>(portOp)) {
j.attribute("name", port.inner_sym());
j.attribute("to-client-type", toJSON(port.outType()));
j.attribute("to-server-type", toJSON(port.inType()));
}
});
});
}
};

j.object([&] {
Expand All @@ -1511,7 +1514,51 @@ void ESIEmitCollateralPass::emitServiceJSON() {
auto sym = FlatSymbolRefAttr::get(ctxt, topModName);
Operation *hwMod = topSyms.getDefinition(sym);
j.attribute("module", toJSON(sym));
emitServicesForModule(hwMod);
j.attributeArray("services", [&] {
hwMod->walk([&](ServiceHierarchyMetadataOp md) {
j.object([&] {
j.attribute("service", md.service_symbol());
j.attribute("instance_path", toJSON(md.serverNamePathAttr()));
});
});
});
});
}
});

// Get a list of metadata ops which originated in modules (path is empty).
DenseMap<hw::HWModuleLike, SmallVector<ServiceHierarchyMetadataOp, 0>>
modsWithLocalServices;
for (auto hwmod : mod.getOps<hw::HWModuleLike>()) {
SmallVector<ServiceHierarchyMetadataOp, 0> metadataOps;
hwmod.walk([&metadataOps](ServiceHierarchyMetadataOp md) {
if (md.serverNamePath().empty())
metadataOps.push_back(md);
});
if (!metadataOps.empty())
modsWithLocalServices[hwmod] = metadataOps;
}

// Then output metadata for those modules exclusively.
j.attributeArray("modules", [&] {
for (auto &modWithSvc : modsWithLocalServices) {
j.object([&] {
j.attribute("symbol", modWithSvc.first.moduleName());
j.attributeArray("services", [&] {
for (ServiceHierarchyMetadataOp metadata : modWithSvc.getSecond()) {
j.object([&] {
j.attribute("service", metadata.service_symbol());
j.attribute("impl_type", metadata.impl_type());
if (metadata.impl_detailsAttr())
j.attribute("impl_details",
toJSON(metadata.impl_detailsAttr()));
j.attributeArray("clients", [&] {
for (auto client : metadata.clients())
j.value(toJSON(client));
});
});
}
});
});
}
});
Expand Down
4 changes: 3 additions & 1 deletion lib/Dialect/ESI/ESIServices.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,9 @@ void ESIConnectServicesPass::copyMetadata(hw::HWMutableModuleLike mod) {
auto instName = b.getStringAttr(inst.instanceName());
for (auto metadata : metadataOps) {
SmallVector<Attribute, 4> path;
path.push_back(instName);
path.push_back(hw::InnerRefAttr::get(
cast<hw::HWModuleLike>(mod.getOperation()).moduleNameAttr(),
instName));
for (auto attr : metadata.serverNamePathAttr())
path.push_back(attr);

Expand Down
196 changes: 115 additions & 81 deletions test/Dialect/ESI/services_collateral.mlir
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,50 @@

// CHECK-LABEL: "declarations": [

// CHECK-LABEL: "name": "HostComms"
// CHECK: "ports": [
// CHECK: [
// CHECK: {
// CHECK: "name": "Send",
// CHECK: "to-server-type": {
// CHECK: "dialect": "esi",
// CHECK: "inner": {
// CHECK: "dialect": "esi",
// CHECK: "mnemonic": "any"
// CHECK: },
// CHECK: "mnemonic": "channel"
// CHECK: }
// CHECK: },
// CHECK: {
// CHECK: "name": "Recv",
// CHECK: "to-client-type": {
// CHECK: "dialect": "esi",
// CHECK: "inner": {
// CHECK: "dialect": "builtin",
// CHECK: "mnemonic": "i8"
// CHECK: },
// CHECK: "mnemonic": "channel"
// CHECK: }
// CHECK: },
// CHECK: {
// CHECK: "name": "ReqResp",
// CHECK: "to-client-type": {
// CHECK: "dialect": "esi",
// CHECK: "inner": {
// CHECK: "dialect": "builtin",
// CHECK: "mnemonic": "i16"
// CHECK: },
// CHECK: "mnemonic": "channel"
// CHECK: },
// CHECK: "to-server-type": {
// CHECK: "dialect": "esi",
// CHECK: "inner": {
// CHECK: "dialect": "builtin",
// CHECK: "mnemonic": "i8"
// CHECK: },
// CHECK: "mnemonic": "channel"
// CHECK: }
// CHECK: }
// CHECK: ]
// CHECK-LABEL: "name": "HostComms",
// CHECK-NEXT: "ports": [
// CHECK-NEXT: {
// CHECK-NEXT: "name": "Send",
// CHECK-NEXT: "to-server-type": {
// CHECK-NEXT: "dialect": "esi",
// CHECK-NEXT: "inner": {
// CHECK-NEXT: "dialect": "esi",
// CHECK-NEXT: "mnemonic": "any"
// CHECK-NEXT: },
// CHECK-NEXT: "mnemonic": "channel"
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "Recv",
// CHECK-NEXT: "to-client-type": {
// CHECK-NEXT: "dialect": "esi",
// CHECK-NEXT: "inner": {
// CHECK-NEXT: "dialect": "builtin",
// CHECK-NEXT: "mnemonic": "i8"
// CHECK-NEXT: },
// CHECK-NEXT: "mnemonic": "channel"
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "name": "ReqResp",
// CHECK-NEXT: "to-client-type": {
// CHECK-NEXT: "dialect": "esi",
// CHECK-NEXT: "inner": {
// CHECK-NEXT: "dialect": "builtin",
// CHECK-NEXT: "mnemonic": "i16"
// CHECK-NEXT: },
// CHECK-NEXT: "mnemonic": "channel"
// CHECK-NEXT: },
// CHECK-NEXT: "to-server-type": {
// CHECK-NEXT: "dialect": "esi",
// CHECK-NEXT: "inner": {
// CHECK-NEXT: "dialect": "builtin",
// CHECK-NEXT: "mnemonic": "i8"
// CHECK-NEXT: },
// CHECK-NEXT: "mnemonic": "channel"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
esi.service.decl @HostComms {
esi.service.to_server @Send : !esi.channel<!esi.any>
esi.service.to_client @Recv : !esi.channel<i8>
Expand All @@ -73,42 +72,77 @@ msft.module @LoopbackCosimTop {} (%clk: i1, %rst: i1) {
// CHECK-LABEL: "top_levels": [

// CHECK-LABEL: "module": "@LoopbackCosimTopWrapper",
// CHECK: "services": [
// CHECK: {
// CHECK: "service": "HostComms",
// CHECK: "path": [
// CHECK: "top"
// CHECK: ],
// CHECK: "impl_type": "cosim",
// CHECK: "clients": [
// CHECK: {
// CHECK: "client_name": [
// CHECK: "m1",
// CHECK: "loopback_inout"
// CHECK: ],
// CHECK: "port": "#hw.innerNameRef<@HostComms::@ReqResp>",
// CHECK: "to_client_type": {
// CHECK: "dialect": "esi",
// CHECK: "inner": {
// CHECK: "dialect": "builtin",
// CHECK: "mnemonic": "i16"
// CHECK: },
// CHECK: "mnemonic": "channel"
// CHECK: }
// CHECK: },
// CHECK: {
// CHECK: "client_name": [
// CHECK: "m1",
// CHECK: "loopback_inout"
// CHECK: ],
// CHECK: "port": "#hw.innerNameRef<@HostComms::@ReqResp>",
// CHECK: "to_server_type": {
// CHECK: "dialect": "esi",
// CHECK: "inner": {
// CHECK: "dialect": "builtin",
// CHECK: "mnemonic": "i8"
// CHECK: },
// CHECK: "mnemonic": "channel"
// CHECK-NEXT: "services": [
// CHECK-NEXT: {
// CHECK-NEXT: "service": "HostComms",
// CHECK-NEXT: "instance_path": [
// CHECK-NEXT: {
// CHECK-NEXT: "inner": "top",
// CHECK-NEXT: "outer_sym": "LoopbackCosimTop"
// CHECK-NEXT: }
// CHECK-NEXT: ]

// CHECK-LABEL: "modules": [
// CHECK-NEXT: {
// CHECK-NEXT: "symbol": "LoopbackCosimTop",
// CHECK-NEXT: "services": [
// CHECK-NEXT: {
// CHECK-NEXT: "service": "HostComms",
// CHECK-NEXT: "impl_type": "cosim",
// CHECK-NEXT: "clients": [
// CHECK-NEXT: {
// CHECK-NEXT: "client_name": [
// CHECK-NEXT: "m1",
// CHECK-NEXT: "loopback_inout"
// CHECK-NEXT: ],
// CHECK-NEXT: "port": {
// CHECK-NEXT: "inner": "ReqResp",
// CHECK-NEXT: "outer_sym": "HostComms"
// CHECK-NEXT: },
// CHECK-NEXT: "to_client_type": {
// CHECK-NEXT: "capnp_name": "I16",
// CHECK-NEXT: "capnp_type_id": 15002640976408729367,
// CHECK-NEXT: "hw_bitwidth": 16,
// CHECK-NEXT: "mlir_name": "!esi.channel<i16>",
// CHECK-NEXT: "type_desc": {
// CHECK-NEXT: "dialect": "esi",
// CHECK-NEXT: "inner": {
// CHECK-NEXT: "dialect": "builtin",
// CHECK-NEXT: "mnemonic": "i16"
// CHECK-NEXT: },
// CHECK-NEXT: "mnemonic": "channel"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "client_name": [
// CHECK-NEXT: "m1",
// CHECK-NEXT: "loopback_inout"
// CHECK-NEXT: ],
// CHECK-NEXT: "port": {
// CHECK-NEXT: "inner": "ReqResp",
// CHECK-NEXT: "outer_sym": "HostComms"
// CHECK-NEXT: },
// CHECK-NEXT: "to_server_type": {
// CHECK-NEXT: "capnp_name": "I8",
// CHECK-NEXT: "capnp_type_id": 9950424317211852587,
// CHECK-NEXT: "hw_bitwidth": 8,
// CHECK-NEXT: "mlir_name": "!esi.channel<i8>",
// CHECK-NEXT: "type_desc": {
// CHECK-NEXT: "dialect": "esi",
// CHECK-NEXT: "inner": {
// CHECK-NEXT: "dialect": "builtin",
// CHECK-NEXT: "mnemonic": "i8"
// CHECK-NEXT: },
// CHECK-NEXT: "mnemonic": "channel"
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: ]


msft.module @LoopbackCosimTopWrapper {} (%clk: i1, %rst: i1) {
Expand Down

0 comments on commit 005caec

Please sign in to comment.