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