From dd35c7e350c996ceb84b0812b720a3d1df8ce20b Mon Sep 17 00:00:00 2001 From: Jeff Fifield Date: Mon, 9 Sep 2024 10:56:25 -0600 Subject: [PATCH] initial cut-n-paste, plus some license updates --- include/aie/Conversion/CMakeLists.txt | 5 + .../AIEToTransaction/AIEToTransaction.cpp | 288 +++++++++++++++++- .../AIEToTransaction/CMakeLists.txt | 5 + lib/Conversion/AIEVecToLLVM/CMakeLists.txt | 5 + lib/Conversion/CMakeLists.txt | 5 + 5 files changed, 307 insertions(+), 1 deletion(-) diff --git a/include/aie/Conversion/CMakeLists.txt b/include/aie/Conversion/CMakeLists.txt index 40f9c3ec7e..6579f14ff1 100644 --- a/include/aie/Conversion/CMakeLists.txt +++ b/include/aie/Conversion/CMakeLists.txt @@ -1,3 +1,8 @@ +# This file is licensed under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# (c) Copyright 2024 Advanced Micro Devices, Inc. set(LLVM_TARGET_DEFINITIONS Passes.td) mlir_tablegen(Passes.h.inc -gen-pass-decls -name Conversion) mlir_tablegen(Passes.capi.h.inc -gen-pass-capi-header -prefix Conversion) diff --git a/lib/Conversion/AIEToTransaction/AIEToTransaction.cpp b/lib/Conversion/AIEToTransaction/AIEToTransaction.cpp index c1b7f8dfb6..4002181498 100644 --- a/lib/Conversion/AIEToTransaction/AIEToTransaction.cpp +++ b/lib/Conversion/AIEToTransaction/AIEToTransaction.cpp @@ -1,17 +1,303 @@ +//===- AIEToTransaction.h ---------------------------------------*- C++ -*-===// +// +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +// Copyright (C) 2024, Advanced Micro Devices, Inc. All rights reserved. +// +//===----------------------------------------------------------------------===// #include "../PassDetail.h" #include "aie/Conversion/AIEToTransaction/AIEToTransaction.h" +#include "aie/Targets/AIERTX.h" + +#include "llvm/Support/Debug.h" + +#include + +#define DEBUG_TYPE "aie-convert-to-transaction" using namespace mlir; +using namespace xilinx; +using namespace xilinx::AIE; + +namespace { + +// An TransactionBinaryOperation encapulates an aie-rt TnxCmd struct +struct TransactionBinaryOperation { + struct XAie_TxnCmd cmd; + TransactionBinaryOperation(XAie_TxnOpcode opc, uint32_t mask, uint64_t addr, + uint32_t value, const uint8_t *data, + uint32_t size) { + cmd.Opcode = opc; + cmd.Mask = mask; + cmd.RegOff = addr; + cmd.Value = value; + cmd.DataPtr = reinterpret_cast(data); + cmd.Size = size; + } +}; +} // namespace + +// Parse a TXN binary blob. On success return the number of columns from the +// header and a vector of parsed operations. On failure return std::nullopt. +static std::optional +parseTransactionBinary(const std::vector &data, + std::vector &ops) { + + uint32_t major = data[0]; + uint32_t minor = data[1]; + uint32_t num_cols = data[4]; + + uint32_t num_ops, txn_size; + std::memcpy(&num_ops, &data[8], 4); + std::memcpy(&txn_size, &data[12], 4); + + LLVM_DEBUG(llvm::dbgs() << "Major: " << major << "\n"); + LLVM_DEBUG(llvm::dbgs() << "Minor: " << minor << "\n"); + LLVM_DEBUG(llvm::dbgs() << "DevGen: " << data[2] << "\n"); + LLVM_DEBUG(llvm::dbgs() << "NumRows: " << data[3] << "\n"); + LLVM_DEBUG(llvm::dbgs() << "NumCols: " << num_cols << "\n"); + LLVM_DEBUG(llvm::dbgs() << "NumMemTileRows: " << data[5] << "\n"); + LLVM_DEBUG(llvm::dbgs() << "NumOps: " << num_ops << "\n"); + LLVM_DEBUG(llvm::dbgs() << "TxnSize: " << txn_size << " bytes\n"); + + size_t i = 16; + + // Convert opcode from uint8 to enum + auto convertOpcode = [](uint8_t opc) { + switch (opc) { + case 0: + return XAie_TxnOpcode::XAIE_IO_WRITE; + case 1: + return XAie_TxnOpcode::XAIE_IO_BLOCKWRITE; + case 3: + return XAie_TxnOpcode::XAIE_IO_MASKWRITE; + default: + llvm::errs() << "Unhandled opcode: " << std::to_string(opc) << "\n"; + return XAie_TxnOpcode::XAIE_IO_CUSTOM_OP_MAX; + } + }; + + // Parse the binary blob. There are two versions supported, 0.1 and 1.0. + // For both versions, build a list of TransactionBinaryOperation objects + // representing the parsed operations. + if (major == 0 && minor == 1) { + while (i < data.size()) { + + XAie_TxnOpcode opc = convertOpcode(data[i]); + LLVM_DEBUG(llvm::dbgs() << "opcode: " + std::to_string(opc) + "\n"); + + uint64_t addr = 0; + uint32_t value = 0; + uint32_t size = 0; + uint32_t mask = 0; + const uint8_t *data_ptr = nullptr; + + if (opc == XAie_TxnOpcode::XAIE_IO_WRITE) { + LLVM_DEBUG(llvm::dbgs() << "opcode: WRITE (0x00)\n"); + uint32_t addr0, addr1; + std::memcpy(&addr0, &data[i + 8], 4); + std::memcpy(&addr1, &data[i + 12], 4); + std::memcpy(&value, &data[i + 16], 4); + std::memcpy(&size, &data[i + 20], 4); + addr = static_cast(addr1) << 32 | addr0; + i += size; + } else if (opc == XAie_TxnOpcode::XAIE_IO_BLOCKWRITE) { + LLVM_DEBUG(llvm::dbgs() << "opcode: BLOCKWRITE (0x01)\n"); + std::memcpy(&addr, &data[i + 8], 4); + std::memcpy(&size, &data[i + 12], 4); + data_ptr = data.data() + i + 16; + i += size; + size = size - 16; + } else if (opc == XAie_TxnOpcode::XAIE_IO_MASKWRITE) { + LLVM_DEBUG(llvm::dbgs() << "opcode: MASKWRITE (0x03)\n"); + uint32_t addr0, addr1; + std::memcpy(&addr0, &data[i + 8], 4); + std::memcpy(&addr1, &data[i + 12], 4); + std::memcpy(&value, &data[i + 16], 4); + std::memcpy(&mask, &data[i + 20], 4); + std::memcpy(&size, &data[i + 24], 4); + addr = static_cast(addr1) << 32 | addr0; + i += size; + } else { + llvm::errs() << "Unhandled opcode: " << std::to_string(opc) << "\n"; + return std::nullopt; + } + ops.emplace_back(opc, mask, addr, value, data_ptr, size); + LLVM_DEBUG(llvm::dbgs() << "addr: " << addr << "\n"); + LLVM_DEBUG(llvm::dbgs() << "value: " << value << "\n"); + LLVM_DEBUG(llvm::dbgs() << "size: " << size << "\n"); + LLVM_DEBUG(llvm::dbgs() << "mask: " << mask << "\n"); + LLVM_DEBUG(llvm::dbgs() + << "data: " << reinterpret_cast(data_ptr) << "\n"); + } + } else if (major == 1 && minor == 0) { + while (i < data.size()) { + + XAie_TxnOpcode opc = convertOpcode(data[i]); + LLVM_DEBUG(llvm::dbgs() << "opcode: " + std::to_string(opc) + "\n"); + + uint64_t addr = 0; + uint32_t value = 0; + uint32_t size = 0; + uint32_t mask = 0; + const uint8_t *data_ptr = nullptr; + + if (opc == XAie_TxnOpcode::XAIE_IO_WRITE) { + LLVM_DEBUG(llvm::dbgs() << "opcode: WRITE (0x00)\n"); + std::memcpy(&addr, &data[i + 4], 4); + std::memcpy(&value, &data[i + 8], 4); + i += 12; + } else if (opc == XAie_TxnOpcode::XAIE_IO_BLOCKWRITE) { + LLVM_DEBUG(llvm::dbgs() << "opcode: BLOCKWRITE (0x01)\n"); + std::memcpy(&addr, &data[i + 4], 4); + std::memcpy(&size, &data[i + 8], 4); + data_ptr = data.data() + i + 12; + i += size; + size = size - 12; + } else if (opc == XAie_TxnOpcode::XAIE_IO_MASKWRITE) { + LLVM_DEBUG(llvm::dbgs() << "opcode: MASKWRITE (0x03)\n"); + std::memcpy(&addr, &data[i + 4], 4); + std::memcpy(&value, &data[i + 8], 4); + std::memcpy(&mask, &data[i + 12], 4); + i += 16; + } else { + llvm::errs() << "Unhandled opcode: " << std::to_string(opc) << "\n"; + return std::nullopt; + } + LLVM_DEBUG(llvm::dbgs() << "addr: " << addr << "\n"); + LLVM_DEBUG(llvm::dbgs() << "value: " << value << "\n"); + LLVM_DEBUG(llvm::dbgs() << "size: " << size << "\n"); + LLVM_DEBUG(llvm::dbgs() << "mask: " << mask << "\n"); + LLVM_DEBUG(llvm::dbgs() + << "data: " << reinterpret_cast(data_ptr) << "\n"); + ops.emplace_back(opc, mask, addr, value, data_ptr, size); + } + } else { + llvm::errs() << "Unsupported TXN binary version: " << major << "." << minor + << "\n"; + return std::nullopt; + } + + return num_cols; +} + +static LogicalResult +generateTxn(AIERTXControl &ctl, const StringRef workDirPath, DeviceOp &targetOp, + bool aieSim, bool enableElfs, bool enableInit, bool enableCores) { + if (enableElfs && !targetOp.getOps().empty() && + failed(ctl.addAieElfs(targetOp, workDirPath, aieSim))) + return failure(); + if (enableInit && failed(ctl.addInitConfig(targetOp))) + return failure(); + if (enableCores && !targetOp.getOps().empty() && + failed(ctl.addCoreEnable(targetOp))) + return failure(); + return success(); +} namespace { struct ConvertAIEToTransactionPass : ConvertAIEToTransactionBase { void runOnOperation() override { + auto device = getOperation(); - device.dump(); + + const BaseNPUTargetModel &targetModel = + (const BaseNPUTargetModel &)device.getTargetModel(); + + if (!targetModel.isNPU()) + return; + + bool aieSim = false; + bool xaieDebug = false; + + AIERTXControl ctl(targetModel); + if (failed(ctl.setIOBackend(aieSim, xaieDebug))) + return signalPassFailure(); + + // start collecting transations + XAie_StartTransaction(&ctl.devInst, XAIE_TRANSACTION_DISABLE_AUTO_FLUSH); + + std::string workDirPath = "workdir"; + auto result = + generateTxn(ctl, workDirPath, device, aieSim, true, true, true); + if (failed(result)) + return signalPassFailure(); + + // Export the transactions to a binary buffer + uint8_t *txn_ptr = XAie_ExportSerializedTransaction(&ctl.devInst, 0, 0); + XAie_TxnHeader *hdr = (XAie_TxnHeader *)txn_ptr; + std::vector txn_data(txn_ptr, txn_ptr + hdr->TxnSize); + + // parse the binary data + std::vector operations; + auto c = parseTransactionBinary(txn_data, operations); + if (!c) { + llvm::errs() << "Failed to parse binary\n"; + return signalPassFailure(); + } + // int columns = *c; + + OpBuilder builder(device); + auto loc = device.getLoc(); + + // for each blockwrite in the binary, create a GlobalOp with the data + std::vector global_data; + for (auto &op : operations) { + if (op.cmd.Opcode != XAIE_IO_BLOCKWRITE) { + global_data.push_back(nullptr); + continue; + } + uint32_t size = op.cmd.Size / 4; + const uint32_t *d = reinterpret_cast(op.cmd.DataPtr); + std::vector data32(d, d + size); + + int id = 0; + std::string name = "blockwrite_data"; + while (device.lookupSymbol(name)) + name = "blockwrite_data_" + std::to_string(id++); + + MemRefType memrefType = MemRefType::get({size}, builder.getI32Type()); + TensorType tensorType = + RankedTensorType::get({size}, builder.getI32Type()); + auto global = builder.create( + loc, name, builder.getStringAttr("private"), memrefType, + DenseElementsAttr::get(tensorType, data32), true, nullptr); + global_data.push_back(global); + } + + auto seq = builder.create(loc, nullptr); + seq.getBody().push_back(new Block); + + // create the txn ops + builder.setInsertionPointToStart(&seq.getBody().front()); + for (auto p : llvm::zip(operations, global_data)) { + auto op = std::get<0>(p); + memref::GlobalOp payload = std::get<1>(p); + + if (op.cmd.Opcode == XAie_TxnOpcode::XAIE_IO_WRITE) { + builder.create(loc, op.cmd.RegOff, op.cmd.Value, + nullptr, nullptr, nullptr); + } else if (op.cmd.Opcode == XAie_TxnOpcode::XAIE_IO_BLOCKWRITE) { + auto memref = builder.create( + loc, payload.getType(), payload.getName()); + builder.create( + loc, builder.getUI32IntegerAttr(op.cmd.RegOff), memref.getResult(), + nullptr, nullptr, nullptr); + } else if (op.cmd.Opcode == XAie_TxnOpcode::XAIE_IO_MASKWRITE) { + builder.create(loc, op.cmd.RegOff, op.cmd.Value, + op.cmd.Mask, nullptr, nullptr, + nullptr); + } else { + llvm::errs() << "Unhandled txn opcode: " << op.cmd.Opcode << "\n"; + return signalPassFailure(); + } + } } }; diff --git a/lib/Conversion/AIEToTransaction/CMakeLists.txt b/lib/Conversion/AIEToTransaction/CMakeLists.txt index 87e0c826c3..c2b8735d37 100644 --- a/lib/Conversion/AIEToTransaction/CMakeLists.txt +++ b/lib/Conversion/AIEToTransaction/CMakeLists.txt @@ -1,3 +1,8 @@ +# This file is licensed under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# (c) Copyright 2024 Advanced Micro Devices, Inc. add_mlir_conversion_library(MLIRAIEToTransaction AIEToTransaction.cpp diff --git a/lib/Conversion/AIEVecToLLVM/CMakeLists.txt b/lib/Conversion/AIEVecToLLVM/CMakeLists.txt index acba6d9780..268b06782d 100644 --- a/lib/Conversion/AIEVecToLLVM/CMakeLists.txt +++ b/lib/Conversion/AIEVecToLLVM/CMakeLists.txt @@ -1,3 +1,8 @@ +# This file is licensed under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# (c) Copyright 2024 Advanced Micro Devices, Inc. add_mlir_conversion_library(MLIRAIEVecToLLVM AIEVecToLLVM.cpp diff --git a/lib/Conversion/CMakeLists.txt b/lib/Conversion/CMakeLists.txt index 7dfda13f60..8f0cf09cd1 100644 --- a/lib/Conversion/CMakeLists.txt +++ b/lib/Conversion/CMakeLists.txt @@ -1,2 +1,7 @@ +# This file is licensed under the Apache License v2.0 with LLVM Exceptions. +# See https://llvm.org/LICENSE.txt for license information. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# (c) Copyright 2024 Advanced Micro Devices, Inc. add_subdirectory(AIEToTransaction) add_subdirectory(AIEVecToLLVM) \ No newline at end of file