MLIR-AIE 1.4.5.dev
AIEPathFinder.h
Go to the documentation of this file.
1//===- AIEPathFinder.h ------------------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2021-2022 Xilinx, Inc.
4// Copyright (C) 2022-2026 Advanced Micro Devices, Inc.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef AIE_PATHFINDER_H
10#define AIE_PATHFINDER_H
11
15
16#include "llvm/ADT/ArrayRef.h"
17#include "llvm/ADT/BitVector.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/DenseSet.h"
20#include "llvm/ADT/IntEqClasses.h"
21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/SmallVector.h"
23#include "llvm/Support/Error.h"
24#include "llvm/Support/raw_ostream.h"
25
26#include <functional>
27#include <map>
28#include <optional>
29#include <set>
30#include <string>
31#include <tuple>
32#include <vector>
33
34namespace xilinx::AIE {
35
36// A shim's DMA, NOC and PLIO ports reach its switchbox through the shim mux,
37// on the South channel these return for a port that sends or receives.
39int shimMuxChannelTo(Port dst);
40
41// The connections from the source ports to the destination ports of a
42// switchbox, if `srcCoords == dstCoords`, or of the wires from one switchbox
43// to its neighbour at `dstCoords`.
45 // A connection from a source port to a destination port.
46 struct Cell {
47 bool available = false;
48 // weight of Dijkstra's shortest path
49 double demand = 0;
50 // iterations the connection was over capacity
51 int overCapacity = 0;
52 // circuit streams using the connection
53 int usedCapacity = 0;
54 // packet streams using the connection
56 // only packet streams of this group may share the connection
57 int packetGroupId = -1;
58 // packet ids routed through the connection (and its crossbar row and
59 // column), by the flow routing each; it may be shared only among distinct
60 // ids.
61 llvm::SmallDenseMap<int, int, 2> packetIds;
62 // whether a prioritized flow uses the connection
63 bool isPriority = false;
64 };
65
66 SwitchboxConnect() = default;
67 SwitchboxConnect(TileID coords) : srcCoords(coords), dstCoords(coords) {}
70
72 std::vector<Port> srcPorts;
73 std::vector<Port> dstPorts;
74 // The connection from srcPorts[i] to dstPorts[j] is cells[i * dstPorts.size()
75 // + j].
76 std::vector<Cell> cells;
77 // Units of dst ports tied to one arbiter (see planArbiters in
78 // AIECreatePathFindFlows.cpp); a unit's leader lists the packet flows
79 // (indices into the router's flows) leaving by any of its ports
80 llvm::IntEqClasses dstUnits;
81 std::vector<llvm::SmallVector<int, 2>> unitPacketFlows;
82 // source ports the design already gives packet rules, which circuit streams
83 // cannot enter
84 llvm::BitVector packetOnlySrc;
85 // dst ports packet streams may no longer take
86 llvm::BitVector circuitOnlyDst;
87
88 Cell &at(size_t i, size_t j) { return cells[i * dstPorts.size() + j]; }
89 const Cell &at(size_t i, size_t j) const {
90 return cells[i * dstPorts.size() + j];
91 }
92
93 // The index of `p` in srcPorts or dstPorts, or -1.
94 int srcIndex(Port p) const { return indexIn(srcPorts, p); }
95 int dstIndex(Port p) const { return indexIn(dstPorts, p); }
96
97 // Size the cells and the per-port state to srcPorts and dstPorts.
98 void resize() {
99 cells.assign(srcPorts.size() * dstPorts.size(), Cell());
100 packetOnlySrc = llvm::BitVector(srcPorts.size());
101 circuitOnlyDst = llvm::BitVector(dstPorts.size());
102 unitPacketFlows.resize(dstPorts.size());
103 resetUnits();
104 }
105
106 void resetUnits() {
107 dstUnits.clear();
108 dstUnits.grow(dstPorts.size());
109 for (auto &flows : unitPacketFlows)
110 flows.clear();
111 }
112
113 llvm::ArrayRef<int> unitFlows(int j) const {
114 return unitPacketFlows[dstUnits.findLeader(j)];
115 }
116
117 void addToUnit(int j, int flow) {
118 auto &flows = unitPacketFlows[dstUnits.findLeader(j)];
119 if (!llvm::is_contained(flows, flow))
120 flows.push_back(flow);
121 }
122
123 void joinUnits(int j, int k) {
124 j = dstUnits.findLeader(j);
125 k = dstUnits.findLeader(k);
126 if (j == k)
127 return;
128 int leader = dstUnits.join(j, k);
129 int other = leader == j ? k : j;
130 for (int flow : unitPacketFlows[other])
131 addToUnit(leader, flow);
132 unitPacketFlows[other].clear();
133 }
134
135 // update demand at the beginning of each dijkstraShortestPaths iteration
136 void updateDemand();
137
138 // Bumps an over-capacity cell's demand, all but ruling it out if a
139 // prioritized flow uses it, to keep prioritized flows' routes.
140 static void bumpDemand(Cell &c);
141
142private:
143 static int indexIn(llvm::ArrayRef<Port> ports, Port p) {
144 const Port *it = llvm::find(ports, p);
145 return it == ports.end() ? -1 : it - ports.begin();
146 }
147};
148
150 PathEndPoint() = default;
152
155
156 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
157 const PathEndPoint &s) {
158 return os << describeTilePort(s.coords, s.port);
159 }
160
161 bool operator<(const PathEndPoint &rhs) const {
162 return std::tie(coords, port) < std::tie(rhs.coords, rhs.port);
163 }
164
165 bool operator==(const PathEndPoint &rhs) const {
166 return std::tie(coords, port) == std::tie(rhs.coords, rhs.port);
167 }
168};
169
170struct Flow {
171 // -1 for a circuit flow.
173 bool isPriorityFlow = false;
175 std::vector<PathEndPoint> dsts;
176 // packet id carried by this flow (nullopt for circuit flows); a channel may
177 // be shared only among distinct ids so same-id flows never merge then fan
178 // out.
179 std::optional<int> packetId;
180};
181
182// A SwitchSetting defines the required settings for a Switchbox for a flow
183// SwitchSetting.srcs is the fanin
184// SwitchSetting.dsts is the fanout
186 SwitchSetting() = default;
187 SwitchSetting(std::vector<Port> srcs) : srcs(std::move(srcs)) {}
188 SwitchSetting(std::vector<Port> srcs, std::vector<Port> dsts)
189 : srcs(std::move(srcs)), dsts(std::move(dsts)) {}
190
191 std::vector<Port> srcs;
192 std::vector<Port> dsts;
193
194 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
195 const SwitchSetting &s) {
196 os << "{";
197 llvm::interleaveComma(llvm::map_range(s.srcs, describePort), os);
198 os << "} -> {";
199 llvm::interleaveComma(llvm::map_range(s.dsts, describePort), os);
200 return os << "}";
201 }
202
203 bool operator<(const SwitchSetting &rhs) const { return srcs < rhs.srcs; }
204};
205
206using SwitchSettings = std::map<TileID, SwitchSetting>;
207
208inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
209 const SwitchSettings &ss) {
210 os << "\tSwitchSettings: ";
211 for (const auto &[coords, setting] : ss)
212 os << coords << ": " << setting << " | ";
213 return os << "\n";
214}
215
216// A hop of a packet flow's tree, from one port to the next; `joined` when the
217// flow takes it by joining another flow's tree.
218struct TreeHop {
220 bool joined;
221
222 bool operator==(const TreeHop &rhs) const {
223 return from == rhs.from && to == rhs.to && joined == rhs.joined;
224 }
225};
226using PacketTrees = std::map<PathEndPoint, std::vector<TreeHop>>;
227
228// Whether packet flows from the two sources, with ids among the two sets, can
229// deadlock if they share an arbiter; see StreamConflicts::conflict.
231 std::function<bool(const PathEndPoint &, const std::set<int> &,
232 const PathEndPoint &, const std::set<int> &)>;
233
234// Described packet streams, and why the first two conflict.
236 std::vector<std::string> flows;
237 std::string why;
238};
239// The most pairwise-conflicting packet streams found crossing from the tiles
240// `low` holds to the others if `up` (else back), searching no further than
241// `limit` + 1; see Pathfinder::cutOverflow.
242using PacketsApartAcross = std::function<PacketsApart(
243 llvm::function_ref<bool(TileID)> low, bool up, size_t limit)>;
244
245// Packets `src` sends with ids `a` and `b` share a master port they leave
246// tile `at` by, which puts them on one arbiter. If `apart` is set, the
247// packets with id `b` for that destination on the tile reach it by a slave
248// port of their own instead.
249struct TreeSplit {
252 int a, b;
253 std::optional<PathEndPoint> apart;
254
255 bool operator<(const TreeSplit &rhs) const {
256 return std::tie(src, at, a, b, apart) <
257 std::tie(rhs.src, rhs.at, rhs.a, rhs.b, rhs.apart);
258 }
259};
260
261// What makes a routing unusable: switchbox connections to move, and where a
262// source's tree has to branch, and crowded tiles (see Pathfinder::relax).
264 std::vector<std::pair<TileID, Connect>> connections;
265 std::vector<TreeSplit> splits;
266 std::vector<TileID> crowded;
267 // Sources whose packet flows the routing put on one arbiter or link in a
268 // hold cycle, to keep apart like conflicting ones from then on.
269 std::vector<std::pair<PathEndPoint, PathEndPoint>> apart;
270 // Sources whose packet flows wait on each other at receivers they share
271 // in a hold cycle, so their trees should meet: each routes the ids the
272 // other does not send as a part of their own from then on.
273 std::vector<std::pair<PathEndPoint, PathEndPoint>> together;
274 // Sources whose tree waits on an arbiter it holds itself; they stop
275 // trunking (see RouteState::trunked).
276 std::vector<PathEndPoint> untrunk;
277 // Whether the connections all break the overlay's master sets; see
278 // RouteState::overlayMasters.
279 bool onlyOverlayMasters = false;
280};
281
282// A routing findPaths found.
283struct Routing {
284 // The switch settings of each source's flows.
285 std::map<PathEndPoint, SwitchSettings> settings;
286 // The packet flows' trees, by source.
288 // The switch settings of the packets a source sends with an id, where they
289 // are routed apart from the others the source sends.
290 std::map<std::pair<PathEndPoint, int>, SwitchSettings> idSettings;
291};
292
293// Why no legal routing was found, reported at `loc`, or the device if unset,
294// with `reason` if the router can say. A routing check's failure also names
295// the faults the router has to move.
296class RoutingFailure : public llvm::ErrorInfo<RoutingFailure> {
297public:
298 static char ID;
299
300 explicit RoutingFailure(std::string reason, RoutingFaults faults = {},
301 std::optional<mlir::Location> loc = std::nullopt)
302 : reason(std::move(reason)), faults(std::move(faults)), loc(loc) {}
303
304 void log(llvm::raw_ostream &os) const override;
305 std::error_code convertToErrorCode() const override {
306 return llvm::inconvertibleErrorCode();
307 }
308
309 std::string reason;
311 std::optional<mlir::Location> loc;
312};
313
314// A routing that can deadlock only where allow-deadlock-prone lets it: usable,
315// though the router would rather move the faults it names.
317 : public llvm::ErrorInfo<DeadlockProneRouting, RoutingFailure> {
318public:
319 static char ID;
320 using ErrorInfo::ErrorInfo;
321};
322
323// No legal routing around the routes prioritized flows keep, which the reason
324// already blames.
326 : public llvm::ErrorInfo<PinnedRoutingFailure, RoutingFailure> {
327public:
328 static char ID;
329 using ErrorInfo::ErrorInfo;
330};
331
332// Checks a routing that fits the fabric: a RoutingFailure if it is unusable,
333// success if it is accepted.
334using RoutingCheck = std::function<llvm::Error(const Routing &)>;
335
336// What packet flows are routed under.
338 // Routings the check rejects count as illegal; the connections it names
339 // are penalized like overused channels so later iterations avoid them, and
340 // the trees it splits branch where it says from then on. A routing it
341 // rejects as a DeadlockProneRouting is kept, and found if no better one is
342 // soon.
344 // Packet flows that conflict are steered off each other's master ports; see
345 // edgeWeight.
348 // The prioritized packet flows from these sources take these trees
349 // instead of being routed.
351 // Whether prioritized packet flows not pinned route first, keeping
352 // other flows off their channels; otherwise they route like the others.
353 bool prioritize = true;
354};
355
356// Congestion-negotiated routing: each iteration routes every flow by
357// Dijkstra, given each connection's demand, and raises the demand of the
358// connections used over capacity, until no connection is.
360public:
361 void initialize(int maxCol, int maxRow, const AIETargetModel &targetModel);
362 // Adds a flow from `src` to `dst`; failures to route it are reported at
363 // `loc` when given.
364 void addFlow(TileID srcCoords, Port srcPort, TileID dstCoords, Port dstPort,
365 std::optional<int> packetId, bool isPriorityFlow,
366 std::optional<mlir::Location> loc = std::nullopt);
367 void sortFlows();
368 // Reserves the connections `switchboxOp` already makes, so routing avoids
369 // them. Fails if it makes one the switchbox cannot.
370 mlir::LogicalResult addFixedConnection(SwitchboxOp switchboxOp);
371 // Keeps routes out of the switchbox at `coords`.
372 void excludeTile(TileID coords);
373 // A RoutingFailure if no legal routing is found in `maxIterations`.
374 llvm::Expected<Routing> findPaths(int maxIterations);
375 void setPacketConstraints(PacketConstraints c) { constraints = std::move(c); }
376 // Loosens the packet constraints by one step after findPaths found no
377 // routing; false once no step is left or no packet stream took part in the
378 // failure. Packet flows start sharing channels only within their
379 // destination group. The steps, each skipped if it changes nothing: share
380 // channels with any packet flow; cap the fan-out of tiles the routing check
381 // found out of packet rules or msels to packetFanoutCap channels per
382 // direction; route the second id of an unbranchable split apart, which
383 // restarts sharing and caps; then share and cap again; route the ids a
384 // source sends that a source it must keep apart from does not as a part of
385 // their own, which restarts sharing and caps; then share and cap again.
386 bool relax();
387
388private:
389 // A directed edge in the dense routing graph: from some node to node `dst`,
390 // realized by cell (i, j) of `sb`. `sb` points into `graph`, so demand reads
391 // always see the current iteration's weights.
392 struct Edge {
393 int dst;
395 int i;
396 int j;
397 };
398
399 // A `Port` is (bundle, channel) with no direction, so one dense node stands
400 // for both a switchbox port's input side and its output side. Dijkstra
401 // therefore searches over states, not nodes: a state is a node paired with
402 // the side of that port the stream is currently on. A stream enters a
403 // switchbox on an input port, crosses the crossbar once to an output port,
404 // and then rides the wire to the neighbour's input port -- so In only ever
405 // takes intra-switchbox edges and Out only ever takes inter-switchbox ones.
406 // Without the split, Dijkstra can chain two crossbar hops through one port
407 // and turn the stream around inside a switchbox; the settings it emits then
408 // dead-end and AIECreatePathFindFlows reports the flow as unroutable.
409 enum PortSide : int { In = 0, Out = 1 };
410 static int stateId(int nodeId, PortSide side) { return 2 * nodeId + side; }
411 static int stateNode(int state) { return state >> 1; }
412
413 // Build the dense integer node numbering and per-node adjacency from `graph`
414 // and `flows`. Topology is fixed across congestion iterations, so this runs
415 // once. A node's crossbar edges come before its wire edges, each in the order
416 // of the PathEndPoints they reach, so Dijkstra breaks ties the same way every
417 // run.
418 void buildRoutingGraph();
419
420 // The cost of taking `e`, as dijkstraShortestPaths weighs it.
421 double edgeWeight(const Edge &e, std::optional<int> packetId,
422 const llvm::BitVector *avoid,
423 const llvm::BitVector *avoidBranch) const;
424
425 // Dijkstra over the dense graph from the states in `seeds`, each starting at
426 // its cost in `seedCosts`. Fills `preds` (predecessor state id, or -1) and
427 // `predEdge` (the edge taken to reach each state). Reuses the scratch buffers
428 // below. Each edge costs its edgeWeight given `packetId`, `avoid` and, from a
429 // state in `branchAvoid`, the flows it maps to. States in `stops` are reached
430 // but not left, and a crossbar hop is taken only if `mayCross` allows it. The
431 // search ends once every state in `targets` is settled; only their `distance`
432 // and paths are final then.
433 void dijkstraShortestPaths(
434 llvm::ArrayRef<int> seeds, llvm::ArrayRef<double> seedCosts,
435 std::optional<int> packetId, const llvm::BitVector *avoid = nullptr,
436 const llvm::DenseMap<int, llvm::BitVector> *branchAvoid = nullptr,
437 const llvm::DenseSet<int> *stops = nullptr,
438 llvm::ArrayRef<int> targets = {},
439 llvm::function_ref<bool(int, int)> mayCross = nullptr);
440
441 struct RouteState;
442 struct TreeBuilder;
443 // Route `flow`'s tree around those routed before it this iteration. A
444 // RoutingFailure if it reaches no path to a destination.
445 llvm::Error routePart(RouteState &st, int flow);
446 // Steer the next iteration away from what the routing check faulted.
447 // Returns the illegal edges the faults count as.
448 int applyRoutingFaults(RouteState &st, const RoutingFaults &faults);
449 // A RoutingFailure saying why the last iteration's routing does not fit.
450 llvm::Error explainNoRouting(const RouteState &st) const;
451 // A RoutingFailure if the flows crossing some row or column boundary need
452 // more channels across it than it has, however they are routed.
453 llvm::Error cutOverflow() const;
454 bool hasRoom(const SwitchboxConnect &sb) const;
455 // The steps of relax.
456 bool shareAllChannels();
457 bool capCrowdedFanOut();
458 bool routeIdsApart();
459 bool splitSharedIds();
460 bool stopMeeting();
461
462 // Flows to be routed
463 std::vector<Flow> flows;
464 // The packet ids each source sends each destination.
465 std::map<std::pair<PathEndPoint, PathEndPoint>, llvm::SmallVector<int, 2>>
466 packetIdsTo;
467 // The packet ids each source sends, to any destination.
468 std::map<PathEndPoint, std::set<int>> idsBySource() const;
469 // The packet ids each source sends in prioritized flows.
470 std::map<PathEndPoint, std::set<int>> priorityIds;
471 // Where each source's flow to each destination was declared.
472 std::map<PathEndPoint, std::map<PathEndPoint, mlir::Location>> flowLocs;
473 std::optional<mlir::Location> flowLoc(const PathEndPoint &src,
474 const PathEndPoint *dst) const;
475 // The routing graph, by the tiles a SwitchboxConnect connects: a tile to
476 // itself for its switchbox, or to a neighbour for the wires between them.
477 std::map<std::pair<TileID, TileID>, SwitchboxConnect> graph;
478
479 // Dense routing graph (built once by buildRoutingGraph()).
480 bool graphBuilt = false;
481 std::map<PathEndPoint, int> nodeIds; // PathEndPoint -> dense id
482 std::vector<PathEndPoint> nodes; // dense id -> PathEndPoint
483 std::vector<std::vector<Edge>> adjacency; // dense id -> out-edges
484 std::vector<size_t> wireEdgesBegin; // dense id -> first wire edge
485
486 // Dijkstra scratch, indexed by state id (2 * nodes.size()) and reused across
487 // calls.
488 std::vector<double> distance;
489 std::vector<uint64_t> indexInHeap;
490 std::vector<int8_t> colors;
491 std::vector<int> preds;
492 std::vector<Edge> predEdge;
493
494 int getOrAddNodeId(const PathEndPoint &pep);
495
496 PacketConstraints constraints;
497 // Why the routing check rejected the last routing it rejected.
498 std::string checkReason;
499 // Whether packet streams took part in the last failure: the routing check
500 // rejected a routing, or packet streams cross a link left overused.
501 bool packetsFailed = true;
502 bool shareChannels = false, idsApart = false, splitShared = false;
503 // Trees that share destinations no longer meet (see TreeBuilder::meet), so
504 // what is left of their hazard is a hold cycle through those receivers.
505 bool meetApart = false;
506 // Whether a tree met another in any attempt, so stopping meeting can change
507 // anything.
508 bool treesMet = false;
509 // The device's columns and rows; the graph has tiles one past each.
510 int columns = 0, rows = 0;
511 size_t relaxStep = 0;
512 llvm::DenseSet<TileID> crowdedTiles, cappedTiles;
513};
514
515// Routes the flows of a device with a Pathfinder, and finds or creates the
516// tiles, switchboxes and shim muxes the routing is lowered onto.
518public:
519 // A RoutingFailure if the flows in `device` have no legal routing.
520 llvm::Error runAnalysis(DeviceOp &device);
521
522 int getMaxCol() const { return maxCol; }
523 int getMaxRow() const { return maxRow; }
524
525 TileOp getTile(mlir::OpBuilder &builder, int col, int row);
526 TileOp getTile(mlir::OpBuilder &builder, const TileID &tileId);
527 SwitchboxOp getSwitchbox(mlir::OpBuilder &builder, int col, int row);
528 ShimMuxOp getShimMux(mlir::OpBuilder &builder, int col);
529
530 // The ops at `tile` the analysis has found or created, or null.
531 TileOp lookupTile(TileID tile) const { return coordToTile.lookup(tile); }
532 SwitchboxOp lookupSwitchbox(TileID tile) const {
533 return coordToSwitchbox.lookup(tile);
534 }
535 ShimMuxOp lookupShimMux(int col) const {
536 return coordToShimMux.lookup({col, 0});
537 }
538
540 // The routing runAnalysis found.
542 // The sources of the circuit flows lowered so far.
543 std::set<PathEndPoint> processedFlows;
544
545private:
546 // how long until declared unroutable
547 static constexpr int maxIterations = 1000;
548
549 int maxCol = 0, maxRow = 0;
550 llvm::DenseMap<TileID, TileOp> coordToTile;
551 llvm::DenseMap<TileID, SwitchboxOp> coordToSwitchbox;
552 llvm::DenseMap<TileID, ShimMuxOp> coordToShimMux;
553};
554
555} // namespace xilinx::AIE
556
557#endif
ShimMuxOp getShimMux(mlir::OpBuilder &builder, int col)
SwitchboxOp getSwitchbox(mlir::OpBuilder &builder, int col, int row)
SwitchboxOp lookupSwitchbox(TileID tile) const
TileOp getTile(mlir::OpBuilder &builder, const TileID &tileId)
TileOp lookupTile(TileID tile) const
TileOp getTile(mlir::OpBuilder &builder, int col, int row)
llvm::Error runAnalysis(DeviceOp &device)
std::set< PathEndPoint > processedFlows
ShimMuxOp lookupShimMux(int col) const
llvm::Expected< Routing > findPaths(int maxIterations)
void setPacketConstraints(PacketConstraints c)
void excludeTile(TileID coords)
void addFlow(TileID srcCoords, Port srcPort, TileID dstCoords, Port dstPort, std::optional< int > packetId, bool isPriorityFlow, std::optional< mlir::Location > loc=std::nullopt)
void initialize(int maxCol, int maxRow, const AIETargetModel &targetModel)
mlir::LogicalResult addFixedConnection(SwitchboxOp switchboxOp)
void log(llvm::raw_ostream &os) const override
RoutingFailure(std::string reason, RoutingFaults faults={}, std::optional< mlir::Location > loc=std::nullopt)
std::optional< mlir::Location > loc
std::error_code convertToErrorCode() const override
std::function< llvm::Error(const Routing &)> RoutingCheck
int shimMuxChannelTo(Port dst)
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
std::function< bool(const PathEndPoint &, const std::set< int > &, const PathEndPoint &, const std::set< int > &)> PacketConflict
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const SwitchSettings &ss)
std::function< PacketsApart( llvm::function_ref< bool(TileID)> low, bool up, size_t limit)> PacketsApartAcross
int shimMuxChannelFrom(Port src)
std::string describeTilePort(TileID tile, Port port)
Names a tile port the way diagnostics do, e.g. "(0, 2) DMA:1".
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
Definition AIEDialect.h:265
std::map< TileID, SwitchSetting > SwitchSettings
std::string describePort(Port port)
Names a port the way diagnostics do, e.g. "DMA:1".
std::map< PathEndPoint, std::vector< TreeHop > > PacketTrees
std::vector< PathEndPoint > dsts
std::optional< int > packetId
std::vector< std::string > flows
PathEndPoint(TileID coords, Port port)
bool operator==(const PathEndPoint &rhs) const
friend llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const PathEndPoint &s)
bool operator<(const PathEndPoint &rhs) const
std::vector< std::pair< TileID, Connect > > connections
std::vector< PathEndPoint > untrunk
std::vector< std::pair< PathEndPoint, PathEndPoint > > together
std::vector< TreeSplit > splits
std::vector< TileID > crowded
std::vector< std::pair< PathEndPoint, PathEndPoint > > apart
std::map< PathEndPoint, SwitchSettings > settings
std::map< std::pair< PathEndPoint, int >, SwitchSettings > idSettings
std::vector< Port > dsts
bool operator<(const SwitchSetting &rhs) const
friend llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const SwitchSetting &s)
SwitchSetting(std::vector< Port > srcs)
SwitchSetting(std::vector< Port > srcs, std::vector< Port > dsts)
std::vector< Port > srcs
llvm::SmallDenseMap< int, int, 2 > packetIds
llvm::IntEqClasses dstUnits
llvm::ArrayRef< int > unitFlows(int j) const
std::vector< Port > dstPorts
std::vector< Port > srcPorts
std::vector< llvm::SmallVector< int, 2 > > unitPacketFlows
SwitchboxConnect(TileID srcCoords, TileID dstCoords)
static void bumpDemand(Cell &c)
void addToUnit(int j, int flow)
Cell & at(size_t i, size_t j)
std::vector< Cell > cells
const Cell & at(size_t i, size_t j) const
bool operator==(const TreeHop &rhs) const
std::optional< PathEndPoint > apart
bool operator<(const TreeSplit &rhs) const