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<DmaChannelResetForOp> toErase;
55 WalkResult res = device.walk([&](DmaChannelResetForOp op) -> WalkResult {
57 symbolTable.lookup<ObjectFifoRearmBindingOp>(op.getObjfifo());
59 op.emitOpError(
"could not resolve '")
61 <<
"' to an aie.objectfifo_rearm_binding; run "
62 "--aie-objectFifo-stateful-transform first";
63 return WalkResult::interrupt();
66 ArrayRef<int32_t> dirs = binding.getChannelDirs();
67 ArrayRef<int32_t> chans = binding.getChannelIndices();
68 ValueRange tiles = binding.getChannelTiles();
74 std::optional<ArrayRef<int32_t>> headBdIds = binding.getHeadBdIds();
75 std::optional<ArrayRef<int32_t>> repeats = binding.getRepeatCounts();
76 if (!headBdIds || !repeats) {
77 op.emitOpError(
"objectFIFO re-arm binding '")
79 <<
"' has no head_bd_ids/repeat_counts; run --aie-assign-bd-ids "
80 "before this pass, or set them on the binding";
81 return WalkResult::interrupt();
84 OpBuilder builder(op);
85 Location loc = op.getLoc();
86 MLIRContext *ctx = builder.getContext();
90 SmallVector<ResolvedEndpoint> endpoints;
91 for (
unsigned i = 0; i < tiles.size(); ++i) {
92 auto tileOp = tiles[i].getDefiningOp<TileOp>();
94 op.emitOpError(
"re-arm binding channel tile is not an aie.tile");
95 return WalkResult::interrupt();
98 dirs[i] == 0 ? DMAChannelDir::S2MM : DMAChannelDir::MM2S;
102 ep.channel = chans[i];
103 ep.col = tileOp.getCol();
104 ep.row = tileOp.getRow();
105 ep.headBdId =
static_cast<uint32_t
>((*headBdIds)[i]);
106 ep.repeatCount = (*repeats)[i];
107 endpoints.push_back(ep);
113 for (Value lock : binding.getLocks())
114 if (!lock.getDefiningOp<AIE::LockOp>()) {
115 op.emitOpError(
"re-arm binding lock operand is not an aie.lock");
116 return WalkResult::interrupt();
128 for (
const ResolvedEndpoint &ep : endpoints)
129 DmaChannelResetOp::create(builder, loc, ep.tile,
130 DMAChannelDirAttr::get(ctx, ep.dir),
131 builder.getI32IntegerAttr(ep.channel));
134 ValueRange locks = binding.getLocks();
135 ArrayRef<int32_t> lockInits = binding.getLockInits();
136 for (
unsigned j = 0; j < locks.size(); ++j)
137 SetLockOp::create(builder, loc, locks[j],
145 for (
const ResolvedEndpoint &ep : endpoints) {
146 bool issueToken = ep.row == 0 && ep.dir == DMAChannelDir::S2MM;
151 builder, loc,
static_cast<uint32_t
>(ep.repeatCount));
153 NpuPushQueueOp::create(builder, loc, builder.getI32IntegerAttr(ep.col),
154 builder.getI32IntegerAttr(ep.row),
155 DMAChannelDirAttr::get(ctx, ep.dir),
156 builder.getI32IntegerAttr(ep.channel),
157 builder.getBoolAttr(issueToken), repeatVal, bdVal,
161 toErase.push_back(op);
162 return WalkResult::advance();
165 if (res.wasInterrupted())
168 for (DmaChannelResetForOp op : toErase)
174 SmallVector<ObjectFifoRearmBindingOp> deadBindings;
175 for (
auto binding : device.getOps<ObjectFifoRearmBindingOp>())
176 if (SymbolTable::symbolKnownUseEmpty(binding.getSymNameAttr(), device))
177 deadBindings.push_back(binding);
178 for (ObjectFifoRearmBindingOp binding : deadBindings)
185 : OpConversionPattern<DmaChannelResetOp> {
186 using OpConversionPattern<DmaChannelResetOp>::OpConversionPattern;
189 : OpConversionPattern(context) {}
193 ConversionPatternRewriter &rewriter)
const override {
194 AIE::DeviceOp dev = op->getParentOfType<AIE::DeviceOp>();
197 AIE::TileOp tile = op.getTileOp();
198 int col = tile.getCol();
199 int row = tile.getRow();
200 int channel = op.getChannel();
201 AIE::DMAChannelDir dir = op.getDirection();
205 uint32_t ctrlAddrLocal =
212 std::string ctrlRegName =
213 (dir == AIE::DMAChannelDir::S2MM ?
"DMA_S2MM_" :
"DMA_MM2S_") +
214 std::to_string(channel) +
"_Ctrl";
216 tm.lookupRegister(ctrlRegName, tile.getTileID(),
true);
218 return op.emitOpError(
"target has no ")
219 << ctrlRegName <<
" register in its register database";
222 return op.emitOpError()
223 << ctrlRegName <<
" has no Reset field in the register database";
224 std::optional<uint32_t> resetMask = tm.getFieldMask(*resetField);
226 return op.emitOpError()
227 << ctrlRegName <<
" Reset field does not fit in a 32-bit register";
228 std::optional<uint32_t> resetValue = tm.encodeFieldValue(*resetField, 1);
230 return op.emitOpError()
232 <<
" Reset field value does not fit in its bit width";
234 Location loc = op.getLoc();
235 IntegerAttr colAttr = rewriter.getI32IntegerAttr(col);
236 IntegerAttr rowAttr = rewriter.getI32IntegerAttr(row);
248 NpuMaskWrite32Op::create(rewriter, loc, assertAddr, assertVal, assertMask,
249 nullptr, colAttr, rowAttr);
254 rewriter.replaceOpWithNewOp<NpuMaskWrite32Op>(
255 op, clearAddr, clearVal, clearMask,
nullptr, colAttr, rowAttr);
263 AIELowerDmaChannelResetPass> {
265 DeviceOp device = getOperation();
270 if (failed(expandDmaChannelResetForOps(device)))
271 return signalPassFailure();
273 ConversionTarget target(getContext());
274 target.addLegalOp<NpuMaskWrite32Op>();
275 target.addLegalDialect<arith::ArithDialect>();
276 target.addIllegalOp<DmaChannelResetOp>();
278 RewritePatternSet patterns(&getContext());
281 SmallVector<Operation *> roots;
282 device.walk([&](DmaChannelResetOp op) { roots.push_back(op); });
283 if (failed(applyPartialConversion(roots, target, std::move(patterns))))
288std::unique_ptr<OperationPass<DeviceOp>>
290 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