MLIR-AIE
AIEAssignLockIDs.cpp
Go to the documentation of this file.
1//===- AIEAssignLockIDs.cpp -------------------------------------*- C++ -*-===//
2//
3// This file is licensed under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7// (c) Copyright 2022 Xilinx Inc.
8//
9//===----------------------------------------------------------------------===//
10
11// This pass aims to assign lockIDs to AIE.lock operations. The lockID is
12// numbered from the most recent AIE.lock within the same tile. If the lockID
13// exceeds the number of locks on the tile, the pass generates an error and
14// terminates. AIE.lock operations for different tiles are numbered
15// independently. If there are existing lock IDs, this pass is idempotent
16// and only assigns lock IDs to locks without an ID.
17
20
21#include "mlir/Pass/Pass.h"
22#include "llvm/ADT/DenseMap.h"
23
24namespace xilinx::AIE {
25#define GEN_PASS_DEF_AIEASSIGNLOCKIDS
26#include "aie/Dialect/AIE/Transforms/AIEPasses.h.inc"
27} // namespace xilinx::AIE
28
29#define DEBUG_TYPE "aie-assign-lock-ids"
30
31using namespace mlir;
32using namespace xilinx;
33using namespace xilinx::AIE;
34
36 : xilinx::AIE::impl::AIEAssignLockIDsBase<AIEAssignLockIDsPass> {
37 void getDependentDialects(DialectRegistry &registry) const override {
38 registry.insert<func::FuncDialect>();
39 registry.insert<AIEDialect>();
40 }
41
42 void runOnOperation() override {
43 DeviceOp device = getOperation();
44 OpBuilder rewriter = OpBuilder::atBlockTerminator(device.getBody());
45
46 // All of the lock ops on a tile, separated into ops which have been
47 // assigned to a lock, and ops which have not.
48 struct TileLockOps {
49 DenseSet<int> assigned;
50 SmallVector<LockOp> unassigned;
51 };
52
53 DenseMap<TileOp, TileLockOps> tileToLocks;
54
55 // Construct data structure storing locks by tile.
56 device.walk<WalkOrder::PreOrder>([&](LockOp lockOp) {
57 TileOp tileOp = lockOp.getTileOp();
58 if (lockOp.getLockID().has_value()) {
59 auto lockID = lockOp.getLockID().value();
60 auto iter = tileToLocks.find(tileOp);
61 if (iter == tileToLocks.end())
62 tileToLocks.insert({tileOp, {{lockID}, /* unassigned = */ {}}});
63 else {
64 if (iter->second.assigned.find(lockID) !=
65 iter->second.assigned.end()) {
66 auto diag = lockOp->emitOpError("is assigned to the same lock (")
67 << lockID << ") as another op.";
68 diag.attachNote(tileOp.getLoc())
69 << "tile has lock ops assigned to same lock.";
70 return signalPassFailure();
71 }
72 iter->second.assigned.insert(lockID);
73 }
74 } else {
75 auto iter = tileToLocks.find(tileOp);
76 if (iter == tileToLocks.end())
77 tileToLocks.insert({tileOp, {/* assigned = */ {}, {lockOp}}});
78 else
79 iter->second.unassigned.push_back(lockOp);
80 }
81 });
82
83 // IR mutation: assign locks to all unassigned lock ops.
84 for (auto [tileOp, locks] : tileToLocks) {
85 const auto locksPerTile =
86 getTargetModel(tileOp).getNumLocks(tileOp.getCol(), tileOp.getRow());
87 uint32_t nextID = 0;
88 for (auto lockOp : locks.unassigned) {
89 while (nextID < locksPerTile &&
90 (locks.assigned.find(nextID) != locks.assigned.end())) {
91 ++nextID;
92 }
93 if (nextID == locksPerTile) {
94 mlir::InFlightDiagnostic diag =
95 lockOp->emitOpError("not allocated a lock.");
96 diag.attachNote(tileOp.getLoc()) << "because only " << locksPerTile
97 << " locks available in this tile.";
98 return signalPassFailure();
99 }
100 lockOp.setLockIDAttr(rewriter.getI32IntegerAttr(nextID));
101 ++nextID;
102 }
103 }
104 }
105};
106
107std::unique_ptr<OperationPass<DeviceOp>> AIE::createAIEAssignLockIDsPass() {
108 return std::make_unique<AIEAssignLockIDsPass>();
109}
virtual uint32_t getNumLocks(AIETileType tileType) const =0
Return the number of lock objects for a given tile type.
Include the generated interface declarations.
std::unique_ptr< mlir::OperationPass< DeviceOp > > createAIEAssignLockIDsPass()
const AIETargetModel & getTargetModel(mlir::Operation *op)
void getDependentDialects(DialectRegistry &registry) const override
void runOnOperation() override