diff --git a/include/aie-c/TargetModel.h b/include/aie-c/TargetModel.h new file mode 100644 index 0000000000..4e166f373f --- /dev/null +++ b/include/aie-c/TargetModel.h @@ -0,0 +1,143 @@ +//===- TargetModel.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 +// +// (c) Copyright 2024 Advanced Micro Devices, Inc. +// +//===----------------------------------------------------------------------===// + +#ifndef AIE_C_TARGETMODEL_H +#define AIE_C_TARGETMODEL_H + +#include "mlir-c/IR.h" + +#ifdef __cplusplus +extern "C" { +#endif + +//===----------------------------------------------------------------------===// +// Opaque type declarations. +// +// Types are exposed to C bindings as structs containing opaque pointers. They +// are not supposed to be inspected from C. This allows the underlying +// representation to change without affecting the API users. The use of structs +// instead of typedefs enables some type safety as structs are not implicitly +// convertible to each other. +// +// Instances of these types may or may not own the underlying object. The +// ownership semantics is defined by how an instance of the type was obtained. +//===----------------------------------------------------------------------===// + +#define DEFINE_C_API_STRUCT(name, storage) \ + struct name { \ + storage d; \ + }; \ + typedef struct name name + +DEFINE_C_API_STRUCT(AieTargetModel, uint32_t); + +#undef DEFINE_C_API_STRUCT + +MLIR_CAPI_EXPORTED AieTargetModel aieGetTargetModel(uint32_t device); + +/// Returns the number of columns in the target model. +MLIR_CAPI_EXPORTED int aieTargetModelColumns(AieTargetModel targetModel); + +/// Returns the number of rows in the target model. +MLIR_CAPI_EXPORTED int aieTargetModelRows(AieTargetModel targetModel); + +/// Returns true if this is an NPU target model. +MLIR_CAPI_EXPORTED bool aieTargetModelIsNPU(AieTargetModel targetModel); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsCoreTile(AieTargetModel targetModel, + int col, int row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsMemTile(AieTargetModel targetModel, + int col, int row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsShimNOCTile(AieTargetModel targetModel, + int col, int row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsShimPLTile(AieTargetModel targetModel, + int col, int row); + +MLIR_CAPI_EXPORTED bool +aieTargetModelIsShimNOCorPLTile(AieTargetModel targetModel, int col, int row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsInternal(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsWest(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsEast(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsNorth(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsSouth(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsMemWest(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsMemEast(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsMemNorth(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool aieTargetModelIsMemSouth(AieTargetModel targetModel, + int src_col, int src_row, + int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED bool +aieTargetModelIsLegalMemAffinity(AieTargetModel targetModel, int src_col, + int src_row, int dst_col, int dst_row); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetMemSouthBaseAddress(AieTargetModel targetModel); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetMemNorthBaseAddress(AieTargetModel targetModel); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetMemEastBaseAddress(AieTargetModel targetModel); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetMemWestBaseAddress(AieTargetModel targetModel); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetLocalMemorySize(AieTargetModel targetModel); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetNumLocks(AieTargetModel targetModel, int col, int row); + +MLIR_CAPI_EXPORTED uint32_t aieTargetModelGetNumBDs(AieTargetModel targetModel, + int col, int row); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetNumMemTileRows(AieTargetModel targetModel); + +MLIR_CAPI_EXPORTED uint32_t +aieTargetModelGetMemTileSize(AieTargetModel targetModel); + +/// Returns true if this is an NPU target model. +MLIR_CAPI_EXPORTED bool aieTargetModelIsNPU(AieTargetModel targetModel); + +#ifdef __cplusplus +} +#endif + +#endif // AIE_C_TARGETMODEL_H diff --git a/include/aie/Dialect/AIE/IR/AIEDialect.h b/include/aie/Dialect/AIE/IR/AIEDialect.h index 77d1ecd9f5..62e94a0a29 100644 --- a/include/aie/Dialect/AIE/IR/AIEDialect.h +++ b/include/aie/Dialect/AIE/IR/AIEDialect.h @@ -234,6 +234,7 @@ typedef struct DMAChannel { } DMAChannel; const AIETargetModel &getTargetModel(mlir::Operation *op); +const AIETargetModel &getTargetModel(AIEDevice device); mlir::ParseResult parseObjectFifoProducerTile(mlir::OpAsmParser &parser, diff --git a/include/aie/Dialect/AIE/IR/AIETargetModel.h b/include/aie/Dialect/AIE/IR/AIETargetModel.h index 141fe22a60..c61622d27e 100644 --- a/include/aie/Dialect/AIE/IR/AIETargetModel.h +++ b/include/aie/Dialect/AIE/IR/AIETargetModel.h @@ -54,7 +54,7 @@ using TileID = struct TileID { class AIETargetModel { public: - AIETargetModel() = default; + AIETargetModel(AIEDevice device) : device(device) {} virtual ~AIETargetModel(); @@ -204,11 +204,17 @@ class AIETargetModel { // Return true if this is an NPU-based device // There are several special cases for handling the NPU at the moment. virtual bool isNPU() const { return false; } + + // Return the AIEDevice for this target model + AIEDevice getDevice() const { return device; } + +private: + AIEDevice device; }; class AIE1TargetModel : public AIETargetModel { public: - AIE1TargetModel() = default; + AIE1TargetModel(AIEDevice device) : AIETargetModel(device) {} bool isCoreTile(int col, int row) const override { return row > 0; } bool isMemTile(int col, int row) const override { return false; } @@ -272,7 +278,7 @@ class AIE1TargetModel : public AIETargetModel { class AIE2TargetModel : public AIETargetModel { public: - AIE2TargetModel() = default; + AIE2TargetModel(AIEDevice device) : AIETargetModel(device) {} AIEArch getTargetArch() const override; @@ -329,7 +335,7 @@ class VC1902TargetModel : public AIE1TargetModel { 2, 3, 6, 7, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 46, 47}; public: - VC1902TargetModel() = default; + VC1902TargetModel(AIEDevice device) : AIE1TargetModel(device) {} int columns() const override { return 50; } @@ -352,7 +358,7 @@ class VE2302TargetModel : public AIE2TargetModel { llvm::SmallDenseSet nocColumns = {2, 3, 6, 7, 10, 11}; public: - VE2302TargetModel() = default; + VE2302TargetModel(AIEDevice device) : AIE2TargetModel(device) {} int columns() const override { return 17; } @@ -404,7 +410,7 @@ class VE2802TargetModel : public AIE2TargetModel { 22, 23, 30, 31, 34, 35}; public: - VE2802TargetModel() = default; + VE2802TargetModel(AIEDevice device) : AIE2TargetModel(device) {} int columns() const override { return 38; } @@ -456,7 +462,7 @@ class VE2802TargetModel : public AIE2TargetModel { class BaseNPUTargetModel : public AIE2TargetModel { public: - BaseNPUTargetModel() = default; + BaseNPUTargetModel(AIEDevice device) : AIE2TargetModel(device) {} int rows() const override { return 6; /* 1 Shim row, 1 memtile row, and 4 Core rows. */ @@ -488,7 +494,7 @@ class BaseNPUTargetModel : public AIE2TargetModel { // The full Phoenix NPU class NPUTargetModel : public BaseNPUTargetModel { public: - NPUTargetModel() = default; + NPUTargetModel(AIEDevice device) : BaseNPUTargetModel(device) {} int columns() const override { return 5; } @@ -509,7 +515,8 @@ class VirtualizedNPUTargetModel : public BaseNPUTargetModel { int cols; public: - VirtualizedNPUTargetModel(int _cols) : BaseNPUTargetModel(), cols(_cols) {} + VirtualizedNPUTargetModel(AIEDevice device, int _cols) + : BaseNPUTargetModel(device), cols(_cols) {} int columns() const override { return cols; } diff --git a/include/aie/Dialect/XLLVM/IR/XLLVMAIE2IntrOps.td b/include/aie/Dialect/XLLVM/IR/XLLVMAIE2IntrOps.td index 37e8a12ae9..2442a51c1d 100644 --- a/include/aie/Dialect/XLLVM/IR/XLLVMAIE2IntrOps.td +++ b/include/aie/Dialect/XLLVM/IR/XLLVMAIE2IntrOps.td @@ -15,6 +15,7 @@ #define AIE_DIALECT_XLLVM_IR_XLLVMAIE2INTROPS_TD include "aie/Dialect/XLLVM/IR/XLLVM.td" +include "aie/Dialect/XLLVM/IR/XLLVMTypeConstraints.td" include "mlir/Interfaces/InferTypeOpInterface.td" include "mlir/Interfaces/SideEffectInterfaces.td" @@ -338,4 +339,16 @@ def VectorExtractElem32I512IntrOp : I32:$idx, I32:$sign)>; +// ----- MAX ELEMENT ----- + +def VectorMaxLtBf16IntrOp : + AIEVec2_IntrOp<"vmax.ltbf16", + [TypeIs<"res", + LLVM_StructOf<[ + VectorOfLengthAndType<[32], [BF16]>, + I32]> + >], /*numResults=*/2>, + Arguments<(ins VectorOfLengthAndType<[32], [BF16]>:$lhs, + VectorOfLengthAndType<[32], [BF16]>:$rhs)>; + #endif // AIE_DIALECT_XLLVM_IR_XLLVMAIE2INTROPS_TD diff --git a/include/aie/Dialect/XLLVM/IR/XLLVMTypeConstraints.td b/include/aie/Dialect/XLLVM/IR/XLLVMTypeConstraints.td new file mode 100644 index 0000000000..9b5b0973d3 --- /dev/null +++ b/include/aie/Dialect/XLLVM/IR/XLLVMTypeConstraints.td @@ -0,0 +1,46 @@ +//===- XLLVMTypeConstraints.td - XLLVM type constraints. --*- tablegen -*-====// +// +// 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. +// +//===----------------------------------------------------------------------===// +// Defines type constraints for LLVM types used in XLLVM intrinsic op +// definitions. +//===----------------------------------------------------------------------===// + + +#ifndef AIE_DIALECT_XLLVM_IR_XLLVMTYPECONSTRAINTS_TD +#define AIE_DIALECT_XLLVM_IR_XLLVMTYPECONSTRAINTS_TD + +class EnumeratedType { + Type type = ty; + int index = idx; +} + +class EnumerateTypeListFrom tlist, int from = 0> { + list sequence = + !if(!empty(tlist), [], + !listconcat( + [EnumeratedType], + EnumerateTypeListFrom.sequence + )); +} + +class LLVM_StructOf structTypes> : + Type< + And<[LLVM_AnyStruct.predicate, + CPred<"cast<::mlir::LLVM::LLVMStructType>($_self).getBody().size() == " # !size(structTypes)>, + And.sequence, + SubstLeaves<"$_self", + "cast<::mlir::LLVM::LLVMStructType>($_self).getBody()[" # enumTy.index # "]", + enumTy.type.predicate> + ) + > + ]>, + "an LLVM struct of {" # !interleave(!foreach(ty, structTypes, ty.summary), "; ") # "}" + >; + +#endif // AIE_DIALECT_XLLVM_IR_XLLVMTYPECONSTRAINTS_TD diff --git a/lib/CAPI/CMakeLists.txt b/lib/CAPI/CMakeLists.txt index 892957d40c..0d938dddee 100644 --- a/lib/CAPI/CMakeLists.txt +++ b/lib/CAPI/CMakeLists.txt @@ -4,6 +4,7 @@ add_mlir_public_c_api_library(AIECAPI Dialects.cpp Registration.cpp + TargetModel.cpp Translation.cpp LINK_LIBS PUBLIC diff --git a/lib/CAPI/TargetModel.cpp b/lib/CAPI/TargetModel.cpp new file mode 100644 index 0000000000..8a029305e9 --- /dev/null +++ b/lib/CAPI/TargetModel.cpp @@ -0,0 +1,150 @@ +//===- TargetModel.cpp - C API for AIE TargetModel ------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "aie-c/TargetModel.h" + +#include "aie/Dialect/AIE/IR/AIEDialect.h" +#include "aie/Dialect/AIE/IR/AIETargetModel.h" + +using namespace mlir; + +static inline AieTargetModel wrap(const xilinx::AIE::AIETargetModel &tm) { + return AieTargetModel{static_cast(tm.getDevice())}; +} + +static inline const xilinx::AIE::AIETargetModel &unwrap(AieTargetModel tm) { + return xilinx::AIE::getTargetModel(static_cast(tm.d)); +} + +AieTargetModel aieGetTargetModel(uint32_t device) { + return wrap( + xilinx::AIE::getTargetModel(static_cast(device))); +} + +int aieTargetModelColumns(AieTargetModel targetModel) { + return unwrap(targetModel).columns(); +} + +int aieTargetModelRows(AieTargetModel targetModel) { + return unwrap(targetModel).rows(); +} + +bool aieTargetModelIsCoreTile(AieTargetModel targetModel, int col, int row) { + return unwrap(targetModel).isCoreTile(col, row); +} + +bool aieTargetModelIsMemTile(AieTargetModel targetModel, int col, int row) { + return unwrap(targetModel).isMemTile(col, row); +} + +bool aieTargetModelIsShimNOCTile(AieTargetModel targetModel, int col, int row) { + return unwrap(targetModel).isShimNOCTile(col, row); +} + +bool aieTargetModelIsShimPLTile(AieTargetModel targetModel, int col, int row) { + return unwrap(targetModel).isShimPLTile(col, row); +} + +bool aieTargetModelIsShimNOCorPLTile(AieTargetModel targetModel, int col, + int row) { + return unwrap(targetModel).isShimNOCorPLTile(col, row); +} + +bool aieTargetModelIsInternal(AieTargetModel targetModel, int src_col, + int src_row, int dst_col, int dst_row) { + return unwrap(targetModel).isInternal(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsWest(AieTargetModel targetModel, int src_col, int src_row, + int dst_col, int dst_row) { + return unwrap(targetModel).isWest(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsEast(AieTargetModel targetModel, int src_col, int src_row, + int dst_col, int dst_row) { + return unwrap(targetModel).isEast(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsNorth(AieTargetModel targetModel, int src_col, int src_row, + int dst_col, int dst_row) { + return unwrap(targetModel).isNorth(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsSouth(AieTargetModel targetModel, int src_col, int src_row, + int dst_col, int dst_row) { + return unwrap(targetModel).isSouth(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsMemWest(AieTargetModel targetModel, int src_col, + int src_row, int dst_col, int dst_row) { + return unwrap(targetModel).isMemWest(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsMemEast(AieTargetModel targetModel, int src_col, + int src_row, int dst_col, int dst_row) { + return unwrap(targetModel).isMemEast(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsMemNorth(AieTargetModel targetModel, int src_col, + int src_row, int dst_col, int dst_row) { + return unwrap(targetModel).isMemNorth(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsMemSouth(AieTargetModel targetModel, int src_col, + int src_row, int dst_col, int dst_row) { + return unwrap(targetModel).isMemSouth(src_col, src_row, dst_col, dst_row); +} + +bool aieTargetModelIsLegalMemAffinity(AieTargetModel targetModel, int src_col, + int src_row, int dst_col, int dst_row) { + return unwrap(targetModel) + .isLegalMemAffinity(src_col, src_row, dst_col, dst_row); +} + +uint32_t aieTargetModelGetMemSouthBaseAddress(AieTargetModel targetModel) { + return unwrap(targetModel).getMemSouthBaseAddress(); +} + +uint32_t aieTargetModelGetMemNorthBaseAddress(AieTargetModel targetModel) { + return unwrap(targetModel).getMemNorthBaseAddress(); +} + +uint32_t aieTargetModelGetMemEastBaseAddress(AieTargetModel targetModel) { + return unwrap(targetModel).getMemEastBaseAddress(); +} + +uint32_t aieTargetModelGetMemWestBaseAddress(AieTargetModel targetModel) { + return unwrap(targetModel).getMemWestBaseAddress(); +} + +uint32_t aieTargetModelGetLocalMemorySize(AieTargetModel targetModel) { + return unwrap(targetModel).getLocalMemorySize(); +} + +uint32_t aieTargetModelGetNumLocks(AieTargetModel targetModel, int col, + int row) { + return unwrap(targetModel).getNumLocks(col, row); +} + +uint32_t aieTargetModelGetNumBDs(AieTargetModel targetModel, int col, int row) { + return unwrap(targetModel).getNumBDs(col, row); +} + +uint32_t aieTargetModelGetNumMemTileRows(AieTargetModel targetModel) { + return unwrap(targetModel).getNumMemTileRows(); +} + +uint32_t aieTargetModelGetMemTileSize(AieTargetModel targetModel) { + return unwrap(targetModel).getMemTileSize(); +} + +bool aieTargetModelIsNPU(AieTargetModel targetModel) { + return unwrap(targetModel).isNPU(); +} \ No newline at end of file diff --git a/lib/Dialect/AIE/IR/AIEDialect.cpp b/lib/Dialect/AIE/IR/AIEDialect.cpp index 439ef6f20b..82360ab80f 100644 --- a/lib/Dialect/AIE/IR/AIEDialect.cpp +++ b/lib/Dialect/AIE/IR/AIEDialect.cpp @@ -101,14 +101,14 @@ LogicalResult myVerifyOffsetSizeAndStrideOp(OffsetSizeAndStrideOpInterface op) { return success(); } -static VC1902TargetModel VC1902model; -static VE2302TargetModel VE2302model; -static VE2802TargetModel VE2802model; -static NPUTargetModel NPUmodel; -static VirtualizedNPUTargetModel NPUmodel1col(1); -static VirtualizedNPUTargetModel NPUmodel2col(2); -static VirtualizedNPUTargetModel NPUmodel3col(3); -static VirtualizedNPUTargetModel NPUmodel4col(4); +static VC1902TargetModel VC1902model(AIEDevice::xcvc1902); +static VE2302TargetModel VE2302model(AIEDevice::xcve2302); +static VE2802TargetModel VE2802model(AIEDevice::xcve2802); +static NPUTargetModel NPUmodel(AIEDevice::npu1); +static VirtualizedNPUTargetModel NPUmodel1col(AIEDevice::npu1_1col, 1); +static VirtualizedNPUTargetModel NPUmodel2col(AIEDevice::npu1_2col, 2); +static VirtualizedNPUTargetModel NPUmodel3col(AIEDevice::npu1_3col, 3); +static VirtualizedNPUTargetModel NPUmodel4col(AIEDevice::npu1_4col, 4); const AIETargetModel &getTargetModel(Operation *op) { if (auto t = dyn_cast(op)) @@ -121,6 +121,28 @@ const AIETargetModel &getTargetModel(Operation *op) { return VC1902model; } +const AIETargetModel &getTargetModel(AIEDevice device) { + switch (device) { + case AIEDevice::xcvc1902: + return VC1902model; + case AIEDevice::xcve2302: + return VE2302model; + case AIEDevice::xcve2802: + return VE2802model; + case AIEDevice::npu1: + return NPUmodel; + case AIEDevice::npu1_1col: + return NPUmodel1col; + case AIEDevice::npu1_2col: + return NPUmodel2col; + case AIEDevice::npu1_3col: + return NPUmodel3col; + case AIEDevice::npu1_4col: + return NPUmodel4col; + } + return VC1902model; +} + // Walk the operation hierarchy until we find a containing TileElement. // If no parent is a TileElement, then return null. static TileElement getParentTileElement(Operation *op) { @@ -982,25 +1004,7 @@ LogicalResult GetCascadeOp::verify() { //===----------------------------------------------------------------------===// const AIETargetModel &DeviceOp::getTargetModel() { - switch (getDevice()) { - case AIEDevice::xcvc1902: - return VC1902model; - case AIEDevice::xcve2302: - return VE2302model; - case AIEDevice::xcve2802: - return VE2802model; - case AIEDevice::npu1: - return NPUmodel; - case AIEDevice::npu1_1col: - return NPUmodel1col; - case AIEDevice::npu1_2col: - return NPUmodel2col; - case AIEDevice::npu1_3col: - return NPUmodel3col; - case AIEDevice::npu1_4col: - return NPUmodel4col; - } - return VC1902model; + return xilinx::AIE::getTargetModel(getDevice()); } LogicalResult DeviceOp::verify() { return success(); } diff --git a/lib/Dialect/XLLVM/XLLVMOps.cpp b/lib/Dialect/XLLVM/XLLVMOps.cpp index 31356dcb81..5da545bdcb 100644 --- a/lib/Dialect/XLLVM/XLLVMOps.cpp +++ b/lib/Dialect/XLLVM/XLLVMOps.cpp @@ -46,12 +46,16 @@ getNamedIntrinsicDeclaration(llvm::Module *M, llvm::StringRef fullName, llvm::CallInst *createExternalLLVMIntrinsicCall( llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation, Operation *intrOp, llvm::StringRef intrinsicName) { - // We support 0 or 1 results - assert(intrOp->getNumResults() <= 1 && - "external multi-result intrinsics not supported"); llvm::Type *resTy = nullptr; - if (intrOp->getNumResults()) + unsigned numResults = intrOp->getNumResults(); + if (numResults == 1) resTy = moduleTranslation.convertType(*(intrOp->getResultTypes().begin())); + else if (numResults > 1) { + SmallVector resTys; + for (auto ty : intrOp->getResultTypes()) + resTys.push_back(moduleTranslation.convertType(ty)); + resTy = llvm::StructType::get(builder.getContext(), resTys); + } auto operands = moduleTranslation.lookupValues(intrOp->getOperands()); SmallVector types; for (auto op : operands) diff --git a/python/AIEMLIRModule.cpp b/python/AIEMLIRModule.cpp index 63afb38803..0a4d029b86 100644 --- a/python/AIEMLIRModule.cpp +++ b/python/AIEMLIRModule.cpp @@ -7,6 +7,7 @@ #include "aie-c/Dialects.h" #include "aie-c/Registration.h" +#include "aie-c/TargetModel.h" #include "aie-c/Translation.h" #include "mlir-c/IR.h" @@ -27,6 +28,16 @@ using namespace mlir::python::adaptors; namespace py = pybind11; using namespace py::literals; +class PyAieTargetModel { +public: + PyAieTargetModel(AieTargetModel model) : model(model) {} + operator AieTargetModel() const { return model; } + AieTargetModel get() const { return model; } + +private: + AieTargetModel model; +}; + PYBIND11_MODULE(_aie, m) { aieRegisterAllPasses(); @@ -141,4 +152,150 @@ PYBIND11_MODULE(_aie, m) { return stealCStr(aieLLVMLink(modules.data(), modules.size())); }, "modules"_a); + + m.def("get_target_model", + [](uint32_t d) -> PyAieTargetModel { return aieGetTargetModel(d); }); + + py::class_(m, "AIETargetModel", py::module_local()) + .def( + "columns", + [](PyAieTargetModel &self) { + return aieTargetModelColumns(self.get()); + }, + "Get the number of columns in the device.") + .def( + "rows", + [](PyAieTargetModel &self) { return aieTargetModelRows(self.get()); }, + "Get the number of rows in the device.") + .def("is_core_tile", + [](PyAieTargetModel &self, int col, int row) { + return aieTargetModelIsCoreTile(self.get(), col, row); + }) + .def("is_mem_tile", + [](PyAieTargetModel &self, int col, int row) { + return aieTargetModelIsMemTile(self.get(), col, row); + }) + .def("is_shim_noc_tile", + [](PyAieTargetModel &self, int col, int row) { + return aieTargetModelIsShimNOCTile(self.get(), col, row); + }) + .def("is_shim_pl_tile", + [](PyAieTargetModel &self, int col, int row) { + return aieTargetModelIsShimPLTile(self.get(), col, row); + }) + .def("is_shim_noc_or_pl_tile", + [](PyAieTargetModel &self, int col, int row) { + return aieTargetModelIsShimNOCorPLTile(self.get(), col, row); + }) + // .def("is_valid_tile") + // .def("is_valid_trace_master") + // .def("get_mem_west") + // .def("get_mem_east") + // .def("get_mem_north") + // .def("get_mem_south") + .def("is_internal", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsInternal(self.get(), src_col, src_row, + dst_col, dst_row); + }) + .def("is_west", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsWest(self.get(), src_col, src_row, dst_col, + dst_row); + }) + .def("is_east", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsEast(self.get(), src_col, src_row, dst_col, + dst_row); + }) + .def("is_north", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsNorth(self.get(), src_col, src_row, dst_col, + dst_row); + }) + .def("is_south", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsSouth(self.get(), src_col, src_row, dst_col, + dst_row); + }) + .def("is_mem_west", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsMemWest(self.get(), src_col, src_row, + dst_col, dst_row); + }) + .def("is_mem_east", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsMemEast(self.get(), src_col, src_row, + dst_col, dst_row); + }) + .def("is_mem_north", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsMemNorth(self.get(), src_col, src_row, + dst_col, dst_row); + }) + .def("is_mem_south", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsMemSouth(self.get(), src_col, src_row, + dst_col, dst_row); + }) + .def("is_legal_mem_affinity", + [](PyAieTargetModel &self, int src_col, int src_row, int dst_col, + int dst_row) { + return aieTargetModelIsLegalMemAffinity(self.get(), src_col, + src_row, dst_col, dst_row); + }) + //.def("get_mem_internal_base_address") + .def("get_mem_west_base_address", + [](PyAieTargetModel &self) { + return aieTargetModelGetMemWestBaseAddress(self.get()); + }) + .def("get_mem_east_base_address", + [](PyAieTargetModel &self) { + return aieTargetModelGetMemEastBaseAddress(self.get()); + }) + .def("get_mem_north_base_address", + [](PyAieTargetModel &self) { + return aieTargetModelGetMemNorthBaseAddress(self.get()); + }) + .def("get_mem_south_base_address", + [](PyAieTargetModel &self) { + return aieTargetModelGetMemSouthBaseAddress(self.get()); + }) + .def("get_local_memory_size", + [](PyAieTargetModel &self) { + return aieTargetModelGetLocalMemorySize(self.get()); + }) + .def("get_num_locks", + [](PyAieTargetModel &self, int col, int row) { + return aieTargetModelGetNumLocks(self.get(), col, row); + }) + .def("get_num_bds", + [](PyAieTargetModel &self, int col, int row) { + return aieTargetModelGetNumBDs(self.get(), col, row); + }) + .def("get_num_mem_tile_rows", + [](PyAieTargetModel &self) { + return aieTargetModelGetNumMemTileRows(self.get()); + }) + .def("get_mem_tile_size", + [](PyAieTargetModel &self) { + return aieTargetModelGetMemTileSize(self.get()); + }) + // .def("get_num_dest_switchbox_connections", int col, int row) + // .def("get_num_source_switchbox_connections", int col, int row) + // .def("get_num_dest_shim_mux_connections", int col, int row) + // .def("get_num_source_shim_mux_connections", int col, int row) + // .def("is_legal_memtile_connection") + .def("is_npu", [](PyAieTargetModel &self) { + return aieTargetModelIsNPU(self.get()); + }); } diff --git a/python/dialects/aie.py b/python/dialects/aie.py index 84c3f8595d..cd02b3381e 100644 --- a/python/dialects/aie.py +++ b/python/dialects/aie.py @@ -17,6 +17,7 @@ from .._mlir_libs._aie import ( ObjectFifoSubviewType, ObjectFifoType, + get_target_model, aie_llvm_link, generate_bcf, generate_cdo, diff --git a/test/Target/LLVMIR/aievec.mlir b/test/Target/LLVMIR/aievec.mlir index fbea27805b..ddcea0a721 100644 --- a/test/Target/LLVMIR/aievec.mlir +++ b/test/Target/LLVMIR/aievec.mlir @@ -1,6 +1,6 @@ -// RUN: aie-translate %s -mlir-to-llvmir | FileCheck %s +// RUN: aie-translate %s -mlir-to-llvmir -split-input-file | FileCheck %s -// ----- MAC ----- +// -- MAC -- // CHECK-LABEL: define <16 x i64> @mac_conf_acc32 llvm.func @mac_conf_acc32(%A : vector<64xi8>, @@ -30,7 +30,7 @@ llvm.func @mac_conf_bf16(%A : vector<32xbf16>, llvm.return %0 : vector<8xi64> } -// ----- MSC ----- +// -- MSC -- // CHECK-LABEL: define <8 x i64> @msc_conf_bf16 llvm.func @msc_conf_bf16(%A : vector<32xbf16>, @@ -46,7 +46,7 @@ llvm.func @msc_conf_bf16(%A : vector<32xbf16>, llvm.return %0 : vector<8xi64> } -// ----- MUL ----- +// -- MUL -- // CHECK-LABEL: define <16 x i64> @mul_conf_acc32 llvm.func @mul_conf_acc32(%A : vector<64xi8>, @@ -87,7 +87,7 @@ llvm.func @mul_conf_bf16(%A : vector<32xbf16>, llvm.return %0 : vector<8xi64> } -// ----- SET ----- +// -- SET -- // CHECK-LABEL: define <16 x i32> @vector_set_128b_into_512b llvm.func @vector_set_128b_into_512b(%v : vector<4xi32>) -> vector<16xi32> { @@ -105,7 +105,7 @@ llvm.func @vector_set_256b_into_512b(%v : vector<8xi32>) -> vector<16xi32> { llvm.return %1 : vector<16xi32> } -// ----- SRS ----- +// -- SRS -- // CHECK-LABEL: define <16 x i16> @srs_256b_v16_acc32 llvm.func @srs_256b_v16_acc32(%v : vector<8xi64>, %shft : i32, %sign : i32) -> vector<16xi16> { @@ -169,7 +169,7 @@ llvm.func @srs_256b_v16_accfloat(%v : vector<8xi64>) -> vector<16xbf16> { llvm.return %0 : vector<16xbf16> } -// ----- BROADCAST ----- +// -- BROADCAST -- // CHECK-LABEL: define <64 x i8> @vbroadcast8_i512 llvm.func @vbroadcast8_i512(%val : i32) -> vector<64xi8> { @@ -211,7 +211,7 @@ llvm.func @vbroadcastfloat_i512(%val : f32) -> vector<16xf32> { llvm.return %0 : vector<16xf32> } -// ----- EXT ----- +// -- EXT -- // CHECK-LABEL: define <8 x i32> @ext_i256_i512 llvm.func @ext_i256_i512(%v : vector<16xi32>, %idx : i32) -> vector<8xi32> { @@ -249,7 +249,7 @@ llvm.func @ext_i128_i512(%v : vector<16xi32>) -> vector<4xi32> { llvm.return %1 : vector<4xi32> } -// ----- CONCAT ----- +// -- CONCAT -- // CHECK-LABEL: define <16 x i32> @concat_i512_i256 llvm.func @concat_i512_i256(%a : vector<8xi32>, %b : vector<8xi32>) -> vector<16xi32> { @@ -280,7 +280,7 @@ llvm.func @concat_i1024_i512(%a : vector<16xi32>, %b : vector<16xi32>) -> vector llvm.return %0 : vector<32xi32> } -// ----- SHUFFLE ----- +// -- SHUFFLE -- // CHECK-LABEL: define <16 x i32> @shuffle_i512 llvm.func @shuffle_i512(%a : vector<16xi32>, %b : vector<16xi32>, %mode : i32) -> vector<16xi32> { @@ -291,7 +291,7 @@ llvm.func @shuffle_i512(%a : vector<16xi32>, %b : vector<16xi32>, %mode : i32) - llvm.return %0 : vector<16xi32> } -// ----- UNDEF ----- +// -- UNDEF -- // CHECK-LABEL: define <16 x i32> @undef_v16i32 llvm.func @undef_v16i32() -> vector<16xi32> { @@ -300,7 +300,7 @@ llvm.func @undef_v16i32() -> vector<16xi32> { llvm.return %0 : vector<16xi32> } -// ----- UPD ----- +// -- UPD -- // CHECK-LABEL: define <32 x bfloat> @upd_bf512_bf256 llvm.func @upd_bf512_bf256(%a : vector<32xbf16>, %b : vector<16xbf16>, %idx : i32) -> vector<32xbf16> { @@ -310,7 +310,7 @@ llvm.func @upd_bf512_bf256(%a : vector<32xbf16>, %b : vector<16xbf16>, %idx : i3 llvm.return %0 : vector<32xbf16> } -// ----- SHIFT ----- +// -- SHIFT -- // CHECK-LABEL: define <16 x i32> @vshift_i512_i512 llvm.func @vshift_i512_i512(%a : vector<16xi32>, %b : vector<16xi32>, %step : i32, %shift : i32) -> vector<16xi32> { @@ -330,7 +330,7 @@ llvm.func @vshift_bf512_bf512(%a : vector<32xbf16>, %b : vector<32xbf16>, %step llvm.return %0 : vector<32xbf16> } -// ----- EXTRACT ELEMENT ----- +// -- EXTRACT ELEMENT -- // CHECK-LABEL: define i32 @vextract_elem8_i512 llvm.func @vextract_elem8_i512(%a : vector<64xi8>, %idx : i32, %sign : i32) -> i32 { @@ -356,7 +356,7 @@ llvm.func @vextract_elem32_i512(%a : vector<16xi32>, %idx : i32, %sign : i32) -> llvm.return %0 : i32 } -// ----- UPS ----- +// -- UPS -- // CHECK-LABEL: define <8 x i64> @acc32_v16_i256_ups llvm.func @acc32_v16_i256_ups(%v : vector<16xi16>, %shift : i32, %sign : i32) -> vector<8xi64> { @@ -419,3 +419,17 @@ llvm.func @accfloat_v16_256b_ups(%v : vector<16xbf16>) -> vector<8xi64> { %0 = "xllvm.intr.aie2.v16bf16.to.v16accfloat"(%v) : (vector<16xbf16>) -> vector<8xi64> llvm.return %0 : vector<8xi64> } + +// ----- + +// CHECK-LABEL: <32 x bfloat> @vmax_ltbf16 +llvm.func @vmax_ltbf16(%lhs: vector<32xbf16>, %rhs: vector<32xbf16>) -> vector<32xbf16> { + // CHECK: call { <32 x bfloat>, i32 } @llvm.aie2.vmax.ltbf16( + // CHECK-SAME: <32 x bfloat> %{{[0-9]+}}, <32 x bfloat> %{{[0-9]+}}) + %0 = "xllvm.intr.aie2.vmax.ltbf16"(%lhs, %rhs) : + (vector<32xbf16>, vector<32xbf16>) -> !llvm.struct<(vector<32xbf16>, i32)> + %1 = llvm.extractvalue %0[0] : !llvm.struct<(vector<32xbf16>, i32)> + llvm.return %1 : vector<32xbf16> +} + +// CHECK-LABEL: declare { <32 x bfloat>, i32 } @llvm.aie2.vmax.ltbf16(<32 x bfloat>, <32 x bfloat>) diff --git a/test/dialect/XLLVM/invalid.mlir b/test/dialect/XLLVM/invalid.mlir new file mode 100644 index 0000000000..7a146148f1 --- /dev/null +++ b/test/dialect/XLLVM/invalid.mlir @@ -0,0 +1,10 @@ +// RUN: aie-opt %s -split-input-file -verify-diagnostics + +func.func @invalidStructType(%A : vector<32xbf16>, %B : vector<32xbf16>) + -> vector<16xbf16> { + // expected-error @+1 {{'res' is an LLVM struct of {vector of bfloat16 type values of length 32; 32-bit signless integer}} + %rs = "xllvm.intr.aie2.vmax.ltbf16"(%A, %B) : + (vector<32xbf16>, vector<32xbf16>) -> !llvm.struct<(vector<16xbf16>, i32)> + %rv = llvm.extractvalue %rs[0] : !llvm.struct<(vector<16xbf16>, i32)> + return %rv : vector<16xbf16> +} \ No newline at end of file diff --git a/test/python/aie_ops.py b/test/python/aie_ops.py index 6c68e9f7c6..fcd021aea9 100644 --- a/test/python/aie_ops.py +++ b/test/python/aie_ops.py @@ -24,6 +24,7 @@ cascade_flow, WireBundle, packetflow, + get_target_model, ) from aie.ir import InsertionPoint, Block, TypeAttr from aie.extras.context import mlir_mod_ctx @@ -268,3 +269,25 @@ def test_module_context(): test_module_context() + + +# CHECK-LABEL: test_target_model +# CHECK: xcvc1902 rows 9 +# CHECK: xcvc1902 cols 50 +# CHECK: xcvc1902 npu False +# CHECK: npu1 rows 6 +# CHECK: npu1 cols 5 +# CHECK: npu1 npu True +# CHECK: npu1_1col rows 6 +# CHECK: npu1_1col cols 1 +# CHECK: npu1_1col npu True +def test_target_model(): + print("test_target_model") + for d in AIEDevice: + tm = get_target_model(d) + print(f"{d} rows {tm.rows()}") + print(f"{d} cols {tm.columns()}") + print(f"{d} npu {tm.is_npu()}") + + +test_target_model()