12#include "mlir/Pass/Pass.h"
15#define GEN_PASS_DEF_AIESPLITFLOWVIAS
16#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
29static bool isDirectWire(Value srcTile, WireBundle srcBundle,
int srcChannel,
30 Value dstTile, WireBundle dstBundle,
int dstChannel) {
31 if (srcChannel != dstChannel) {
34 auto src = srcTile.getDefiningOp<TileOp>();
35 auto dst = dstTile.getDefiningOp<TileOp>();
39 int sc = src.colIndex(), sr = src.rowIndex();
40 int dc = dst.colIndex(), dr = dst.rowIndex();
42 if (srcBundle == WireBundle::North && dstBundle == WireBundle::South &&
46 if (srcBundle == WireBundle::South && dstBundle == WireBundle::North &&
52 if (srcBundle == WireBundle::East && dstBundle == WireBundle::West &&
56 if (srcBundle == WireBundle::West && dstBundle == WireBundle::East &&
64static bool isDirectShimMux(Value srcTile, WireBundle srcBundle,
int srcChannel,
65 Value dstTile, WireBundle dstBundle,
67 auto tile = srcTile.getDefiningOp<TileOp>();
68 if (srcTile != dstTile || !tile || !tile.isShimNOCorPLTile())
70 if (dstBundle == WireBundle::South)
72 if (srcBundle == WireBundle::South)
77static FailureOr<std::pair<Value, WireBundle>> wireEndpoint(DeviceOp device,
81 auto tile = cast<TileOp>(tileValue.getDefiningOp());
82 if (!llvm::is_contained({WireBundle::North, WireBundle::South,
83 WireBundle::East, WireBundle::West},
85 return std::make_pair(tileValue, bundle);
88 tile.getTileID(),
Port{bundle, 0});
91 TileID neighbor = endpoint->first;
93 for (TileOp candidate : device.getOps<TileOp>())
94 if (candidate.getTileID() == neighbor)
95 return std::pair<Value, WireBundle>(candidate.getResult(),
96 endpoint->second.bundle);
98 OpBuilder::InsertionGuard guard(builder);
99 builder.setInsertionPoint(tile);
100 return std::pair<Value, WireBundle>(
101 TileOp::create(builder, tile.getLoc(), neighbor.col, neighbor.row)
103 endpoint->second.bundle);
106static void emitPacketFlow(OpBuilder &builder, Location loc, Operation *anchor,
107 Value srcTile, WireBundle srcBundle,
int srcChannel,
108 Value dstTile, WireBundle dstBundle,
int dstChannel,
109 int packetID, IntegerAttr maskAttr,
110 BoolAttr keepPktHeaderAttr,
111 BoolAttr priorityRouteAttr) {
112 OpBuilder::InsertionGuard guard(builder);
113 builder.setInsertionPoint(anchor);
114 auto pf = PacketFlowOp::create(builder, loc,
static_cast<uint8_t
>(packetID),
115 keepPktHeaderAttr, priorityRouteAttr);
117 pf.setMaskAttr(maskAttr);
118 PacketFlowOp::ensureTerminator(pf.getPorts(), builder, loc);
119 builder.setInsertionPoint(pf.getPorts().front().getTerminator());
120 PacketSourceOp::create(builder, loc, srcTile, srcBundle, srcChannel);
121 PacketDestOp::create(builder, loc, dstTile, dstBundle, dstChannel);
129static void emitRoutableSegment(OpBuilder &builder, Location loc,
130 Operation *anchor, Value srcTile,
131 WireBundle srcBundle,
int srcChannel,
132 Value dstTile, WireBundle dstBundle,
133 int dstChannel,
int packetID,
134 mlir::IntegerAttr maskAttr = {},
135 mlir::BoolAttr keepPktHeaderAttr = {},
136 mlir::BoolAttr priorityRouteAttr = {}) {
137 if (srcTile == dstTile && srcBundle == dstBundle &&
138 srcChannel == dstChannel) {
141 if (isDirectWire(srcTile, srcBundle, srcChannel, dstTile, dstBundle,
145 OpBuilder::InsertionGuard guard(builder);
146 builder.setInsertionPoint(anchor);
148 FlowOp::create(builder, loc, srcTile, srcBundle, srcChannel, dstTile,
149 dstBundle, dstChannel);
154 emitPacketFlow(builder, loc, anchor, srcTile, srcBundle, srcChannel, dstTile,
155 dstBundle, dstChannel, packetID, maskAttr, keepPktHeaderAttr,
159struct AIESplitFlowViasPass
160 :
public xilinx::AIE::impl::AIESplitFlowViasBase<AIESplitFlowViasPass> {
161 void runOnOperation()
override {
162 DeviceOp device = getOperation();
163 OpBuilder builder(device.getContext());
165 SmallVector<FlowOp> flowsWithVias;
166 for (
auto flow : device.getOps<FlowOp>()) {
167 if (!flow.getVias().empty()) {
168 flowsWithVias.push_back(flow);
172 for (FlowOp flow : flowsWithVias) {
173 ArrayRef<int32_t> ingressBundles =
174 flow.getViaIngressBundlesAttr().asArrayRef();
175 ArrayRef<int32_t> ingressChannels =
176 flow.getViaIngressChannelsAttr().asArrayRef();
177 ArrayRef<int32_t> egressBundles =
178 flow.getViaEgressBundlesAttr().asArrayRef();
179 ArrayRef<int32_t> egressChannels =
180 flow.getViaEgressChannelsAttr().asArrayRef();
181 Location loc = flow.getLoc();
184 Value srcTile = flow.getSource();
185 WireBundle srcBundle = flow.getSourceBundle();
186 int srcChannel = flow.getSourceChannel();
188 auto emitSegment = [&](Value dstTile, WireBundle dstBundle,
190 emitRoutableSegment(builder, loc, flow, srcTile, srcBundle, srcChannel,
191 dstTile, dstBundle, dstChannel, -1);
194 for (
size_t i = 0, e = flow.getVias().size(); i < e; i++) {
195 Value viaTile = flow.getVias()[i];
196 auto ingressBundle =
static_cast<WireBundle
>(ingressBundles[i]);
197 int ingressChannel = ingressChannels[i];
198 auto egressBundle =
static_cast<WireBundle
>(egressBundles[i]);
199 int egressChannel = egressChannels[i];
202 isDirectShimMux(srcTile, srcBundle, srcChannel, viaTile,
203 ingressBundle, ingressChannel);
206 isDirectWire(srcTile, srcBundle, srcChannel, viaTile,
207 ingressBundle, ingressChannel);
208 auto segmentSource = std::make_pair(srcTile, srcBundle);
209 if (i > 0 && !directWire) {
210 auto endpoint = wireEndpoint(device, builder, srcTile, srcBundle);
211 if (failed(endpoint)) {
212 flow.emitOpError(
"via egress has no neighboring tile");
213 return signalPassFailure();
215 segmentSource = *endpoint;
218 wireEndpoint(device, builder, viaTile, ingressBundle);
219 if (failed(wireSource)) {
220 flow.emitOpError(
"via ingress has no neighboring tile");
221 return signalPassFailure();
223 auto [wireTile, wireBundle] = *wireSource;
224 srcTile = segmentSource.first;
225 srcBundle = segmentSource.second;
226 emitSegment(wireTile, wireBundle, ingressChannel);
229 Value localSrcTile = foldIngress ? srcTile : viaTile;
230 WireBundle localSrcBundle = foldIngress ? srcBundle : ingressBundle;
231 int localSrcChannel = foldIngress ? srcChannel : ingressChannel;
233 Value nextTile = i + 1 < e ? flow.getVias()[i + 1] : flow.getDest();
234 WireBundle nextBundle =
235 i + 1 < e ?
static_cast<WireBundle
>(ingressBundles[i + 1])
236 : flow.getDestBundle();
238 i + 1 < e ? ingressChannels[i + 1] : flow.getDestChannel();
239 bool foldEgress = isDirectShimMux(viaTile, egressBundle, egressChannel,
240 nextTile, nextBundle, nextChannel);
242 OpBuilder::InsertionGuard guard(builder);
243 builder.setInsertionPoint(flow);
244 FlowOp::create(builder, loc, localSrcTile, localSrcBundle,
245 localSrcChannel, foldEgress ? nextTile : viaTile,
246 foldEgress ? nextBundle : egressBundle,
247 foldEgress ? nextChannel : egressChannel);
249 srcTile = foldEgress ? nextTile : viaTile;
250 srcBundle = foldEgress ? nextBundle : egressBundle;
251 srcChannel = foldEgress ? nextChannel : egressChannel;
254 if (srcTile != flow.getDest() || srcBundle != flow.getDestBundle() ||
255 srcChannel != flow.getDestChannel()) {
256 auto endpoint = wireEndpoint(device, builder, srcTile, srcBundle);
257 if (failed(endpoint)) {
258 flow.emitOpError(
"via egress has no neighboring tile");
259 return signalPassFailure();
261 std::tie(srcTile, srcBundle) = *endpoint;
263 emitSegment(flow.getDest(), flow.getDestBundle(), flow.getDestChannel());
270 SmallVector<PacketFlowOp> pktFlowsWithVias;
271 for (
auto pf : device.getOps<PacketFlowOp>()) {
272 if (!pf.getVias().empty()) {
273 pktFlowsWithVias.push_back(pf);
277 for (PacketFlowOp pf : pktFlowsWithVias) {
278 Location loc = pf.getLoc();
280 ArrayRef<int32_t> inB = pf.getViaIngressBundlesAttr().asArrayRef();
281 ArrayRef<int32_t> inC = pf.getViaIngressChannelsAttr().asArrayRef();
282 ArrayRef<int32_t> egB = pf.getViaEgressBundlesAttr().asArrayRef();
283 ArrayRef<int32_t> egC = pf.getViaEgressChannelsAttr().asArrayRef();
287 PacketSourceOp source;
289 for (Operation &op : pf.getPorts().front()) {
290 if (
auto s = dyn_cast<PacketSourceOp>(op)) {
292 }
else if (
auto d = dyn_cast<PacketDestOp>(op)) {
296 Value srcTile = source.getTile();
297 WireBundle srcBundle = source.getBundle();
298 int srcChannel = source.getChannel();
299 auto emitSegment = [&](Value dstTile, WireBundle dstBundle,
300 int dstChannel, BoolAttr keepPktHeader = {}) {
301 emitRoutableSegment(builder, loc, pf, srcTile, srcBundle, srcChannel,
302 dstTile, dstBundle, dstChannel,
id,
303 pf.getMaskAttr(), keepPktHeader,
304 pf.getPriorityRouteAttr());
307 for (
size_t i = 0, e = pf.getVias().size(); i < e; i++) {
308 Value viaTile = pf.getVias()[i];
309 auto ingress =
static_cast<WireBundle
>(inB[i]);
310 int ingressChannel = inC[i];
311 auto egress =
static_cast<WireBundle
>(egB[i]);
312 int egressChannel = egC[i];
314 bool foldIngress = isDirectShimMux(srcTile, srcBundle, srcChannel,
315 viaTile, ingress, ingressChannel);
317 bool directWire = isDirectWire(srcTile, srcBundle, srcChannel,
318 viaTile, ingress, ingressChannel);
319 auto segmentSource = std::make_pair(srcTile, srcBundle);
320 if (i > 0 && !directWire) {
321 auto endpoint = wireEndpoint(device, builder, srcTile, srcBundle);
322 if (failed(endpoint)) {
323 pf.emitOpError(
"via egress has no neighboring tile");
324 return signalPassFailure();
326 segmentSource = *endpoint;
328 auto wireSource = wireEndpoint(device, builder, viaTile, ingress);
329 if (failed(wireSource)) {
330 pf.emitOpError(
"via ingress has no neighboring tile");
331 return signalPassFailure();
333 auto [wireTile, wireBundle] = *wireSource;
334 srcTile = segmentSource.first;
335 srcBundle = segmentSource.second;
336 emitSegment(wireTile, wireBundle, ingressChannel);
339 Value localSrcTile = foldIngress ? srcTile : viaTile;
340 WireBundle localSrcBundle = foldIngress ? srcBundle : ingress;
341 int localSrcChannel = foldIngress ? srcChannel : ingressChannel;
343 Value nextTile = i + 1 < e ? pf.getVias()[i + 1] : dest.getTile();
344 WireBundle nextBundle =
345 i + 1 < e ?
static_cast<WireBundle
>(inB[i + 1]) : dest.getBundle();
346 int nextChannel = i + 1 < e ? inC[i + 1] : dest.getChannel();
347 bool foldEgress = isDirectShimMux(viaTile, egress, egressChannel,
348 nextTile, nextBundle, nextChannel);
350 BoolAttr keepPktHeader;
351 if ((foldEgress && nextTile == dest.getTile() &&
352 nextBundle == dest.getBundle() &&
353 nextChannel == dest.getChannel()) ||
354 (viaTile == dest.getTile() && egress == dest.getBundle() &&
355 egressChannel == dest.getChannel()))
356 keepPktHeader = pf.getKeepPktHeaderAttr();
358 builder, loc, pf, localSrcTile, localSrcBundle, localSrcChannel,
359 foldEgress ? nextTile : viaTile, foldEgress ? nextBundle : egress,
360 foldEgress ? nextChannel : egressChannel,
id, pf.getMaskAttr(),
361 keepPktHeader, pf.getPriorityRouteAttr());
363 srcTile = foldEgress ? nextTile : viaTile;
364 srcBundle = foldEgress ? nextBundle : egress;
365 srcChannel = foldEgress ? nextChannel : egressChannel;
368 if (srcTile != dest.getTile() || srcBundle != dest.getBundle() ||
369 srcChannel != dest.getChannel()) {
370 auto endpoint = wireEndpoint(device, builder, srcTile, srcBundle);
371 if (failed(endpoint)) {
372 pf.emitOpError(
"via egress has no neighboring tile");
373 return signalPassFailure();
375 std::tie(srcTile, srcBundle) = *endpoint;
377 emitSegment(dest.getTile(), dest.getBundle(), dest.getChannel(),
378 pf.getKeepPktHeaderAttr());
387 return std::make_unique<AIESplitFlowViasPass>();
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::unique_ptr< mlir::OperationPass< DeviceOp > > createAIESplitFlowViasPass()
int shimMuxChannelFrom(Port src)
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
std::optional< std::pair< TileID, Port > > getConnectingWireEndpoint(const AIETargetModel &targetModel, TileID tile, Port port)