12#include "mlir/Dialect/Arith/IR/Arith.h"
13#include "mlir/IR/SymbolTable.h"
14#include "mlir/Pass/Pass.h"
15#include "mlir/Transforms/DialectConversion.h"
18#define GEN_PASS_DEF_AIELOWERDMACHANNELRESET
19#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
22#define DEBUG_TYPE "aie-lower-dma-channel-reset"
39static LogicalResult expandDmaChannelResetForOps(DeviceOp device) {
40 SymbolTable symbolTable(device);
43 struct ResolvedEndpoint {
54 SmallVector<DMAStartOp> corePushStarts;
55 device.walk([&](DMAStartOp start) {
56 if (start.getCorePushes())
57 corePushStarts.push_back(start);
60 SmallVector<DmaChannelResetForOp> toErase;
61 WalkResult res = device.walk([&](DmaChannelResetForOp op) -> WalkResult {
63 symbolTable.lookup<ObjectFifoRearmBindingOp>(op.getObjfifo());
65 op.emitOpError(
"could not resolve '")
67 <<
"' to an aie.objectfifo_rearm_binding; run "
68 "--aie-objectFifo-stateful-transform first";
69 return WalkResult::interrupt();
72 ArrayRef<int32_t> dirs = binding.getChannelDirs();
73 ArrayRef<int32_t> chans = binding.getChannelIndices();
74 ValueRange tiles = binding.getChannelTiles();
80 std::optional<ArrayRef<int32_t>> headBdIds = binding.getHeadBdIds();
81 std::optional<ArrayRef<int32_t>> repeats = binding.getRepeatCounts();
82 if (!headBdIds || !repeats) {
83 op.emitOpError(
"objectFIFO re-arm binding '")
85 <<
"' has no head_bd_ids/repeat_counts; run --aie-assign-bd-ids "
86 "before this pass, or set them on the binding";
87 return WalkResult::interrupt();
90 OpBuilder builder(op);
91 Location loc = op.getLoc();
92 MLIRContext *ctx = builder.getContext();
96 SmallVector<ResolvedEndpoint> endpoints;
97 for (
unsigned i = 0; i < tiles.size(); ++i) {
98 auto tileOp = tiles[i].getDefiningOp<TileOp>();
100 op.emitOpError(
"re-arm binding channel tile is not an aie.tile");
101 return WalkResult::interrupt();
104 dirs[i] == 0 ? DMAChannelDir::S2MM : DMAChannelDir::MM2S;
105 for (DMAStartOp start : corePushStarts) {
106 if (start->getParentOfType<TileElement>().getTile() == tiles[i] &&
107 start.getChannelDir() == dir &&
108 start.getChannelIndex() == chans[i]) {
110 "does not support core-pushed DMA channels; reset requires "
111 "coordination with the issuing core and all shared senders");
112 return WalkResult::interrupt();
118 ep.channel = chans[i];
119 ep.col = tileOp.getCol();
120 ep.row = tileOp.getRow();
121 ep.headBdId =
static_cast<uint32_t
>((*headBdIds)[i]);
122 ep.repeatCount = (*repeats)[i];
123 endpoints.push_back(ep);
129 for (Value lock : binding.getLocks())
130 if (!lock.getDefiningOp<AIE::LockOp>()) {
131 op.emitOpError(
"re-arm binding lock operand is not an aie.lock");
132 return WalkResult::interrupt();
144 for (
const ResolvedEndpoint &ep : endpoints)
145 DmaChannelResetOp::create(builder, loc, ep.tile,
146 DMAChannelDirAttr::get(ctx, ep.dir),
147 builder.getI32IntegerAttr(ep.channel));
150 ValueRange locks = binding.getLocks();
151 ArrayRef<int32_t> lockInits = binding.getLockInits();
152 for (
unsigned j = 0; j < locks.size(); ++j)
153 SetLockOp::create(builder, loc, locks[j],
161 for (
const ResolvedEndpoint &ep : endpoints) {
162 bool issueToken = ep.row == 0 && ep.dir == DMAChannelDir::S2MM;
167 builder, loc,
static_cast<uint32_t
>(ep.repeatCount));
169 NpuPushQueueOp::create(builder, loc, builder.getI32IntegerAttr(ep.col),
170 builder.getI32IntegerAttr(ep.row),
171 DMAChannelDirAttr::get(ctx, ep.dir),
172 builder.getI32IntegerAttr(ep.channel),
173 builder.getBoolAttr(issueToken), repeatVal, bdVal,
177 toErase.push_back(op);
178 return WalkResult::advance();
181 if (res.wasInterrupted())
184 for (DmaChannelResetForOp op : toErase)
190 SmallVector<ObjectFifoRearmBindingOp> deadBindings;
191 for (
auto binding : device.getOps<ObjectFifoRearmBindingOp>())
192 if (SymbolTable::symbolKnownUseEmpty(binding.getSymNameAttr(), device))
193 deadBindings.push_back(binding);
194 for (ObjectFifoRearmBindingOp binding : deadBindings)
201 : OpConversionPattern<DmaChannelResetOp> {
202 using OpConversionPattern<DmaChannelResetOp>::OpConversionPattern;
205 : OpConversionPattern(context) {}
209 ConversionPatternRewriter &rewriter)
const override {
210 AIE::DeviceOp dev = op->getParentOfType<AIE::DeviceOp>();
213 AIE::TileOp tile = op.getTileOp();
214 int col = tile.getCol();
215 int row = tile.getRow();
216 int channel = op.getChannel();
217 AIE::DMAChannelDir dir = op.getDirection();
221 uint32_t ctrlAddrLocal =
228 std::string ctrlRegName =
229 (dir == AIE::DMAChannelDir::S2MM ?
"DMA_S2MM_" :
"DMA_MM2S_") +
230 std::to_string(channel) +
"_Ctrl";
232 tm.lookupRegister(ctrlRegName, tile.getTileID(),
true);
234 return op.emitOpError(
"target has no ")
235 << ctrlRegName <<
" register in its register database";
238 return op.emitOpError()
239 << ctrlRegName <<
" has no Reset field in the register database";
240 std::optional<uint32_t> resetMask = tm.getFieldMask(*resetField);
242 return op.emitOpError()
243 << ctrlRegName <<
" Reset field does not fit in a 32-bit register";
244 std::optional<uint32_t> resetValue = tm.encodeFieldValue(*resetField, 1);
246 return op.emitOpError()
248 <<
" Reset field value does not fit in its bit width";
250 Location loc = op.getLoc();
251 IntegerAttr colAttr = rewriter.getI32IntegerAttr(col);
252 IntegerAttr rowAttr = rewriter.getI32IntegerAttr(row);
264 NpuMaskWrite32Op::create(rewriter, loc, assertAddr, assertVal, assertMask,
265 nullptr, colAttr, rowAttr);
270 rewriter.replaceOpWithNewOp<NpuMaskWrite32Op>(
271 op, clearAddr, clearVal, clearMask,
nullptr, colAttr, rowAttr);
279 AIELowerDmaChannelResetPass> {
281 DeviceOp device = getOperation();
286 if (failed(expandDmaChannelResetForOps(device)))
287 return signalPassFailure();
289 ConversionTarget target(getContext());
290 target.addLegalOp<NpuMaskWrite32Op>();
291 target.addLegalDialect<arith::ArithDialect>();
292 target.addIllegalOp<DmaChannelResetOp>();
294 RewritePatternSet patterns(&getContext());
297 SmallVector<Operation *> roots;
298 device.walk([&](DmaChannelResetOp op) { roots.push_back(op); });
299 if (failed(applyPartialConversion(roots, target, std::move(patterns))))
304std::unique_ptr<OperationPass<DeviceOp>>
306 return std::make_unique<AIELowerDmaChannelResetPass>();
uint32_t getLocalDmaControlAddress(int col, int row, int channel, AIE::DMAChannelDir direction) const
Return the DMA task-queue register address relative to its tile.
mlir::Value createConstantI32(mlir::OpBuilder &builder, mlir::Location loc, uint32_t value)
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIELowerDmaChannelResetPass()
void runOnOperation() override
DmaChannelResetToMaskWrite32Pattern(MLIRContext *context)
LogicalResult matchAndRewrite(DmaChannelResetOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override
Bit field information for a register.
const BitFieldInfo * getField(llvm::StringRef fieldName) const