MLIR-AIE 1.4.5.dev
AIEAssignPacketIds.cpp
Go to the documentation of this file.
1//===- AIEAssignPacketIds.cpp -----------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2026 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
12
13#include "mlir/Pass/Pass.h"
14
15using namespace mlir;
16using namespace xilinx;
17using namespace xilinx::AIE;
18
19namespace xilinx::AIE {
20#define GEN_PASS_DEF_AIEASSIGNPACKETIDS
21#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
22} // namespace xilinx::AIE
23
24namespace {
25
26struct AIEAssignPacketIdsPass
27 : public xilinx::AIE::impl::AIEAssignPacketIdsBase<AIEAssignPacketIdsPass> {
28 using Base::Base;
29
30 void runOnOperation() override {
31 DeviceOp device = getOperation();
32 PacketIdSpace space(device);
33
34 // Pinned ids are checked before any are handed out, so a bad pin is
35 // reported as one rather than surfacing as an exhausted field.
36 for (auto route : device.getOps<RouteOp>()) {
37 std::optional<PacketInfoAttr> packet = route.getPacket();
38 if (packet && packet->isAssigned() &&
39 packet->assignedId() > space.maxId()) {
40 route.emitOpError("pkt_id ")
41 << packet->assignedId() << " is out of range (max " << space.maxId()
42 << ")";
43 return signalPassFailure();
44 }
45 }
46
47 // Ids go out in structural order, so a design declared in another order
48 // or under other names gets the same ones.
49 // The pass flag is a default for routes that express no preference, so a
50 // device may mix circuit- and packet-switched connections.
51 SmallVector<RouteOp> unpinned;
52 for (auto route : device.getOps<RouteOp>()) {
53 std::optional<PacketInfoAttr> packet = route.getPacket();
54 if ((packet || clPacketSwObjectFifos) &&
55 !(packet && packet->isAssigned()))
56 unpinned.push_back(route);
57 }
58 if (unpinned.size() > 1) {
59 DenseMap<Operation *, unsigned> rank = StructuralGraph::of(device).rank();
60 llvm::stable_sort(unpinned, [&](RouteOp a, RouteOp b) {
61 return rank.lookup(a) < rank.lookup(b);
62 });
63 }
64
65 // A DMA program states its BDs' header itself, so it cannot use an id
66 // handed out here. Indexed once instead of a device-wide
67 // SymbolTable::getSymbolUses walk per unpinned route's source: the first
68 // DMAStartOp naming a given endpoint is all the loop below needs.
69 DenseMap<StringRef, DMAStartOp> dmaStartByEndpoint;
70 device.walk([&](DMAStartOp start) {
71 if (FlatSymbolRefAttr name = start.getEndpoint())
72 dmaStartByEndpoint.try_emplace(name.getValue(), start);
73 });
74
75 for (auto route : unpinned) {
76 std::optional<PacketInfoAttr> packet = route.getPacket();
77 for (StringRef source : route.getSourceNames()) {
78 auto it = dmaStartByEndpoint.find(source);
79 if (it == dmaStartByEndpoint.end())
80 continue;
81 it->second.emitOpError("names @")
82 << source
83 << ", the source of a packet-switched route without a pinned "
84 "pkt_id; pin pkt_id on each route it sources and state that "
85 "header in each of the program's BDs";
86 return signalPassFailure();
87 }
88 std::optional<int> id = space.takeLowestFrom();
89 if (!id) {
90 route.emitOpError("max number of packet IDs reached");
91 return signalPassFailure();
92 }
93 uint16_t type = packet ? packet->getPktType() : 0;
94 route.setPacketAttr(PacketInfoAttr::get(device.getContext(), type, *id));
95 }
96 }
97};
98
99} // namespace
100
101std::unique_ptr<OperationPass<DeviceOp>>
103 return std::make_unique<AIEAssignPacketIdsPass>();
104}
105
106std::unique_ptr<OperationPass<DeviceOp>>
108 AIEAssignPacketIdsOptions options;
109 options.clPacketSwObjectFifos = packetSwitched;
110 return std::make_unique<AIEAssignPacketIdsPass>(options);
111}
std::optional< int > takeLowestFrom(int from=0)
Takes and returns the lowest free id at or above from, or nothing when the field is exhausted.
int maxId() const
The largest id the target's header field holds.
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIEAssignPacketIdsPass()
llvm::DenseMap< mlir::Operation *, unsigned > rank() const
Rank the nodes by their features and then, a round at a time until no class splits,...
static StructuralGraph of(DeviceOp device)
The ops directly in device but its runtime sequences, each with the ops nested in it,...