18#include "mlir/IR/Attributes.h"
19#include "mlir/Target/LLVMIR/Import.h"
20#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
32static TileID getNextCoords(
int col,
int row, WireBundle bundle) {
34 case WireBundle::North:
35 return {col, row + 1};
36 case WireBundle::South:
37 return {col, row - 1};
38 case WireBundle::East:
39 return {col + 1, row};
40 case WireBundle::West:
41 return {col - 1, row};
47static void translateSwitchboxes(DeviceOp targetOp, raw_ostream &output) {
49 std::map<TileID, int> sourceCounts;
50 std::map<TileID, int> destinationCounts;
51 for (FlowOp flowOp : targetOp.getOps<FlowOp>()) {
52 TileOp source = cast<TileOp>(flowOp.getSource().getDefiningOp());
53 TileOp dest = cast<TileOp>(flowOp.getDest().getDefiningOp());
54 TileID srcID = {source.colIndex(), source.rowIndex()};
55 TileID dstID = {dest.colIndex(), dest.rowIndex()};
56 sourceCounts[srcID]++;
57 destinationCounts[dstID]++;
59 for (PacketFlowOp pktFlowOp : targetOp.getOps<PacketFlowOp>()) {
60 Region &r = pktFlowOp.getPorts();
62 for (Operation &Op : b.getOperations()) {
63 if (
auto pktSource = dyn_cast<PacketSourceOp>(Op)) {
64 TileOp source = cast<TileOp>(pktSource.getTile().getDefiningOp());
65 TileID srcID = {source.colIndex(), source.rowIndex()};
66 sourceCounts[srcID]++;
67 }
else if (
auto pktDest = dyn_cast<PacketDestOp>(Op)) {
68 TileOp dest = cast<TileOp>(pktDest.getTile().getDefiningOp());
69 TileID dstID = {dest.colIndex(), dest.rowIndex()};
70 destinationCounts[dstID]++;
75 std::map<TileID, ShimMuxOp> shimMuxes;
76 for (ShimMuxOp shimMuxOp : targetOp.getOps<ShimMuxOp>()) {
77 shimMuxes[{shimMuxOp.colIndex(), shimMuxOp.rowIndex()}] = shimMuxOp;
80 int totalPathLength = 0;
82 for (SwitchboxOp switchboxOp : targetOp.getOps<SwitchboxOp>()) {
83 int col = switchboxOp.colIndex();
84 int row = switchboxOp.rowIndex();
85 std::string switchString =
"\"switchbox" + std::to_string(col) +
86 std::to_string(row) +
"\": {\n" +
87 "\"col\": " + std::to_string(col) +
",\n" +
88 "\"row\": " + std::to_string(row) +
",\n";
92 "\"source_count\": " + std::to_string(sourceCounts[{col, row}]) +
",\n";
93 switchString +=
"\"destination_count\": " +
94 std::to_string(destinationCounts[{col, row}]) +
",\n";
97 std::vector<uint32_t> connectCounts(getMaxEnumValForWireBundle() + 1, 0);
98 for (
auto &connectCount : connectCounts)
101 std::set<Port> ports;
102 for (ConnectOp connectOp : switchboxOp.getOps<ConnectOp>())
103 ports.insert(connectOp.destPort());
104 for (MasterSetOp masterSetOp : switchboxOp.getOps<MasterSetOp>())
105 ports.insert(masterSetOp.destPort());
106 for (
Port port : ports) {
107 connectCounts[int(port.bundle)]++;
110 switchString +=
"\"northbound\": " +
111 std::to_string(connectCounts[
int(WireBundle::North)]) +
113 switchString +=
"\"eastbound\": " +
114 std::to_string(connectCounts[
int(WireBundle::East)]) +
116 switchString +=
"\"southbound\": " +
117 std::to_string(connectCounts[
int(WireBundle::South)]) +
119 switchString +=
"\"westbound\": " +
120 std::to_string(connectCounts[
int(WireBundle::West)]) +
"\n";
121 switchString +=
"},\n";
122 output << switchString;
125 totalPathLength += connectCounts[int(WireBundle::North)];
126 totalPathLength += connectCounts[int(WireBundle::East)];
127 totalPathLength += connectCounts[int(WireBundle::South)];
128 totalPathLength += connectCounts[int(WireBundle::West)];
131 if (shimMuxes.count({col, row})) {
132 auto shimMuxOp = shimMuxes[{col, row}];
133 std::set<Port> ports;
134 for (ConnectOp connectOp : shimMuxOp.getOps<ConnectOp>()) {
135 Port port = connectOp.sourcePort();
136 if (port.bundle == WireBundle::North) {
140 for (PacketRulesOp packetRulesOp : shimMuxOp.getOps<PacketRulesOp>()) {
141 Port port = packetRulesOp.sourcePort();
142 if (port.bundle == WireBundle::North) {
146 totalPathLength -= ports.size();
151 output <<
"\"total_path_length\": " << totalPathLength <<
",\n";
154static void translateCircuitFlows(DeviceOp targetOp,
int &flowCount,
155 raw_ostream &output) {
157 std::set<std::pair<TileOp, Port>> flowSources;
158 for (FlowOp flowOp : targetOp.getOps<FlowOp>()) {
160 Port currPort = {flowOp.getSourceBundle(), flowOp.getSourceChannel()};
161 SwitchboxOp currSwitchbox;
163 TileOp source = cast<TileOp>(flowOp.getSource().getDefiningOp());
167 std::pair<TileOp, Port> flowSource = {source, currPort};
168 if (flowSources.count(flowSource)) {
171 flowSources.insert(flowSource);
173 std::string routeString =
174 "\"route" + std::to_string(flowCount++) +
"\": [ ";
177 std::queue<Port> nextPorts;
178 std::queue<SwitchboxOp> nextSwitches;
181 for (SwitchboxOp switchboxOp : targetOp.getOps<SwitchboxOp>()) {
182 if (switchboxOp.colIndex() == source.colIndex() &&
183 switchboxOp.rowIndex() == source.rowIndex()) {
184 currSwitchbox = switchboxOp;
190 for (ShimMuxOp shimMuxOp : targetOp.getOps<ShimMuxOp>()) {
191 if (shimMuxOp.colIndex() == source.colIndex() &&
192 shimMuxOp.rowIndex() == source.rowIndex()) {
193 for (ConnectOp connectOp : shimMuxOp.getOps<ConnectOp>()) {
194 if (connectOp.getSourceBundle() == currPort.bundle &&
195 connectOp.getSourceChannel() == currPort.channel) {
197 currPort.channel = connectOp.getDestChannel();
209 for (ConnectOp connectOp : currSwitchbox.getOps<ConnectOp>()) {
211 if ((currSwitchbox.rowIndex() == 0 &&
212 connectOp.getDestBundle() == WireBundle::South) ||
213 connectOp.getDestBundle() == WireBundle::DMA ||
214 connectOp.getDestBundle() == WireBundle::Core)
217 if (connectOp.getSourceBundle() == currPort.bundle &&
218 connectOp.getSourceChannel() == currPort.channel) {
220 connectOp.getDestChannel()});
223 getNextCoords(currSwitchbox.colIndex(), currSwitchbox.rowIndex(),
224 connectOp.getDestBundle());
227 for (SwitchboxOp switchboxOp : targetOp.getOps<SwitchboxOp>()) {
228 if (switchboxOp.colIndex() == nextCoords.col &&
229 switchboxOp.rowIndex() == nextCoords.row) {
230 nextSwitches.push(switchboxOp);
238 std::string dirString = std::string(
"[[") +
239 std::to_string(currSwitchbox.colIndex()) +
", " +
240 std::to_string(currSwitchbox.rowIndex()) +
"], [";
241 int opCount = 0, dirCount = 0;
242 for (ConnectOp connectOp : currSwitchbox.getOps<ConnectOp>()) {
243 if (connectOp.getSourceBundle() == currPort.bundle &&
244 connectOp.getSourceChannel() == currPort.channel) {
250 (std::string)stringifyWireBundle(connectOp.getDestBundle()) +
256 routeString += dirString;
258 if (nextPorts.empty() || nextSwitches.empty()) {
262 currPort = nextPorts.front();
263 currSwitchbox = nextSwitches.front();
269 routeString += std::string(
" ],\n");
270 output << routeString;
274static void translatePacketFlows(DeviceOp targetOp,
int &flowCount,
275 raw_ostream &output) {
277 std::set<std::pair<TileOp, Port>> flowSources;
278 for (PacketFlowOp pktFlowOp : targetOp.getOps<PacketFlowOp>()) {
279 Region &r = pktFlowOp.getPorts();
280 Block &b = r.front();
281 Port sourcePort, destPort;
283 for (Operation &Op : b.getOperations()) {
284 if (
auto pktSource = dyn_cast<PacketSourceOp>(Op)) {
285 source = cast<TileOp>(pktSource.getTile().getDefiningOp());
286 sourcePort = pktSource.port();
287 }
else if (
auto pktDest = dyn_cast<PacketDestOp>(Op)) {
288 dest = cast<TileOp>(pktDest.getTile().getDefiningOp());
289 destPort = pktDest.port();
294 Port currPort = sourcePort;
295 SwitchboxOp currSwitchbox;
298 std::pair<TileOp, Port> flowSource = {source, currPort};
299 if (flowSources.count(flowSource)) {
302 flowSources.insert(flowSource);
304 std::string routeString =
305 "\"route" + std::to_string(flowCount++) +
"\": [ ";
308 std::queue<Port> nextPorts;
309 std::queue<SwitchboxOp> nextSwitches;
312 for (SwitchboxOp switchboxOp : targetOp.getOps<SwitchboxOp>()) {
313 if (switchboxOp.colIndex() == source.colIndex() &&
314 switchboxOp.rowIndex() == source.rowIndex()) {
315 currSwitchbox = switchboxOp;
321 for (ShimMuxOp shimMuxOp : targetOp.getOps<ShimMuxOp>()) {
322 if (shimMuxOp.colIndex() == source.colIndex() &&
323 shimMuxOp.rowIndex() == source.rowIndex()) {
324 for (ConnectOp connectOp : shimMuxOp.getOps<ConnectOp>()) {
325 if (connectOp.getSourceBundle() == currPort.bundle &&
326 connectOp.getSourceChannel() == currPort.channel) {
328 currPort.channel = connectOp.getDestChannel();
339 for (
auto packetRulesOp : currSwitchbox.getOps<PacketRulesOp>()) {
341 for (
auto masterSetOp : currSwitchbox.getOps<MasterSetOp>()) {
342 for (Value amsel : masterSetOp.getAmsels()) {
344 packetRulesOp.getRules().front().getOps<PacketRuleOp>()) {
345 if (ruleOp.getAmsel() == amsel) {
346 destPort = masterSetOp.destPort();
353 if ((currSwitchbox.rowIndex() == 0 &&
354 destPort.bundle == WireBundle::South) ||
355 destPort.bundle == WireBundle::DMA ||
356 destPort.bundle == WireBundle::Core)
359 if (packetRulesOp.sourcePort() == currPort) {
364 getNextCoords(currSwitchbox.colIndex(), currSwitchbox.rowIndex(),
368 for (SwitchboxOp switchboxOp : targetOp.getOps<SwitchboxOp>()) {
369 if (switchboxOp.colIndex() == nextCoords.col &&
370 switchboxOp.rowIndex() == nextCoords.row) {
371 nextSwitches.push(switchboxOp);
379 std::string dirString = std::string(
"[[") +
380 std::to_string(currSwitchbox.colIndex()) +
", " +
381 std::to_string(currSwitchbox.rowIndex()) +
"], [";
382 int opCount = 0, dirCount = 0;
383 for (
auto packetRulesOp : currSwitchbox.getOps<PacketRulesOp>()) {
384 if (packetRulesOp.sourcePort() == currPort) {
386 for (
auto masterSetOp : currSwitchbox.getOps<MasterSetOp>()) {
387 for (Value amsel : masterSetOp.getAmsels()) {
389 packetRulesOp.getRules().front().getOps<PacketRuleOp>()) {
390 if (ruleOp.getAmsel() == amsel) {
391 destPort = masterSetOp.destPort();
400 "\"" + (std::string)stringifyWireBundle(destPort.bundle) +
"\"";
405 routeString += dirString;
407 if (nextPorts.empty() || nextSwitches.empty()) {
411 currPort = nextPorts.front();
412 currSwitchbox = nextSwitches.front();
418 routeString += std::string(
" ],\n");
419 output << routeString;
424 llvm::StringRef deviceName) {
425 DeviceOp targetOp = AIE::DeviceOp::getForSymbolInModule(module, deviceName);
427 return module.emitOpError("expected AIE.device operation at toplevel");
429 std::set<TileID> switchboxes;
430 for (SwitchboxOp switchboxOp : targetOp.getOps<SwitchboxOp>())
431 switchboxes.insert({switchboxOp.colIndex(), switchboxOp.rowIndex()});
432 WalkResult untraceable = targetOp.walk([&](Operation *op) {
434 if (
auto flowOp = dyn_cast<FlowOp>(op))
435 source = flowOp.getSource();
436 else if (
auto pktSource = dyn_cast<PacketSourceOp>(op))
437 source = pktSource.getTile();
439 return WalkResult::advance();
440 if (switchboxes.count(cast<TileOp>(source.getDefiningOp()).getTileID()))
441 return WalkResult::advance();
442 op->emitError(
"no switchbox at the flow's source to trace it through; "
443 "keep the routed switchboxes with "
444 "--aie-find-flows=remove-lifted=false");
445 return WalkResult::interrupt();
447 if (untraceable.wasInterrupted())
453 translateSwitchboxes(targetOp, output);
454 translateCircuitFlows(targetOp, flowCount, output);
455 translatePacketFlows(targetOp, flowCount, output);
457 output <<
"\"route_all\": [],\n";
458 output <<
"\n\"end json\": 0\n";
mlir::LogicalResult AIEFlowsToJSON(mlir::ModuleOp module, llvm::raw_ostream &output, llvm::StringRef deviceName="")
struct TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")"; return os; } friend std::string to_string(const TileID &s) { std::ostringstream ss; ss<< s; return ss.str(); } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const TileID &s) { os<< to_string(s); return os; } inline bool operator<(const TileID &rhs) const { return std::tie(col, row)< std::tie(rhs.col, rhs.row); } bool operator==(const TileID &rhs) const { return std::tie(col, row)==std::tie(rhs.col, rhs.row); } bool operator!=(const TileID &rhs) const { return !(*this==rhs);} int col, row;} TileID
struct Port { WireBundle bundle; int channel; bool operator==(const Port &rhs) const { return std::tie(bundle, channel)==std::tie(rhs.bundle, rhs.channel); } bool operator!=(const Port &rhs) const { return !(*this==rhs);} bool operator<(const Port &rhs) const { return std::tie(bundle, channel)< std::tie(rhs.bundle, rhs.channel); } friend std::ostream &operator<<(std::ostream &os, const Port &port) { os<< "("; os<< stringifyWireBundle(port.bundle).str(); os<< ": "<< std::to_string(port.channel)<< ")"; return os; } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const Port &port) { os<< to_string(port); return os; } } Port
WireBundle getConnectingBundle(WireBundle dir)