MLIR-AIE 1.4.5.dev
AIETargetBCF.cpp
Go to the documentation of this file.
1//===- AIETargetBCF.cpp -----------------------------------------*- C++ -*-===//
2//
3// Copyright (C) 2023 Advanced Micro Devices, Inc.
4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5//
6//===----------------------------------------------------------------------===//
7
12
13#include "mlir/IR/IRMapping.h"
14#include "mlir/Pass/Pass.h"
15#include "mlir/Tools/mlir-translate/MlirTranslateMain.h"
16
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/IR/Module.h"
20
21using namespace mlir;
22using namespace xilinx;
23using namespace xilinx::AIE;
24using namespace xilinx::AIEX;
25
26static std::string utohexstr(uint32_t u) { return "0x" + llvm::utohexstr(u); }
27
28namespace xilinx {
29namespace AIE {
30
31LogicalResult AIETranslateToBCF(ModuleOp module, raw_ostream &output,
32 int tileCol, int tileRow,
33 llvm::StringRef deviceName) {
34 DenseMap<TileID, Operation *> tiles;
35 DenseMap<Operation *, SmallVector<BufferOp, 4>> buffers;
36
37 DeviceOp targetOp = AIE::DeviceOp::getForSymbolInModule(module, deviceName);
38 if (!targetOp)
39 module.emitOpError("expected aie.device operation at toplevel");
40
41 collectTiles(targetOp, tiles);
42 collectBuffers(targetOp, buffers);
43
44 // _entry_point _main_init
45 // _symbol _main _after _main_init
46 // _symbol _main_init 0
47 // _reserved DMb 0x00000 0x20000
48 // _symbol a 0x38000 0x2000
49 // _extern a
50 // _stack DM_stack 0x20000 0x400 //stack for core
51 // _reserved DMb 0x40000 0xc0000 // And everything else the core can't
52 // see
53 // // Include all symbols from rom.c
54 // _include _file rom.o
55 for (auto tile : targetOp.getOps<TileOp>())
56 if (tile.colIndex() == tileCol && tile.rowIndex() == tileRow) {
57 const auto &targetModel = getTargetModel(tile);
58 TileID srcCoord = {tile.colIndex(), tile.rowIndex()};
59
60 std::string corefunc = coreFrameSymbolName(tile.getCol(), tile.getRow());
61 output << "_entry_point _main_init\n";
62 output << "_symbol " << corefunc << " _after _main_init\n";
63 output << "_symbol _main_init 0\n";
64 int dataMemoryStart = targetModel.getMemSouthBaseAddress();
65 output << "_reserved DMb 0x00000 " << utohexstr(dataMemoryStart)
66 << " // Don't put data in code memory\n";
67
68 MemoryRun stackRun;
69 if (auto core = tile.getCoreOp()) {
70 if (core.getStackBank() && !core.getStackAddress())
71 return core.emitOpError(
72 "stack_bank has no assigned stack_address; run "
73 "--aie-assign-buffer-addresses with bank-aware allocation");
74 stackRun = core.getStackRun();
75 }
76 output << "_stack DM_stack "
77 << utohexstr(targetModel.getMemInternalBaseAddress(srcCoord) +
78 stackRun.start)
79 << " " << utohexstr(stackRun.size) << " // stack for core\n";
80
81 auto doBuffer = [&](std::optional<TileID> tile, int offset,
82 const std::string &dir) {
83 if (tile) {
84 output << "// " + dir +
85
86 " -------------------------------------------------\n";
87 uint32_t localMemSize = targetModel.getLocalMemorySize();
88 if (tile != srcCoord)
89 output << "_reserved DMb " << utohexstr(offset) << " "
90 << utohexstr(localMemSize) << " "
91 << " // Don't allocate variables in " << dir
92 << " neighbor\n\n";
93 // TODO How to set as reserved if no buffer exists (or reserve
94 // remaining buffer)
95 if (tiles.count(*tile)) {
96 for (auto buf : buffers[tiles[*tile]]) {
97 if (buf.getCoreData())
98 continue;
99 std::string bufName(buf.name().getValue());
100 int bufferBaseAddr = getBufferBaseAddress(buf);
101 int numBytes = buf.getAllocationSize();
102 // Every buffer is an external symbol at a reserved address,
103 // whether or not it has an `initial_value`. No core object
104 // defines a buffer, so there is no data here to overlay. Whoever
105 // configures the device writes the initial value.
106 output << "_symbol " << bufName << " "
107 << utohexstr(offset + bufferBaseAddr) << " " << numBytes
108 << '\n';
109 output << "_extern " << bufName << "\n";
110 output << "_reserved DMb " << utohexstr(offset + bufferBaseAddr)
111 << " " << numBytes << '\n';
112 output << "\n";
113 }
114 }
115 } else {
116 uint32_t localMemSize = targetModel.getLocalMemorySize();
117 output << "_reserved DMb " << utohexstr(offset) << " "
118 << utohexstr(localMemSize) << " "
119 << " // No tile with memory exists to the " << dir << ".\n";
120 }
121 };
122
123 output << "\n// mapping neighbors tile memory\n";
124 doBuffer(targetModel.getMemSouth(srcCoord),
125 targetModel.getMemSouthBaseAddress(), std::string("south"));
126 doBuffer(targetModel.getMemWest(srcCoord),
127 targetModel.getMemWestBaseAddress(), std::string("west"));
128 doBuffer(targetModel.getMemNorth(srcCoord),
129 targetModel.getMemNorthBaseAddress(), std::string("north"));
130 doBuffer(targetModel.getMemEast(srcCoord),
131 targetModel.getMemEastBaseAddress(), std::string("east"));
132 output << "// end mapping neighbors tile memory\n\n";
133
134 int addressSpaceSize = targetModel.getCoreDataAddressSpaceSize();
135 int dataMemoryEnd = targetModel.getMemEastBaseAddress() +
136 targetModel.getLocalMemorySize();
137 output << "_reserved DMb " << utohexstr(dataMemoryEnd) << " "
138 << utohexstr(addressSpaceSize - dataMemoryEnd)
139 << " // And everything else the core can't see\n";
140
141 if (auto coreOp = tile.getCoreOp()) {
142 // `link_files` holds the final-link inputs (object files)
143 if (auto filesAttr = coreOp.getLinkFiles()) {
144 // Canonical path: link_files populated by aie-assign-core-link-files.
145 for (auto f : filesAttr->getAsRange<mlir::StringAttr>())
146 output << "_include _file " << f.getValue() << "\n";
147 } else if (auto linkWith = coreOp.getLinkWith()) {
148 // Deprecated fallback: core-level link_with was not migrated by
149 // aie-assign-core-link-files (e.g., the pass was not run). It carries
150 // no mode, so it is always an ordinary link input.
151 output << "_include _file " << linkWith->str() << "\n";
152 }
153 }
154 output << "_resolve _main core_" << tile.getCol() << "_" << tile.getRow()
155 << "\n";
156 }
157
158 return success();
159}
160} // namespace AIE
161} // namespace xilinx
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 coreFrameSymbolName(int col, int row)
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)
mlir::LogicalResult AIETranslateToBCF(mlir::ModuleOp module, llvm::raw_ostream &output, int tileCol, int tileRow, llvm::StringRef deviceName="")
const AIETargetModel & getTargetModel(mlir::Operation *op)