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