10#include "mlir/Dialect/Utils/StaticValueUtils.h"
11#include "mlir/Interfaces/ControlFlowInterfaces.h"
12#include "llvm/ADT/SmallPtrSet.h"
17std::optional<AIEX::SubviewTraceResult>
19 int64_t offsetInBytes = 0;
20 Value current = value;
25 if (
auto blockArg = dyn_cast<BlockArgument>(current)) {
29 Operation *defOp = current.getDefiningOp();
35 if (
auto castOp = dyn_cast<memref::CastOp>(defOp)) {
36 current = castOp.getSource();
41 if (
auto reinterpretOp = dyn_cast<memref::ReinterpretCastOp>(defOp)) {
43 dyn_cast<MemRefType>(reinterpretOp.getSource().getType());
49 if (
auto strided = dyn_cast<StridedLayoutAttr>(sourceType.getLayout())) {
50 for (int64_t stride : strided.getStrides()) {
58 current = reinterpretOp.getSource();
66 if (
auto subviewOp = dyn_cast<memref::SubViewOp>(defOp)) {
67 auto sourceType = subviewOp.getSourceType();
68 auto resultType = subviewOp.getType();
70 if (llvm::any_of(subviewOp.getStaticOffsets(), ShapedType::isDynamic) ||
71 llvm::any_of(subviewOp.getStaticSizes(), ShapedType::isDynamic) ||
72 llvm::any_of(subviewOp.getStaticStrides(), ShapedType::isDynamic))
76 if (llvm::any_of(subviewOp.getStaticStrides(),
77 [](int64_t s) { return s != 1; }))
80 unsigned elemSizeInBits =
81 sourceType.getElementType().getIntOrFloatBitWidth();
82 if (elemSizeInBits % 8 != 0)
85 llvm::SmallVector<int64_t> srcStrides, resStrides;
86 int64_t srcOff, resOff;
87 if (failed(sourceType.getStridesAndOffset(srcStrides, srcOff)) ||
88 failed(resultType.getStridesAndOffset(resStrides, resOff)))
90 if (srcOff == ShapedType::kDynamic || resOff == ShapedType::kDynamic)
98 ArrayRef<int64_t> resShape = resultType.getShape();
99 if (!resShape.empty()) {
100 if (resStrides.back() != 1)
102 uint64_t product = 1;
103 for (
int d =
static_cast<int>(resShape.size()) - 1; d > 0; --d) {
104 product *=
static_cast<uint64_t
>(resShape[d]);
105 if (resShape[d - 1] > 1 &&
106 static_cast<uint64_t
>(resStrides[d - 1]) != product)
111 offsetInBytes += (resOff - srcOff) * (elemSizeInBits / 8);
113 current = subviewOp.getSource();
123 if (
auto viewOp = dyn_cast<memref::ViewOp>(defOp)) {
124 if (!viewOp.getSizes().empty())
126 std::optional<int64_t> byteShift =
127 getConstantIntValue(viewOp.getByteShift());
130 offsetInBytes += *byteShift;
131 current = viewOp.getSource();
143 if (!isa<BaseMemRefType>(arg.getType()))
146 for (BlockArgument other : arg.getOwner()->getArguments()) {
149 if (isa<BaseMemRefType>(other.getType()))
156 return llvm::count_if(block.getArguments(), [](BlockArgument arg) {
157 return isa<BaseMemRefType>(arg.getType());
162 : dev(dev), prefix(prefix) {
163 for (Operation &op : dev.getBody()->getOperations()) {
164 if (auto global = dyn_cast<memref::GlobalOp>(op))
165 if (auto initVal = global.getInitialValue();
166 initVal && global.getConstant())
167 byValue.try_emplace(*initVal, global);
169 op.getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName());
172 StringRef suffix = symName.getValue();
174 if (suffix.consume_front(prefix) && !suffix.getAsInteger(10, idx) &&
182 ArrayRef<uint32_t> words) {
183 int64_t numWords = words.size();
184 MemRefType memrefType = MemRefType::get({numWords}, builder.getI32Type());
185 TensorType tensorType =
186 RankedTensorType::get({numWords}, builder.getI32Type());
187 auto initVal = DenseElementsAttr::get<uint32_t>(tensorType, words);
191 memref::GlobalOp &global = byValue[initVal];
192 if (global && global.getType() == memrefType)
194 global = memref::GlobalOp::create(
195 builder, loc, prefix + std::to_string(nextId++),
196 builder.getStringAttr(
"private"), memrefType, initVal,
true,
nullptr);
201 OpBuilder &builder, Operation *bdOp, BaseMemRefType bufType,
202 uint64_t registerAddr) {
203 auto idxAttr = bdOp->getAttrOfType<IntegerAttr>(
"offset_state_table_idx");
204 assert(idxAttr &&
"emitUpdateBdAddressFromOffsetParameter called without "
205 "offset_state_table_idx attribute");
207 uint8_t stateIdx =
static_cast<uint8_t
>(idxAttr.getUInt());
208 uint32_t elemBytes = bufType.getElementTypeBitWidth() / 8;
213 AIEX::NpuUpdateFromScratchpadOp::create(
214 builder, bdOp->getLoc(), stateIdx, AIEX::StateTableFunc::Mul,
216 static_cast<uint32_t
>(registerAddr),
217 nullptr,
nullptr,
nullptr);
222 OpBuilder &builder, Operation *bdOp, BaseMemRefType bufType,
225 auto idxAttr = bdOp->getAttrOfType<IntegerAttr>(
"length_state_table_idx");
226 assert(idxAttr &&
"emitUpdateBdLengthFromParameter called without "
227 "length_state_table_idx attribute");
231 uint64_t registerAddr =
235 uint8_t stateIdx =
static_cast<uint8_t
>(idxAttr.getUInt());
236 FailureOr<int64_t> unitBytes =
238 if (failed(unitBytes))
244 int64_t bytesPerStateUnit = bdOp->hasAttr(
"length_core_encoded") ? 16 : 4;
245 AIEX::NpuUpdateFromScratchpadOp::create(
246 builder, bdOp->getLoc(), stateIdx, AIEX::StateTableFunc::Mul,
248 static_cast<uint32_t
>(*unitBytes / bytesPerStateUnit),
249 static_cast<uint32_t
>(registerAddr),
250 nullptr,
nullptr,
nullptr);
255 auto device = seq->getParentOfType<AIE::DeviceOp>();
256 return (device.getSymName() +
":" + seq.getSymName()).str();
260 SmallVector<AIEX::ScratchpadParameterOp> allParams;
261 moduleOp.walk([&](AIEX::ScratchpadParameterOp p) { allParams.push_back(p); });
263 unsigned numSlots = 0;
264 for (
auto p : allParams)
265 if (
auto idx = p.getStateTableIdx())
266 numSlots = std::max(numSlots,
static_cast<unsigned>(*idx) + 1);
267 os << allParams.size() <<
" " << numSlots <<
"\n";
268 for (
auto p : allParams) {
270 llvm::raw_string_ostream ts(typeStr);
271 p.getType().print(ts);
273 auto kind = p.getKind();
274 assert(kind &&
"expected --aie-lower-scratchpad-parameters to have "
275 "assigned every parameter a kind");
276 StringRef kindStr = AIEX::stringifyScratchpadParameterKind(*kind);
277 os << p.getSymName() <<
" ";
278 if (std::optional<uint8_t> stateTableIdx = p.getStateTableIdx())
279 os << static_cast<unsigned>(*stateTableIdx);
282 os <<
" " << typeStr <<
" " << kindStr;
283 auto minValue = p.getMinValue();
284 auto maxValue = p.getMaxValue();
285 if (minValue && maxValue)
286 os <<
" " <<
static_cast<int32_t
>(*minValue) <<
" "
287 <<
static_cast<int32_t
>(*maxValue);
293 SmallVector<std::pair<StringRef, AIEX::JointBoundAttr>> jointBounds;
294 for (
auto p : allParams)
295 if (ArrayAttr bounds = p.getJointBoundsAttr())
296 for (
auto bound : bounds.getAsRange<AIEX::JointBoundAttr>())
297 jointBounds.push_back({p.getSymName(), bound});
298 os << jointBounds.size() <<
"\n";
299 for (
auto [length, bound] : jointBounds)
300 os << length <<
" " << bound.getOffset().getValue() <<
" "
301 << bound.getLengthStep() <<
" " << bound.getMax() <<
"\n";
303 SmallVector<AIE::RuntimeSequenceOp> commands;
304 moduleOp.walk([&](AIE::RuntimeSequenceOp seq) {
305 if (seq.getScratchpadParametersAttr())
306 commands.push_back(seq);
308 os << commands.size() <<
"\n";
309 for (AIE::RuntimeSequenceOp seq : commands) {
310 ArrayAttr reads = seq.getScratchpadParametersAttr();
312 for (
auto ref : reads.getAsRange<FlatSymbolRefAttr>())
313 os <<
" " << ref.getValue();
319 Value task, SmallVectorImpl<DMAConfigureTaskOp> &configures) {
320 bool complete =
true;
321 llvm::SmallPtrSet<Value, 8> seen;
322 SmallVector<Value> worklist{task};
323 while (!worklist.empty()) {
324 Value v = worklist.pop_back_val();
325 if (!v || !seen.insert(v).second)
327 if (
auto cfg = v.getDefiningOp<DMAConfigureTaskOp>()) {
328 configures.push_back(cfg);
332 Operation *regionBranchOp;
333 if (
auto res = dyn_cast<OpResult>(v))
334 regionBranchOp = res.getOwner();
336 regionBranchOp = cast<BlockArgument>(v).getOwner()->getParentOp();
337 auto rbi = dyn_cast_or_null<RegionBranchOpInterface>(regionBranchOp);
343 RegionBranchInverseSuccessorMapping mapping;
344 rbi.getSuccessorInputOperandMapping(mapping);
345 auto operands = mapping.lookup(v);
346 if (operands.empty())
348 for (OpOperand *operand : operands)
349 worklist.push_back(operand->get());
355 SmallVector<DMAConfigureTaskOp> configures;
358 return configures.front();
memref::GlobalOp getOrCreate(OpBuilder &builder, mlir::Location loc, ArrayRef< uint32_t > words)
BlockwriteData(AIE::DeviceOp dev, llvm::StringRef prefix)
virtual const DmaBdLayout * getDmaBdLayout(AIETileType tileType) const
Return the register layout of a buffer descriptor on the given tile type, or null if the target has n...
virtual uint64_t getDmaBdAddress(int col, int row, uint32_t bd_id, int channel=-1, AIE::DMAChannelDir direction=AIE::DMAChannelDir::MM2S) const =0
Return the array address of the dma buffer descriptor for the given col, row, buffer descriptor id,...
unsigned getHostBufferCount(Block &block)
DMAConfigureTaskOp getUniqueReachableConfigure(Value task)
std::optional< SubviewTraceResult > traceSubviewToBlockArgument(Value value)
std::string scratchpadCommandName(AIE::RuntimeSequenceOp seq)
void emitScratchpadParamsFile(mlir::ModuleOp moduleOp, llvm::raw_ostream &os)
bool getReachableConfigures(Value task, SmallVectorImpl< DMAConfigureTaskOp > &configures)
LogicalResult emitUpdateBdAddressFromOffsetParameter(OpBuilder &builder, Operation *bdOp, BaseMemRefType bufType, uint64_t registerAddr)
LogicalResult emitUpdateBdLengthFromParameter(OpBuilder &builder, Operation *bdOp, BaseMemRefType bufType, int64_t lengthUnit, const AIE::AIETargetModel &targetModel, int col, int row, int bdId)
std::optional< unsigned > getHostBufferArgIndex(BlockArgument arg)
mlir::LogicalResult verifyLengthParameterTile(mlir::Operation *op, const AIETargetModel &targetModel, int col, int row)
mlir::FailureOr< int64_t > getLengthUnitBytes(mlir::Operation *op, int64_t lengthUnit, mlir::BaseMemRefType buffer)