23static void writeLDScriptMap(raw_ostream &output, BufferOp buf,
int offset) {
24 std::string bufName(buf.name().getValue());
26 int numBytes = buf.getAllocationSize();
27 output <<
". = 0x" << llvm::utohexstr(offset + bufferBaseAddr) <<
";\n";
28 output << bufName <<
" = .;\n";
29 output <<
". += 0x" << llvm::utohexstr(numBytes) <<
";\n";
67 ModuleOp module, raw_ostream &output,
int tileCol,
int tileRow,
68 llvm::StringRef deviceName,
bool probe,
69 llvm::function_ref<std::string(llvm::StringRef)> resolveLinkFile) {
70 DenseMap<TileID, Operation *> tiles;
71 DenseMap<Operation *, SmallVector<BufferOp, 4>> buffers;
74 AIE::DeviceOp::getForSymbolInModuleOrError(module, deviceName);
83 for (
auto tile : targetOp.getOps<TileOp>()) {
84 if (tile.colIndex() == tileCol && tile.rowIndex() == tileRow) {
85 TileID srcCoord = {tile.colIndex(), tile.rowIndex()};
92 if (
auto core = tile.getCoreOp()) {
93 if (!probe && core.getStackBank() && !core.getStackAddress())
94 return core.emitOpError(
95 "stack_bank has no assigned stack_address; run "
96 "--aie-assign-buffer-addresses with bank-aware allocation");
97 stackRun = core.getStackRun();
101 targetModel.getLocalMemorySize() - stackRun.
end()}
106 if (dataRun.
start < 0 ||
107 dataRun.
end() > targetModel.getLocalMemorySize())
108 return tile.emitOpError(
109 "data region runs past this tile's local memory; the buffer "
110 "allocator's placement is stale. Re-run "
111 "--aie-assign-buffer-addresses");
112 if (dataRun.
size > 0 && stackRun.
size > 0 &&
114 return tile.emitOpError(
115 "data region overlaps the stack; the buffer allocator's "
116 "placement is stale. Re-run --aie-assign-buffer-addresses");
121 for (
auto buf : buffers[tiles[srcCoord]]) {
122 if (buf.getCoreData() || buf.getAllocationSize() == 0 ||
127 int64_t bufEnd = bufStart + buf.getAllocationSize();
128 if (bufStart < dataRun.
end() && dataRun.
start < bufEnd) {
129 return tile.emitOpError(
"data region 0x")
130 << llvm::utohexstr(dataRun.
start) <<
"-0x"
131 << llvm::utohexstr(dataRun.
end() - 1) <<
" overlaps buffer '"
132 << buf.name().getValue() <<
"' at 0x"
133 << llvm::utohexstr(bufStart)
134 <<
"; the buffer allocator's placement is stale. Re-run "
135 "--aie-assign-buffer-addresses";
144 targetModel.getMemInternalBaseAddress(srcCoord) + dataRun.
start;
145 int length = dataRun.
size;
147 !probe && llvm::any_of(buffers[tiles[srcCoord]], [](BufferOp buf) {
148 return buf.getCoreData();
150 llvm::SmallVector<MemoryRun> bankRuns;
157 int numBanks = targetModel.getNumBanks(srcCoord.col, srcCoord.row);
159 numBanks > 0 ? targetModel.getLocalMemorySize() / numBanks : 0;
160 for (
int bank = 0; bank < numBanks; ++bank)
162 MemoryRun{bankSize * bank, targetModel.getLocalMemorySize()});
167 std::string dataOrigin =
"0x" + llvm::utohexstr(origin);
168 std::string dataEnd =
"0x" + llvm::utohexstr(origin + length);
172 for (
auto [bank, run] : llvm::enumerate(bankRuns)) {
174 targetModel.getMemInternalBaseAddress(srcCoord) + run.start;
175 if (run.size == 0 || bankStart >= origin + length ||
176 bankStart + run.size <= origin) {
180 std::string end =
"(ADDR(" + sec +
") + SIZEOF(" + sec +
"))";
181 dataOrigin =
"MAX(" + dataOrigin +
", (SIZEOF(" + sec +
182 ") != 0 ? MIN(" + dataEnd +
", " + end +
") : 0))";
185 output << R
"THESCRIPT(
189 output << " program (RX) : ORIGIN = 0, LENGTH = 0x"
190 << llvm::utohexstr(targetModel.getProgramMemorySize()) <<
"\n";
191 output <<
" data (!RX) : ORIGIN = " << dataOrigin <<
", LENGTH = ";
193 output <<
"0x" << llvm::utohexstr(length);
195 output << dataEnd <<
" - " << dataOrigin;
202 for (
auto [bank, run] : llvm::enumerate(bankRuns)) {
205 targetModel.getMemInternalBaseAddress(srcCoord) +
207 <<
", LENGTH = 0x" << llvm::utohexstr(run.size) <<
"\n";
209 output << R
"THESCRIPT(}
215 /* the __start symbol has to come at address zero. */
218 _init_array_start = .;
219 KEEP(SORT(*.init_array))
230 for (
auto [bank, run] : llvm::enumerate(bankRuns)) {
232 output <<
" " << sec <<
" : { *(" << sec <<
" " << sec <<
".*)"
233 <<
" *(*.DM_bank" <<
bankLetter(bank) <<
"*) } > "
236 output << R
"THESCRIPT( .data : {
255 /* Bitcode an object carries for aiecc's own analysis. It describes the core
256 rather than running on it, and --orphan-handling=error rejects any section
257 with no home, so name it here to drop it. */
264 auto doBuffer = [&](std::optional<TileID> tile,
int offset,
265 const std::string &dir) {
270 if (tiles.count(*tile)) {
271 for (
auto buf : buffers[tiles[*tile]]) {
272 if (buf.getCoreData()) {
276 output << buf.name().getValue() <<
" = 0x"
277 << llvm::utohexstr(offset) <<
";\n";
279 writeLDScriptMap(output, buf, offset);
284 output <<
"/* No tile with memory exists to the " << dir <<
". */\n";
285 output <<
". = 0x" << llvm::utohexstr(offset) <<
";\n";
286 uint32_t localMemSize = targetModel.getLocalMemorySize();
287 output <<
". += 0x" << llvm::utohexstr(localMemSize) <<
";\n";
292 if (
auto core = tile.getCoreOp()) {
296 targetModel.getMemInternalBaseAddress(srcCoord) +
299 output <<
"_sp_start_value_DM_stack = .;\n";
300 output <<
". += 0x" << llvm::utohexstr(stackRun.
size)
301 <<
"; /* stack */\n";
305 targetModel.getMemInternalBaseAddress(srcCoord))
307 output <<
"_sp_start_value_DM_stack = .;\n";
308 output <<
"/* no stack allocated */\n";
311 doBuffer(targetModel.getMemSouth(srcCoord),
312 targetModel.getMemSouthBaseAddress(), std::string(
"south"));
313 doBuffer(targetModel.getMemWest(srcCoord),
314 targetModel.getMemWestBaseAddress(), std::string(
"west"));
315 doBuffer(targetModel.getMemNorth(srcCoord),
316 targetModel.getMemNorthBaseAddress(), std::string(
"north"));
317 doBuffer(targetModel.getMemEast(srcCoord),
318 targetModel.getMemEastBaseAddress(), std::string(
"east"));
320 output <<
" .bss : { *(.bss*) } > data\n";
324 if (
auto coreOp = tile.getCoreOp()) {
326 if (
auto filesAttr = coreOp.getLinkFiles()) {
328 for (
auto f : filesAttr->getAsRange<mlir::StringAttr>()) {
330 << (resolveLinkFile ? resolveLinkFile(f.getValue())
331 : f.getValue().str())
334 }
else if (
auto fileAttr = coreOp.getLinkWith()) {
338 output <<
"INPUT(" << fileAttr.value().str() <<
")\n";
341 output <<
"PROVIDE(main = core_" << tile.getCol() <<
"_"
342 << tile.getRow() <<
");\n";
char bankLetter(int bank)
void collectTiles(DeviceOp &device, llvm::DenseMap< TileID, mlir::Operation * > &tiles)
void collectBuffers(DeviceOp &device, llvm::DenseMap< mlir::Operation *, llvm::SmallVector< BufferOp, 4 > > &buffers)
std::string bankSectionName(int bank)
llvm::SmallVector< MemoryRun > coreBankRegions(TileOp tile, llvm::ArrayRef< BufferOp > buffers, MemoryRun dataRun)
One extent per memory bank for the core's bank-pinned statics, tile-relative and indexed by bank.
struct TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")"; return os; } friend std::string to_string(const TileID &s) { std::ostringstream ss; ss<< s; return ss.str(); } friend llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const TileID &s) { os<< to_string(s); return os; } inline bool operator<(const TileID &rhs) const { return std::tie(col, row)< std::tie(rhs.col, rhs.row); } bool operator==(const TileID &rhs) const { return std::tie(col, row)==std::tie(rhs.col, rhs.row); } bool operator!=(const TileID &rhs) const { return !(*this==rhs);} int col, row;} TileID
int32_t getBufferBaseAddress(mlir::Operation *bufOp)
std::string bankRegionName(int bank)
const AIETargetModel & getTargetModel(mlir::Operation *op)
MemoryRun coreDataRegion(TileOp tile, llvm::ArrayRef< BufferOp > buffers)
The extent the core compiler gets for its own .data, .rodata and .bss, tile-relative.
mlir::LogicalResult AIETranslateToLdScript(mlir::ModuleOp module, llvm::raw_ostream &output, int tileCol, int tileRow, llvm::StringRef deviceName="", bool probe=false, llvm::function_ref< std::string(llvm::StringRef)> resolveLinkFile=nullptr)