diff --git a/include/NeuraDialect/Architecture/Architecture.h b/include/NeuraDialect/Architecture/Architecture.h index 2d560e75..5002bbfd 100644 --- a/include/NeuraDialect/Architecture/Architecture.h +++ b/include/NeuraDialect/Architecture/Architecture.h @@ -1,12 +1,14 @@ #ifndef NEURA_ARCHITECTURE_H #define NEURA_ARCHITECTURE_H +#include +#include +#include +#include #include -#include #include #include -#include -#include +#include namespace mlir { namespace neura { @@ -15,6 +17,25 @@ namespace neura { enum class ResourceKind { Tile, Link, + FunctionUnit, + Register, + RegisterFile, + RegisterFileCluster, +}; + +// Enum for function unit resource type. +enum class FunctionUnitKind { + FixedPointAdder, + FixedPointMultiplier, + CustomizableFunctionUnit, +}; + +// Enum for supported operation types. +enum OperationKind { + IAdd = 0, + IMul = 1, + FAdd = 2, + FMul = 3 }; //===----------------------------------------------------------------------===// @@ -31,7 +52,81 @@ class BasicResource { //===----------------------------------------------------------------------===// // Forward declaration for use in Tile +class Tile; class Link; +class FunctionUnit; +class Register; +class RegisterFile; +class RegisterFileCluster; + +//===----------------------------------------------------------------------===// +// Function Unit. +//===----------------------------------------------------------------------===// + +class FunctionUnit : public BasicResource { +public: + FunctionUnit(int id); + + int getId() const override; + std::string getType() const override { return "function_unit"; } + ResourceKind getKind() const override { return ResourceKind::FunctionUnit; } + + static bool classof(const BasicResource *res) { + return res && res->getKind() == ResourceKind::FunctionUnit; + } + + Tile* getTile() const; + + void setTile(Tile* tile); + + std::set getSupportedOperations() const { + return supported_operations; + } + + bool canSupportOperation(OperationKind operation) const { + for (const auto &op : supported_operations) { + if (op == operation) { + return true; + } + } + return false; + } + +protected: + std::set supported_operations; + +private: + int id; + Tile* tile; +}; + +class FixedPointAdder : public FunctionUnit { +public: + FixedPointAdder(int id) : FunctionUnit(id) { + supported_operations.insert(OperationKind::IAdd); + } + std::string getType() const override { return "fixed_point_adder"; } + ResourceKind getKind() const override { return ResourceKind::FunctionUnit; } +}; + +class FixedPointMultiplier : public FunctionUnit { +public: + FixedPointMultiplier(int id) : FunctionUnit(id) { + supported_operations.insert(OperationKind::IMul); + } + std::string getType() const override { return "fixed_point_multiplier"; } + ResourceKind getKind() const override { return ResourceKind::FunctionUnit; } +}; + +class CustomizableFunctionUnit : public FunctionUnit { +public: + CustomizableFunctionUnit(int id) : FunctionUnit(id) {} + std::string getType() const override { return "customizable_function_unit"; } + ResourceKind getKind() const override { return ResourceKind::FunctionUnit; } + void addSupportedOperation(OperationKind operation_kind) { + supported_operations.insert(operation_kind); + } +}; //===----------------------------------------------------------------------===// // Tile @@ -59,6 +154,24 @@ class Tile : public BasicResource { const std::set& getOutLinks() const; const std::set& getInLinks() const; + void addFunctionUnit(std::unique_ptr func_unit) { + assert(func_unit && "Cannot add null function unit"); + func_unit->setTile(this); + functional_unit_storage.push_back(std::move(func_unit)); + functional_units.insert(functional_unit_storage.back().get()); + } + + bool canSupportOperation(OperationKind operation) const { + for (FunctionUnit *fu : functional_units) { + if (fu->canSupportOperation(operation)) { + return true; + } + } + // TODO: Check if the tile can support the operation based on its capabilities. + // @Jackcuii, https://github.com/coredac/dataflow/issues/82. + return true; + } + private: int id; int x, y; @@ -66,6 +179,8 @@ class Tile : public BasicResource { std::set dst_tiles; std::set in_links; std::set out_links; + std::vector> functional_unit_storage; // Owns FUs. + std::set functional_units; // Non-owning, for fast lookup. }; //===----------------------------------------------------------------------===// @@ -96,6 +211,99 @@ class Link : public BasicResource { Tile* dst_tile; }; +//===----------------------------------------------------------------------===// +// Register +//===----------------------------------------------------------------------===// + +class Register : public BasicResource { +public: + Register(int id); + + int getId() const override; + + std::string getType() const override { return "register"; } + + ResourceKind getKind() const override { return ResourceKind::Register; } + + static bool classof(const BasicResource *res) { + return res && res->getKind() == ResourceKind::Register; + } + + Tile* getTile() const; + + void setRegisterFile(RegisterFile* register_file); + + RegisterFile* getRegisterFile() const; + +private: + int id; + RegisterFile* register_file; +}; + +//===----------------------------------------------------------------------===// +// Register File +//===----------------------------------------------------------------------===// + +class RegisterFile : public BasicResource { +public: + RegisterFile(int id); + + int getId() const override; + + std::string getType() const override { return "register_file"; } + + ResourceKind getKind() const override { return ResourceKind::RegisterFile; } + + static bool classof(const BasicResource *res) { + return res && res->getKind() == ResourceKind::RegisterFile; + } + + Tile* getTile() const; + + void setRegisterFileCluster(RegisterFileCluster* register_file_cluster); + + void addRegister(Register* reg); + + const std::map& getRegisters() const; + RegisterFileCluster* getRegisterFileCluster() const; + +private: + int id; + std::map registers; + RegisterFileCluster* register_file_cluster = nullptr; +}; + +//===----------------------------------------------------------------------===// +// Register File Cluster +//===----------------------------------------------------------------------===// + +class RegisterFileCluster : public BasicResource { +public: + RegisterFileCluster(int id); + int getId() const override; + + std::string getType() const override { return "register_file_cluster"; } + + ResourceKind getKind() const override { return ResourceKind::RegisterFileCluster; } + + static bool classof(const BasicResource *res) { + return res && res->getKind() == ResourceKind::RegisterFileCluster; + } + + Tile* getTile() const; + void setTile(Tile* tile); + + void addRegisterFile(RegisterFile* register_file); + const std::map& getRegisterFiles() const; + +private: + int id; + Tile* tile; + std::map register_files; +}; + +//===----------------------------------------------------------------------===// + struct PairHash { std::size_t operator()(const std::pair &coord) const { return std::hash()(coord.first) ^ (std::hash()(coord.second) << 1); diff --git a/lib/NeuraDialect/Architecture/Architecture.cpp b/lib/NeuraDialect/Architecture/Architecture.cpp index f502b1b5..b0138167 100644 --- a/lib/NeuraDialect/Architecture/Architecture.cpp +++ b/lib/NeuraDialect/Architecture/Architecture.cpp @@ -6,10 +6,18 @@ using namespace mlir; using namespace mlir::neura; +//===----------------------------------------------------------------------===// +// Tile +//===----------------------------------------------------------------------===// + Tile::Tile(int id, int x, int y) { this->id = id; this->x = x; this->y = y; + + // TODO: Add function units based on architecture specs. + // @Jackcuii, https://github.com/coredac/dataflow/issues/82. + addFunctionUnit(std::make_unique(0)); } int Tile::getId() const { return id; } @@ -34,6 +42,10 @@ const std::set &Tile::getOutLinks() const { return out_links; } const std::set &Tile::getInLinks() const { return in_links; } +//===----------------------------------------------------------------------===// +// Link +//===----------------------------------------------------------------------===// + Link::Link(int id) { this->id = id; } int Link::getId() const { return id; } @@ -49,6 +61,95 @@ void Link::connect(Tile *src, Tile *dst) { src->linkDstTile(this, dst); } +//===----------------------------------------------------------------------===// +// FunctionUnit +//===----------------------------------------------------------------------===// + +FunctionUnit::FunctionUnit(int id) { this->id = id; } + +int FunctionUnit::getId() const { return id; } + +void FunctionUnit::setTile(Tile* tile) { + this->tile = tile; +} + +Tile *FunctionUnit::getTile() const { + return this->tile; +} + +//===----------------------------------------------------------------------===// +// Register +//===----------------------------------------------------------------------===// + +Tile *Register::getTile() const { + return this->register_file ? register_file->getTile() : nullptr; +} + +Register::Register(int id) { this->id = id; } + +int Register::getId() const { return id; } + +void Register::setRegisterFile(RegisterFile* register_file) { + this->register_file = register_file; +} + +//===----------------------------------------------------------------------===// +// Register File +//===----------------------------------------------------------------------===// + +RegisterFile::RegisterFile(int id) { this->id = id; } + +int RegisterFile::getId() const { return id; } + +Tile *RegisterFile::getTile() const { + return this->register_file_cluster ? register_file_cluster->getTile() : nullptr; +} + +void RegisterFile::setRegisterFileCluster(RegisterFileCluster* register_file_cluster) { + this->register_file_cluster = register_file_cluster; +} + +void RegisterFile::addRegister(Register* reg) { + registers[reg->getId()] = reg; + reg->setRegisterFile(this); +} + +const std::map& RegisterFile::getRegisters() const { + return this->registers; +} +//===----------------------------------------------------------------------===// +// Register File Cluster +//===----------------------------------------------------------------------===// + +RegisterFileCluster* RegisterFile::getRegisterFileCluster() const { + return this->register_file_cluster; +} + +RegisterFileCluster::RegisterFileCluster(int id) { this->id = id; } + +int RegisterFileCluster::getId() const { return id; } + +void RegisterFileCluster::setTile(Tile* tile) { + this->tile = tile; +} + +Tile *RegisterFileCluster::getTile() const { + return this->tile; +} + +void RegisterFileCluster::addRegisterFile(RegisterFile* register_file) { + register_files[register_file->getId()] = register_file; + register_file->setRegisterFileCluster(this); +} + +const std::map& RegisterFileCluster::getRegisterFiles() const { + return this->register_files; +} + +//===----------------------------------------------------------------------===// +// Architecture +//===----------------------------------------------------------------------===// + Architecture::Architecture(int width, int height) { const int num_tiles = width * height; diff --git a/lib/NeuraDialect/Mapping/mapping_util.cpp b/lib/NeuraDialect/Mapping/mapping_util.cpp index a69d7a07..816d3fd5 100644 --- a/lib/NeuraDialect/Mapping/mapping_util.cpp +++ b/lib/NeuraDialect/Mapping/mapping_util.cpp @@ -15,6 +15,16 @@ using namespace mlir::neura; namespace { +inline OperationKind getOperationKindFromMlirOp(Operation *op) { + if (isa(op)) return IAdd; + if (isa(op)) return IMul; + if (isa(op)) return FAdd; + if (isa(op)) return FMul; + // TODO: Complete the list here. + // @Jackcuii, https://github.com/coredac/dataflow/issues/82. + return IAdd; +} + // Traverses (backward) the operation graph starting from the given operation // towards reserve_value. void traverseAlongPath(Operation *op, Value reserve_value, @@ -530,6 +540,19 @@ void mlir::neura::updateAward(std::map &locs_with_award, std::vector mlir::neura::calculateAward(Operation *op, const Architecture &architecture, const MappingState &mapping_state) { + // Early exit if the operation is not supported by all the tiles. + bool op_can_be_supported = false; + for (Tile *tile : architecture.getAllTiles()) { + if (tile->canSupportOperation(getOperationKindFromMlirOp(op))) { + op_can_be_supported = true; + } + } + if (!op_can_be_supported) { + llvm::errs() << "[calculateAward] Operation: " << *op + << " is not supported by any tile.\n"; + return {}; + } + // A heap of locations with their associated award. Note that we use a // max-heap to prioritize locations with higher awards. std::map locs_with_award; @@ -549,6 +572,11 @@ mlir::neura::calculateAward(Operation *op, const Architecture &architecture, llvm::errs() << "[calculateAward] Operation: " << *op << "; Producers: " << producers.size() << "\n"; for (Tile *tile : architecture.getAllTiles()) { + if (!tile->canSupportOperation(getOperationKindFromMlirOp(op))) { + llvm::errs() << "[calculateAward] Tile: " << tile->getType() + << " does not support operation: " << *op << "\n"; + continue; // Skip tiles that cannot support the operation. + } int earliest_start_time_step = 0; for (Operation *producer : producers) { std::vector producer_locs =