12#include "mlir/Pass/Pass.h"
14#include "llvm/ADT/STLExtras.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/ADT/StringRef.h"
25#define GEN_PASS_DEF_AIECERTVERIFY
26#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
32#define DEBUG_TYPE "cert-verify"
38static int getUcGroupId(Operation *op) {
39 auto group = op->getParentOfType<AIEX::CertAttachToGroupOp>();
40 return group ? group.getGroupID() : 0;
46static LogicalResult checkLocalBarrierColocation(AIE::DeviceOp device) {
47 LogicalResult result = success();
49 std::map<std::pair<int, int>, Operation *> firstScope;
51 [&](AIEX::CertLocalBarrierOp barrier) {
52 int uc = getUcGroupId(barrier);
53 int id = barrier.getLocalBarrierId();
54 Operation *scope = barrier->getParentOfType<AIEX::CertPageOp>();
56 scope = barrier->getParentOfType<AIEX::CertJobOp>();
57 auto key = std::make_pair(uc,
id);
58 auto it = firstScope.find(key);
59 if (it == firstScope.end()) {
60 firstScope[key] = scope;
63 if (it->second != scope) {
65 <<
"cert.local_barrier with local_barrier_id " <<
id <<
" in uC "
66 << uc <<
" must be on the same page as its other participants";
77static LogicalResult checkWaitTctsUniqueness(AIE::DeviceOp device) {
78 LogicalResult result = success();
80 std::map<std::tuple<Operation *, int, int>, Operation *> seen;
81 device.walk([&](AIEX::CertWaitTCTSOp wait) {
82 int tile = wait.getTileId();
83 int channel = wait.getChannelId();
84 Operation *job = wait->getParentOfType<AIEX::CertJobOp>();
85 Operation *scope = wait->getParentOfType<AIEX::CertPageOp>();
88 auto key = std::make_tuple(scope, tile, channel);
89 auto it = seen.find(key);
90 if (it == seen.end()) {
95 if (it->second == job)
97 wait.emitError() <<
"more than one job on this cert.page waits on tile "
98 << tile <<
" channel " << channel <<
" in uC "
100 <<
"; at most one job per page may wait_tcts on a given "
107static std::set<int> computePresentUcs(AIE::DeviceOp device) {
108 std::set<int> present;
109 device.walk([&](AIEX::CertAttachToGroupOp group) {
110 present.insert(group.getGroupID());
112 if (!device.getBody()->getOps<AIEX::CertPageOp>().empty() ||
113 !device.getBody()->getOps<AIEX::CertJobOp>().empty() ||
114 !device.getBody()->getOps<AIEX::CertSectionOp>().empty())
121static LogicalResult checkPreemptConsistency(AIE::DeviceOp device) {
122 std::map<int, std::multiset<int>> preemptIds;
123 std::map<int, AIEX::CertAttachToGroupOp> repAttach;
124 std::set<int> present;
127 device.walk([&](AIEX::CertAttachToGroupOp group) {
128 int uc = group.getGroupID();
130 if (!repAttach.count(uc))
131 repAttach[uc] = group;
135 if (!device.getBody()->getOps<AIEX::CertPageOp>().empty() ||
136 !device.getBody()->getOps<AIEX::CertJobOp>().empty() ||
137 !device.getBody()->getOps<AIEX::CertSectionOp>().empty())
141 device.walk([&](AIEX::CertPreemptOp preempt) {
142 int uc = getUcGroupId(preempt);
144 preemptIds[uc].insert(preempt.getId());
147 if (present.size() < 2)
150 int ref = *present.begin();
151 const std::multiset<int> &refSet = preemptIds[ref];
152 LogicalResult result = success();
153 for (
int uc : present) {
156 if (preemptIds[uc] != refSet) {
157 Operation *loc = repAttach.count(uc) ? repAttach[uc].getOperation()
158 : device.getOperation();
160 <<
"cert.preempt ids on uC " << uc <<
" differ from uC " << ref
161 <<
"; all uCs must have the same preempt ids (G-preempt)";
172static LogicalResult checkGroupIds(AIE::DeviceOp device) {
175 LogicalResult result = success();
176 auto checkId = [&](Operation *op, int64_t id, llvm::StringRef what) {
177 if (id < 0 || id >= numUcs) {
178 op->emitError() << what <<
" " <<
id <<
" is not a valid uC id [0, "
183 device.walk([&](AIEX::CertAttachToGroupOp g) {
184 checkId(g, g.getGroupID(),
"cert.attach_to_group group id");
187 device.walk([&](AIEX::CertPageOp p) {
188 if (
auto pl = p.getPlacementAttr())
189 checkId(p, pl.getInt(),
"cert.page placement");
200static LogicalResult checkRemoteBarrierParties(AIE::DeviceOp device) {
201 std::set<int> present = computePresentUcs(device);
202 LogicalResult result = success();
204 std::map<int, SmallVector<AIEX::CertRemoteBarrierOp, 4>> byId;
205 device.walk([&](AIEX::CertRemoteBarrierOp b) {
206 byId[b.getRemoteBarrierId()].push_back(b);
209 for (
auto &entry : byId) {
210 int id = entry.first;
211 SmallVector<AIEX::CertRemoteBarrierOp, 4> &occs = entry.second;
214 uint32_t mask = occs.front().getPartyMask();
215 bool masksAgree = llvm::all_of(occs, [&](AIEX::CertRemoteBarrierOp b) {
216 return b.getPartyMask() == mask;
220 b.emitError() <<
"cert.remote_barrier id " <<
id
221 <<
" occurrences disagree on party_mask";
227 std::map<int, int> occPerUc;
228 for (
auto b : occs) {
229 int own = getUcGroupId(b);
231 if (own >= 0 && own < 32 && !((mask >> own) & 1u)) {
232 b.emitError() <<
"cert.remote_barrier id " <<
id <<
" on uC " << own
233 <<
" excludes its own uC from party_mask";
237 for (
auto &[uc, count] : occPerUc)
239 occs.front().emitError()
240 <<
"cert.remote_barrier id " <<
id <<
" has " << count
241 <<
" occurrences on uC " << uc
242 <<
" (at most one participant per uC per rendezvous)";
247 for (
int bit = 0; bit < 32; ++bit) {
248 if (!((mask >> bit) & 1u))
250 if (!present.count(bit)) {
251 occs.front().emitError()
252 <<
"cert.remote_barrier id " <<
id <<
" party_mask references uC "
253 << bit <<
" which is not present in the design";
255 }
else if (!occPerUc.count(bit)) {
256 occs.front().emitError()
257 <<
"cert.remote_barrier id " <<
id <<
" party_mask includes uC "
258 << bit <<
" but that uC has no matching remote_barrier(" <<
id
259 <<
") to rendezvous with";
271static LogicalResult checkBarrierLimits(AIE::DeviceOp device) {
272 LogicalResult result = success();
273 std::map<int, std::set<int>> localIds;
274 std::map<int, std::set<int>> remoteIds;
276 device.walk([&](AIEX::CertLocalBarrierOp barrier) {
277 int id = barrier.getLocalBarrierId();
278 if (id < 0 || id > 15) {
279 barrier.emitError() <<
"cert.local_barrier local_barrier_id " <<
id
280 <<
" out of range [0, 15]";
283 localIds[getUcGroupId(barrier)].insert(
id);
286 device.walk([&](AIEX::CertRemoteBarrierOp barrier) {
287 int id = barrier.getRemoteBarrierId();
288 if (id < 0 || id > 6) {
289 barrier.emitError() <<
"cert.remote_barrier remote_barrier_id " <<
id
290 <<
" out of range [0, 6]";
293 remoteIds[getUcGroupId(barrier)].insert(
id);
296 for (
auto &[uc, ids] : localIds)
297 if (ids.size() > 16) {
298 device.emitError() <<
"uC " << uc <<
" uses " << ids.size()
299 <<
" distinct local_barrier ids (max 16)";
302 for (
auto &[uc, ids] : remoteIds)
303 if (ids.size() > 7) {
304 device.emitError() <<
"uC " << uc <<
" uses " << ids.size()
305 <<
" distinct remote_barrier ids (max 7)";
311struct AIECertVerifyPass
312 : xilinx::AIEX::impl::AIECertVerifyBase<AIECertVerifyPass> {
313 void runOnOperation()
override {
314 AIE::DeviceOp device = getOperation();
315 if (failed(checkGroupIds(device)))
317 if (failed(checkLocalBarrierColocation(device)))
319 if (failed(checkWaitTctsUniqueness(device)))
321 if (failed(checkPreemptConsistency(device)))
323 if (failed(checkRemoteBarrierParties(device)))
325 if (failed(checkBarrierLimits(device)))
333 return std::make_unique<AIECertVerifyPass>();
virtual uint32_t getNumControllers() const
Total number of microcontrollers (uC) in the device.
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIECertVerifyPass()