MLIR-AIE
AIETargets.cpp
Go to the documentation of this file.
1//===- AIETargets.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// (c) Copyright 2021 Xilinx Inc.
8//
9//===----------------------------------------------------------------------===//
10
12
16
17#include "mlir/Dialect/Arith/IR/Arith.h"
18#include "mlir/Dialect/ControlFlow/IR/ControlFlow.h"
19#include "mlir/Dialect/DLTI/DLTI.h"
20#include "mlir/Dialect/EmitC/IR/EmitC.h"
21#include "mlir/Dialect/Func/IR/FuncOps.h"
22#include "mlir/Dialect/Index/IR/IndexDialect.h"
23#include "mlir/Dialect/Math/IR/Math.h"
24#include "mlir/Dialect/SCF/IR/SCF.h"
25#include "mlir/Dialect/Vector/IR/VectorOps.h"
26#include "mlir/IR/Attributes.h"
27#include "mlir/Target/LLVMIR/Export.h"
28#include "mlir/Target/LLVMIR/Import.h"
29#include "mlir/Tools/mlir-translate/Translation.h"
30
31#include "llvm/Support/CommandLine.h"
32#include "llvm/Support/Debug.h"
33#include "llvm/Support/FileSystem.h"
34#include "llvm/Support/JSON.h"
35
36#include <set>
37
38#define DEBUG_TYPE "aie-targets"
39
40using namespace mlir;
41using namespace mlir::vector;
42using namespace xilinx;
43using namespace xilinx::AIE;
44
45llvm::json::Value attrToJSON(Attribute &attr) {
46 if (auto a = llvm::dyn_cast<StringAttr>(attr))
47 return {a.getValue().str()};
48
49 if (auto arrayAttr = llvm::dyn_cast<ArrayAttr>(attr)) {
50 llvm::json::Array arrayJSON;
51 for (auto a : arrayAttr)
52 arrayJSON.push_back(attrToJSON(a));
53 return llvm::json::Value(std::move(arrayJSON));
54 }
55
56 if (auto dictAttr = llvm::dyn_cast<DictionaryAttr>(attr)) {
57 llvm::json::Object dictJSON;
58 for (auto a : dictAttr) {
59 auto ident = a.getName();
60 auto attr = a.getValue();
61 dictJSON[ident.str()] = attrToJSON(attr);
62 }
63 return llvm::json::Value(std::move(dictJSON));
64 }
65
66 if (auto intAttr = llvm::dyn_cast<IntegerAttr>(attr))
67 return llvm::json::Value(intAttr.getInt());
68
69 return llvm::json::Value(std::string(""));
70}
71
72namespace xilinx::AIE {
73
74static void registerDialects(DialectRegistry &registry) {
75 registry.insert<xilinx::AIE::AIEDialect>();
76 registry.insert<xilinx::AIEX::AIEXDialect>();
77 registry.insert<func::FuncDialect>();
78 registry.insert<scf::SCFDialect>();
79 registry.insert<cf::ControlFlowDialect>();
80 registry.insert<DLTIDialect>();
81 registry.insert<arith::ArithDialect>();
82 registry.insert<math::MathDialect>();
83 registry.insert<memref::MemRefDialect>();
84 registry.insert<VectorDialect>();
85 registry.insert<LLVM::LLVMDialect>();
86 registry.insert<emitc::EmitCDialect>();
87 registry.insert<index::IndexDialect>();
88}
89
90// Output the buffer map for the given buffer operations, with the given offset.
91// The offset is different depending on where the buffers are accessed from.
92void writeBufferMap(raw_ostream &output, BufferOp buf, int offset) {
93 std::string bufName(buf.name().getValue());
94 int bufferBaseAddr = getBufferBaseAddress(buf);
95 int numBytes = buf.getAllocationSize();
96 output << "_symbol " << bufName << " "
97 << "0x" << llvm::utohexstr(offset + bufferBaseAddr) << " " << numBytes
98 << '\n';
99}
100
101LogicalResult AIETranslateToTargetArch(ModuleOp module, raw_ostream &output) {
102 AIEArch arch = AIEArch::AIE1;
103 if (!module.getOps<DeviceOp>().empty()) {
104 DeviceOp targetOp = *(module.getOps<DeviceOp>().begin());
105 arch = targetOp.getTargetModel().getTargetArch();
106 }
107 if (arch == AIEArch::AIE1)
108 output << "AIE\n";
109 else
110 output << stringifyEnum(arch) << "\n";
111 return success();
112}
113
115 static llvm::cl::opt<int> tileCol(
116 "tilecol", llvm::cl::desc("column coordinate of core to translate"),
117 llvm::cl::init(0));
118 static llvm::cl::opt<int> tileRow(
119 "tilerow", llvm::cl::desc("row coordinate of core to translate"),
120 llvm::cl::init(0));
121
122#ifdef AIE_ENABLE_AIRBIN
123 static llvm::cl::opt<std::string> outputFilename(
124 "airbin-output-filepath",
125 llvm::cl::desc("Output airbin file path (including filename)"),
126 llvm::cl::value_desc("airbin-output-filepath"),
127 llvm::cl::init("airbin.elf"));
128
129 static llvm::cl::opt<std::string> coreFilesDir(
130 "airbin-aux-core-dir-path",
131 llvm::cl::desc("Auxiliary core elf files dir path"),
132 llvm::cl::value_desc("airbin-aux-core-dir-path"), llvm::cl::init("."));
133#endif
134
135 static llvm::cl::opt<std::string> workDirPath(
136 "work-dir-path", llvm::cl::Optional,
137 llvm::cl::desc("Absolute path to working directory"));
138
139 static llvm::cl::opt<bool> bigEndian("big-endian", llvm::cl::init(false),
140 llvm::cl::desc("Endianness"));
141
142 static llvm::cl::opt<bool> cdoUnified(
143 "cdo-unified", llvm::cl::init(false),
144 llvm::cl::desc("Emit unified CDO bin (or separate bins)"));
145 static llvm::cl::opt<bool> cdoDebug("cdo-debug", llvm::cl::init(false),
146 llvm::cl::desc("Emit cdo debug info"));
147 static llvm::cl::opt<bool> cdoAieSim(
148 "cdo-aiesim", llvm::cl::init(false),
149 llvm::cl::desc("AIESIM target cdo generation"));
150 static llvm::cl::opt<bool> cdoXaieDebug(
151 "cdo-xaie-debug", llvm::cl::init(false),
152 llvm::cl::desc("Emit libxaie debug info"));
153 static llvm::cl::opt<size_t> cdoEnableCores(
154 "cdo-enable-cores", llvm::cl::init(true),
155 llvm::cl::desc("Enable cores in CDO"));
156
157 static llvm::cl::opt<bool> outputBinary(
158 "aie-output-binary", llvm::cl::init(true),
159 llvm::cl::desc(
160 "Select binary (true) or text (false) output for supported "
161 "translations. e.g. aie-npu-to-binary, aie-ctrlpkt-to-bin"));
162
163 static llvm::cl::opt<std::string> sequenceName(
164 "aie-sequence-name", llvm::cl::init(""),
165 llvm::cl::desc(
166 "Specify the name of the aiex.runtime_sequence to translate"));
167
168 TranslateFromMLIRRegistration registrationMMap(
169 "aie-generate-mmap", "Generate AIE memory map",
170 [](ModuleOp module, raw_ostream &output) {
171 DenseMap<TileID, Operation *> tiles;
172 DenseMap<Operation *, SmallVector<BufferOp, 4>> buffers;
173
174 if (module.getOps<DeviceOp>().empty()) {
175 module.emitOpError("expected AIE.device operation at toplevel");
176 }
177 DeviceOp targetOp = *(module.getOps<DeviceOp>().begin());
178
179 collectTiles(targetOp, tiles);
180 // sort the tiles for deterministic output
181 using tileType = std::pair<TileID, Operation *>;
182 struct tileCmp {
183 bool operator()(const tileType &lhs, const tileType &rhs) const {
184 return lhs.first < rhs.first;
185 }
186 };
187 std::set<tileType, tileCmp> sortedTiles;
188 for (auto tile : tiles)
189 sortedTiles.insert(tileType{tile.first, tile.second});
190
191 collectBuffers(targetOp, buffers);
192
193 for (auto tile : sortedTiles) {
194 Operation *srcTileOp = tile.second;
195 TileID srcCoord = cast<TileOp>(srcTileOp).getTileID();
196 int srcCol = srcCoord.col;
197 int srcRow = srcCoord.row;
198
199 output << "// Tile(" << srcCol << ", " << srcRow << ")\n";
200 output << "// Memory map: name base_address num_bytes\n";
201
202 auto doBuffer = [&](std::optional<TileID> tile, int offset) {
203 if (tiles.count(*tile))
204 for (auto buf : buffers[tiles[*tile]])
205 writeBufferMap(output, buf, offset);
206 };
207
208 const auto &targetModel = xilinx::AIE::getTargetModel(srcTileOp);
209
210 if (auto tile = targetModel.getMemSouth(srcCoord))
211 doBuffer(tile, targetModel.getMemSouthBaseAddress());
212 if (auto tile = targetModel.getMemWest(srcCoord))
213 doBuffer(tile, targetModel.getMemWestBaseAddress());
214 if (auto tile = targetModel.getMemNorth(srcCoord))
215 doBuffer(tile, targetModel.getMemNorthBaseAddress());
216 if (auto tile = targetModel.getMemEast(srcCoord))
217 doBuffer(tile, targetModel.getMemEastBaseAddress());
218 }
219 return success();
220 },
221 registerDialects);
222
223 TranslateFromMLIRRegistration registrationShimDMAToJSON(
224 "aie-generate-json", "Transform AIE shim DMA allocation info into JSON",
225 [](ModuleOp module, raw_ostream &output) {
226 for (auto d : module.getOps<DeviceOp>()) {
227 llvm::json::Object moduleJSON;
228 for (auto shimDMAMeta : d.getOps<ShimDMAAllocationOp>()) {
229 llvm::json::Object shimJSON;
230 auto channelDir = shimDMAMeta.getChannelDirAttr();
231 shimJSON["channelDir"] = attrToJSON(channelDir);
232 auto channelIndex = shimDMAMeta.getChannelIndexAttr();
233 shimJSON["channelIndex"] = attrToJSON(channelIndex);
234 auto col = shimDMAMeta.getColAttr();
235 shimJSON["col"] = attrToJSON(col);
236 moduleJSON[shimDMAMeta.getSymName()] =
237 llvm::json::Value(std::move(shimJSON));
238 }
239 llvm::json::Value topv(std::move(moduleJSON));
240 std::string ret;
241 llvm::raw_string_ostream ss(ret);
242 ss << llvm::formatv("{0:2}", topv) << "\n";
243 output << ss.str();
244 }
245 return success();
246 },
247 registerDialects);
248
249 TranslateFromMLIRRegistration registrationLDScript(
250 "aie-generate-ldscript", "Generate AIE loader script",
251 [](ModuleOp module, raw_ostream &output) {
252 return AIETranslateToLdScript(module, output, tileCol, tileRow);
253 },
254 registerDialects);
255
256 TranslateFromMLIRRegistration registrationBCF(
257 "aie-generate-bcf", "Generate AIE bcf",
258 [](ModuleOp module, raw_ostream &output) {
259 return AIETranslateToBCF(module, output, tileCol, tileRow);
260 },
261 registerDialects);
262
263 TranslateFromMLIRRegistration registrationTargetArch(
264 "aie-generate-target-arch", "Get the target architecture",
265 AIETranslateToTargetArch, registerDialects);
266
267 TranslateFromMLIRRegistration registrationCoreList(
268 "aie-generate-corelist", "Generate python list of cores",
269 [](ModuleOp module, raw_ostream &output) {
270 if (module.getOps<DeviceOp>().empty()) {
271 module.emitOpError("expected AIE.device operation at toplevel");
272 }
273 DeviceOp targetOp = *(module.getOps<DeviceOp>().begin());
274
275 output << "[";
276 for (auto tileOp : targetOp.getOps<TileOp>()) {
277 int col = tileOp.colIndex();
278 int row = tileOp.rowIndex();
279 if (auto coreOp = tileOp.getCoreOp()) {
280 std::string elfFile = "None";
281 if (auto fileAttr = coreOp.getElfFile())
282 elfFile = "\"" + fileAttr.value().str() + "\"";
283 output << '(' << col << ',' << row << ',' << elfFile << "),";
284 }
285 }
286 output << "]\n";
287 return success();
288 },
289 registerDialects);
290
291 TranslateFromMLIRRegistration registrationXADF(
292 "adf-generate-cpp-graph", "Translate ADFDialect to C++ graph",
293 ADFGenerateCPPGraph, [](DialectRegistry &registry) {
294 registry.insert<xilinx::ADF::ADFDialect>();
295 registerDialects(registry);
296 });
297#ifdef AIE_ENABLE_AIRBIN
298 TranslateFromMLIRRegistration registrationAirbin(
299 "aie-generate-airbin", "Generate configuration binary blob",
300 [](ModuleOp module, raw_ostream &) {
301 return AIETranslateToAirbin(module, outputFilename, coreFilesDir);
302 },
303 registerDialects);
304#endif
305 TranslateFromMLIRRegistration registrationXAIE(
306 "aie-generate-xaie", "Generate libxaie configuration",
307 [](ModuleOp module, raw_ostream &output) {
308 return AIETranslateToXAIEV2(module, output);
309 },
310 registerDialects);
311 TranslateFromMLIRRegistration registrationHSA(
312 "aie-generate-hsa", "Generate hsa data movement configuration",
313 [](ModuleOp module, raw_ostream &output) {
314 return AIETranslateToHSA(module, output);
315 },
316 registerDialects);
317 TranslateFromMLIRRegistration registrationXJSON(
318 "aie-flows-to-json", "Translate AIE flows to JSON", AIEFlowsToJSON,
319 registerDialects);
320 TranslateFromMLIRRegistration registrationXPE(
321 "aie-mlir-to-xpe", "Translate AIE design to XPE file for simulation",
322 AIETranslateGraphXPE, registerDialects);
323 TranslateFromMLIRRegistration registrationSCSimConfig(
324 "aie-mlir-to-scsim-config",
325 "Translate AIE design to SCSimConfig file for simulation",
326 AIETranslateSCSimConfig, registerDialects);
327 TranslateFromMLIRRegistration registrationShimSolution(
328 "aie-mlir-to-shim-solution",
329 "Translate AIE design to ShimSolution file for simulation",
330 AIETranslateShimSolution, registerDialects);
331 TranslateFromMLIRRegistration registrationCDODirect(
332 "aie-generate-cdo", "Generate libxaie for CDO directly",
333 [](ModuleOp module, raw_ostream &) {
334 SmallString<128> workDirPath_;
335 if (workDirPath.getNumOccurrences() == 0) {
336 if (llvm::sys::fs::current_path(workDirPath_))
337 llvm::report_fatal_error(
338 "couldn't get cwd to use as work-dir-path");
339 } else
340 workDirPath_ = workDirPath.getValue();
341 LLVM_DEBUG(llvm::dbgs() << "work-dir-path: " << workDirPath_ << "\n");
342 return AIETranslateToCDODirect(module, workDirPath_.c_str(), bigEndian,
343 cdoUnified, cdoDebug, cdoAieSim,
344 cdoXaieDebug, cdoEnableCores);
345 },
346 registerDialects);
347 TranslateFromMLIRRegistration registrationNPU(
348 "aie-npu-to-binary", "Translate npu instructions to binary",
349 [](ModuleOp module, raw_ostream &output) {
350 std::vector<uint32_t> instructions;
351 auto r = AIETranslateNpuToBinary(module, instructions, sequenceName);
352 if (failed(r))
353 return r;
354 if (outputBinary) {
355 output.write(reinterpret_cast<const char *>(instructions.data()),
356 instructions.size() * sizeof(uint32_t));
357 } else {
358 for (auto w : instructions)
359 output << llvm::format("%08X\n", w);
360 }
361 return success();
362 },
363 registerDialects);
364 TranslateFromMLIRRegistration registrationCtrlPkt(
365 "aie-ctrlpkt-to-bin", "Translate aiex.control_packet ops to binary",
366 [](ModuleOp module, raw_ostream &output) {
367 std::vector<uint32_t> instructions;
368 auto r = AIETranslateControlPacketsToUI32Vec(module, instructions,
369 sequenceName);
370 if (failed(r))
371 return r;
372 if (outputBinary) {
373 output.write(reinterpret_cast<const char *>(instructions.data()),
374 instructions.size() * sizeof(uint32_t));
375 } else {
376 for (auto w : instructions)
377 output << llvm::format("%08X\n", w);
378 }
379 return success();
380 },
381 registerDialects);
382}
383} // namespace xilinx::AIE
llvm::json::Value attrToJSON(Attribute &attr)
Include the generated interface declarations.
mlir::LogicalResult AIETranslateToXAIEV2(mlir::ModuleOp module, llvm::raw_ostream &output)
mlir::LogicalResult AIETranslateToCDODirect(mlir::ModuleOp m, llvm::StringRef workDirPath, bool bigEndian=false, bool emitUnified=false, bool cdoDebug=false, bool aieSim=false, bool xaieDebug=false, bool enableCores=true)
mlir::LogicalResult ADFGenerateCPPGraph(mlir::ModuleOp module, llvm::raw_ostream &output)
void writeBufferMap(raw_ostream &output, BufferOp buf, int offset)
void registerAIETranslations()
mlir::LogicalResult AIETranslateToHSA(mlir::ModuleOp module, llvm::raw_ostream &output)
mlir::LogicalResult AIETranslateToBCF(mlir::ModuleOp module, llvm::raw_ostream &output, int tileCol, int tileRow)
TileID { friend std::ostream &operator<<(std::ostream &os, const TileID &s) { os<< "TileID("<< s.col<< ", "<< s.row<< ")" TileID
int32_t getBufferBaseAddress(mlir::Operation *bufOp)
mlir::LogicalResult AIETranslateToTargetArch(mlir::ModuleOp module, llvm::raw_ostream &output)
mlir::LogicalResult AIETranslateToLdScript(mlir::ModuleOp module, llvm::raw_ostream &output, int tileCol, int tileRow)
mlir::LogicalResult AIETranslateNpuToBinary(mlir::ModuleOp, std::vector< uint32_t > &, llvm::StringRef sequenceName="")
const AIETargetModel & getTargetModel(mlir::Operation *op)
mlir::LogicalResult AIETranslateShimSolution(mlir::ModuleOp module, llvm::raw_ostream &)
mlir::LogicalResult AIEFlowsToJSON(mlir::ModuleOp module, llvm::raw_ostream &output)
mlir::LogicalResult AIETranslateToAirbin(mlir::ModuleOp module, const std::string &outputFilename, const std::string &coreFilesDir, bool testAirBin)
mlir::LogicalResult AIETranslateSCSimConfig(mlir::ModuleOp module, llvm::raw_ostream &output)
mlir::LogicalResult AIETranslateControlPacketsToUI32Vec(mlir::ModuleOp, std::vector< uint32_t > &, llvm::StringRef sequenceName="")
mlir::LogicalResult AIETranslateGraphXPE(mlir::ModuleOp module, llvm::raw_ostream &)
AIEArch
Definition Passes.h:21