34#include "mlir/Pass/Pass.h"
36#include "llvm/ADT/STLExtras.h"
37#include "llvm/ADT/SmallPtrSet.h"
38#include "llvm/ADT/SmallVector.h"
44#define GEN_PASS_DEF_AIEVERIFYRUNTIMEREARM
45#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
55using ChannelKey = std::array<int, 4>;
57struct AIEVerifyRuntimeRearmPass
58 : xilinx::AIEX::impl::AIEVerifyRuntimeRearmBase<AIEVerifyRuntimeRearmPass> {
62 FailureOr<std::map<ChannelKey, SmallVector<LockOp>>>
63 mapChannelLocks(DeviceOp dev) {
64 std::map<ChannelKey, SmallVector<LockOp>> m;
65 WalkResult wr = dev.walk([&](DMAStartOp start) -> WalkResult {
66 Operation *memOp = start->getParentOp();
68 if (
auto x = dyn_cast<MemOp>(memOp))
70 else if (
auto x = dyn_cast<MemTileDMAOp>(memOp))
73 return WalkResult::advance();
74 if (start.getEndpoint()) {
75 start.emitOpError(
"requires a DMA channel index; run "
76 "--aie-objectfifo-allocate before "
77 "--aie-verify-runtime-rearm");
78 return WalkResult::interrupt();
80 ChannelKey key{tile.getCol(), tile.getRow(),
81 static_cast<int>(start.getChannelDir()),
82 start.getChannelIndex()};
83 SmallVector<LockOp> &locks = m[key];
86 llvm::SmallPtrSet<Block *, 8> visited;
87 for (Block *b = start.getDest(); b && visited.insert(b).second;
88 b = (b->getNumSuccessors() == 1 ? b->getSuccessor(0) :
nullptr))
89 for (
auto use : b->getOps<UseLockOp>())
90 if (
auto l = dyn_cast_or_null<LockOp>(use.getLock().getDefiningOp()))
91 if (!llvm::is_contained(locks, l))
93 return WalkResult::advance();
95 if (wr.wasInterrupted())
100 void runOnOperation()
override {
101 DeviceOp dev = getOperation();
102 auto channelLocks = mapChannelLocks(dev);
103 if (failed(channelLocks)) {
112 llvm::SmallPtrSet<Operation *, 16> reArmedBySetLock;
113 dev.walk([&](SetLockOp sl) {
114 reArmedBySetLock.insert(sl.getLockOp().getOperation());
117 auto isReArmed = [&](LockOp l) ->
bool {
118 return reArmedBySetLock.contains(l.getOperation());
121 WalkResult wr = dev.walk([&](DmaChannelResetOp reset) -> WalkResult {
122 TileOp tile = reset.getTileOp();
124 return WalkResult::advance();
125 ChannelKey key{tile.getCol(), tile.getRow(),
126 static_cast<int>(reset.getDirection()),
127 static_cast<int>(reset.getChannel())};
128 auto it = channelLocks->find(key);
129 if (it == channelLocks->end())
130 return WalkResult::advance();
131 SmallVector<LockOp> frozen;
132 for (LockOp l : it->second)
136 return WalkResult::advance();
137 InFlightDiagnostic err = reset.emitOpError(
138 "resets a DMA channel whose objectFIFO lock is never re-armed; the "
139 "semaphore counter stays frozen and the channel's peer will block "
140 "forever on acquire (a runtime deadlock). Re-arm each bound lock "
141 "with an aiex.set_lock");
142 for (LockOp l : frozen)
143 err.attachNote(l.getLoc())
144 <<
"this lock is bound to the reset channel and is not re-armed";
145 return WalkResult::interrupt();
147 if (wr.wasInterrupted())
154std::unique_ptr<OperationPass<DeviceOp>>
156 return std::make_unique<AIEVerifyRuntimeRearmPass>();
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEVerifyRuntimeRearmPass()