12#include "mlir/Dialect/MemRef/IR/MemRef.h"
13#include "mlir/IR/Builders.h"
14#include "mlir/Pass/Pass.h"
17#define GEN_PASS_DEF_AIEFUSETRACEBUFFERS
18#include "aie/Dialect/AIEX/Transforms/AIEXPasses.h.inc"
27struct AIEFuseTraceBuffersPass
28 : xilinx::AIEX::impl::AIEFuseTraceBuffersBase<AIEFuseTraceBuffersPass> {
31 llvm::DenseMap<Operation *, int64_t> claim;
33 llvm::DenseMap<Operation *, SmallVector<AIE::TraceSliceAttr>> slices;
34 llvm::DenseSet<Operation *> done;
36 void runOnOperation()
override {
37 ModuleOp mod = getOperation();
38 for (
auto device : mod.getOps<AIE::DeviceOp>()) {
39 for (
auto seq : device.getOps<AIE::RuntimeSequenceOp>()) {
40 if (failed(fuse(seq))) {
41 return signalPassFailure();
49 LogicalResult fuse(AIE::RuntimeSequenceOp seq) {
50 if (!done.insert(seq.getOperation()).second) {
54 SmallVector<RunOp> runs;
55 seq.walk([&](RunOp run) { runs.push_back(run); });
58 for (RunOp run : runs) {
59 AIE::RuntimeSequenceOp callee = run.getCalleeRuntimeSequenceOp();
61 return run.emitOpError(
"cannot resolve callee runtime sequence");
63 if (failed(fuse(callee))) {
68 AIE::TraceBufferAttr ownBuffer = seq.getTraceBufferAttr();
69 int64_t ownClaim = ownBuffer ? ownBuffer.getSize() : 0;
70 int64_t total = ownClaim;
71 for (RunOp run : runs) {
72 total += claim.lookup(run.getCalleeRuntimeSequenceOp().getOperation());
75 claim[seq.getOperation()] = total;
82 bool needsFusing = total > ownClaim;
84 slices[seq.getOperation()] = ownSlices(seq, ownBuffer, 0);
88 if (ownBuffer && !ownBuffer.getDedicated()) {
89 return seq.emitOpError(
90 "runs traced designs and sets trace.host_config "
91 "reuse_output_buffer=true. Growing the output buffer to hold their "
92 "slices is not supported. Use a separate trace buffer instead");
95 OpBuilder builder(seq);
96 Block &entry = seq.getBody().front();
97 auto i8 = IntegerType::get(seq.getContext(), 8);
98 auto fusedType = MemRefType::get({total}, i8);
100 BlockArgument fusedArg;
102 fusedArg = entry.getArgument(ownBuffer.getArgIndex());
103 fusedArg.setType(fusedType);
105 fusedArg = entry.addArgument(fusedType, seq.getLoc());
110 SmallVector<AIE::TraceSliceAttr> flattened =
111 ownSlices(seq, ownBuffer, 0);
112 int64_t cursor = ownClaim;
114 for (RunOp run : runs) {
115 AIE::RuntimeSequenceOp callee = run.getCalleeRuntimeSequenceOp();
116 int64_t calleeClaim = claim.lookup(callee.getOperation());
117 if (calleeClaim == 0) {
121 AIE::TraceBufferAttr calleeBuffer = callee.getTraceBufferAttr();
122 if (calleeBuffer && !calleeBuffer.getDedicated()) {
123 return run.emitOpError(
124 "calls a design that sets trace.host_config "
125 "reuse_output_buffer=true. That design writes its trace data into "
126 "its own output buffer, so this call site has no argument to "
127 "slice. Slicing an output buffer is not supported. Use a separate "
128 "trace buffer instead");
130 unsigned calleeArgIdx = calleeBuffer
131 ? calleeBuffer.getArgIndex()
132 : callee.getBody().getNumArguments() - 1;
133 auto calleeType = cast<MemRefType>(
134 callee.getBody().getArgument(calleeArgIdx).getType());
136 builder.setInsertionPoint(run);
138 makeSlice(builder, run.getLoc(), fusedArg, cursor, calleeType);
139 run.getOperation()->insertOperands(run.getOperation()->getNumOperands(),
142 for (AIE::TraceSliceAttr s : slices.lookup(callee.getOperation())) {
143 flattened.push_back(AIE::TraceSliceAttr::get(
144 seq.getContext(), s.getDevice(), s.getSequence(),
145 s.getOffset() + cursor, s.getSize()));
147 cursor += calleeClaim;
150 slices[seq.getOperation()] = flattened;
151 seq.setTraceSlicesAttr(builder.getArrayAttr(
152 SmallVector<Attribute>(flattened.begin(), flattened.end())));
153 seq.setTraceBufferAttr(AIE::TraceBufferAttr::get(
154 seq.getContext(), fusedArg.getArgNumber(), 0, total,
159 SmallVector<AIE::TraceSliceAttr> ownSlices(AIE::RuntimeSequenceOp seq,
160 AIE::TraceBufferAttr ownBuffer,
162 SmallVector<AIE::TraceSliceAttr> result;
163 if (ArrayAttr existing = seq.getTraceSlicesAttr()) {
164 for (Attribute a : existing) {
165 auto s = cast<AIE::TraceSliceAttr>(a);
166 result.push_back(AIE::TraceSliceAttr::get(
167 seq.getContext(), s.getDevice(), s.getSequence(),
168 base + s.getOffset(), s.getSize()));
175 auto device = seq->getParentOfType<AIE::DeviceOp>();
176 StringAttr deviceName = device.getSymNameAttr();
177 result.push_back(AIE::TraceSliceAttr::get(
178 seq.getContext(), deviceName ? deviceName.getValue() : StringRef(),
179 seq.getSymName(), base, ownBuffer.getSize()));
187 Value makeSlice(OpBuilder &builder, Location loc, Value buffer,
188 int64_t offset, MemRefType resultType) {
189 int64_t size = resultType.getNumElements();
190 Value sub = memref::SubViewOp::create(
191 builder, loc, buffer,
192 ArrayRef<OpFoldResult>{builder.getIndexAttr(offset)},
193 ArrayRef<OpFoldResult>{builder.getIndexAttr(size)},
194 ArrayRef<OpFoldResult>{builder.getIndexAttr(1)});
195 return memref::ReinterpretCastOp::create(
196 builder, loc, resultType, sub, builder.getIndexAttr(0),
197 ArrayRef<OpFoldResult>{builder.getIndexAttr(size)},
198 ArrayRef<OpFoldResult>{builder.getIndexAttr(1)});
204std::unique_ptr<OperationPass<ModuleOp>>
206 return std::make_unique<AIEFuseTraceBuffersPass>();
std::unique_ptr< mlir::OperationPass< mlir::ModuleOp > > createAIEFuseTraceBuffersPass()