MLIR-AIE
AIEInlineTraceConfig.cpp
Go to the documentation of this file.
1//===- AIEInlineTraceConfig.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// Copyright (C) 2025, Advanced Micro Devices, Inc.
8//
9//===----------------------------------------------------------------------===//
10// Pass to inline trace.start_config and generate npu.write32
11//===----------------------------------------------------------------------===//
12
16
17#include "mlir/IR/Attributes.h"
18#include "mlir/Pass/Pass.h"
19
20namespace xilinx::AIEX {
21#define GEN_PASS_DEF_AIEXINLINETRACECONFIG
22#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
23} // namespace xilinx::AIEX
24
25using namespace mlir;
26using namespace xilinx;
27using namespace xilinx::AIE;
28using namespace xilinx::AIEX;
29
30namespace {
31
32struct AIEInlineTraceConfigPass
33 : xilinx::AIEX::impl::AIEXInlineTraceConfigBase<AIEInlineTraceConfigPass> {
34 void runOnOperation() override {
35 AIE::DeviceOp device = getOperation();
36 const auto &targetModel = device.getTargetModel();
37
38 // Collect all trace.start_config operations
39 SmallVector<TraceStartConfigOp> startConfigs;
40 device.walk([&](TraceStartConfigOp startConfig) {
41 startConfigs.push_back(startConfig);
42 });
43
44 for (auto startConfig : startConfigs) {
45 OpBuilder builder(startConfig);
46
47 // Lookup the trace config symbol
48 auto configSymbolName = startConfig.getTraceConfig();
49 auto configOp =
50 dyn_cast_or_null<TraceConfigOp>(SymbolTable::lookupNearestSymbolFrom(
51 device, builder.getStringAttr(configSymbolName)));
52
53 if (!configOp) {
54 startConfig.emitError("trace config symbol '")
55 << configSymbolName << "' not found";
56 return signalPassFailure();
57 }
58
59 // Get tile and extract col/row
60 auto tile = configOp.getTile();
61 auto tileOp = dyn_cast<TileOp>(tile.getDefiningOp());
62 if (!tileOp) {
63 startConfig.emitError("tile operand must be a TileOp");
64 return signalPassFailure();
65 }
66
67 int col = tileOp.getCol();
68 int row = tileOp.getRow();
69 TileID tileID = {col, row};
70
71 // Determine if we're accessing memory module from packet type
72 bool isMem = false;
73 if (configOp.getPacketType()) {
74 isMem = (*configOp.getPacketType() == TracePacketType::Mem);
75 }
76
77 // Process all trace.reg operations in the config
78 for (auto &op : configOp.getBody().getOps()) {
79 auto regOp = dyn_cast<TraceRegOp>(op);
80 if (!regOp)
81 continue;
82
83 // After packing, field should not be present
84 if (regOp.getField()) {
85 regOp.emitError("aie.trace.reg still has field attribute - run "
86 "-aie-trace-pack-reg-writes pass first");
87 return signalPassFailure();
88 }
89
90 // Look up register to get offset
91 auto regName = regOp.getRegName().str();
92 const RegisterInfo *regInfo =
93 targetModel.lookupRegister(regName, tileID, isMem);
94 if (!regInfo) {
95 regOp.emitError("Register '") << regName << "' not found for tile ("
96 << col << ", " << row << ")";
97 return signalPassFailure();
98 }
99
100 // Extract value (mask is discarded)
101 uint32_t value = 0;
102 if (auto intAttr = llvm::dyn_cast<IntegerAttr>(regOp.getValue())) {
103 value = intAttr.getInt();
104 } else {
105 regOp.emitError("value must be an integer after packing");
106 return signalPassFailure();
107 }
108
109 // Generate aiex.npu.write32 operation with col/row
110 builder.create<AIEX::NpuWrite32Op>(
111 regOp.getLoc(), builder.getUI32IntegerAttr(regInfo->offset),
112 builder.getUI32IntegerAttr(value),
113 nullptr, // buffer
114 builder.getI32IntegerAttr(col), // column
115 builder.getI32IntegerAttr(row) // row
116 );
117 }
118
119 // Remove the start_config invocation
120 startConfig.erase();
121 }
122 }
123};
124
125} // namespace
126
127std::unique_ptr<OperationPass<AIE::DeviceOp>>
129 return std::make_unique<AIEInlineTraceConfigPass>();
130}
std::shared_ptr< Value > value()
Definition cxxopts.hpp:1026
std::unique_ptr< mlir::OperationPass< AIE::DeviceOp > > createAIEXInlineTraceConfigPass()
Include the generated interface declarations.
TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")" TileID