diff --git a/include/NeuraDialect/Architecture/Architecture.h b/include/NeuraDialect/Architecture/Architecture.h index 5002bbfd..dfd81237 100644 --- a/include/NeuraDialect/Architecture/Architecture.h +++ b/include/NeuraDialect/Architecture/Architecture.h @@ -172,6 +172,14 @@ class Tile : public BasicResource { return true; } + void addRegisterFileCluster(RegisterFileCluster* register_file_cluster); + + const RegisterFileCluster *getRegisterFileCluster() const; + + const std::vector getRegisterFiles() const; + + const std::vector getRegisters() const; + private: int id; int x, y; @@ -181,6 +189,7 @@ class Tile : public BasicResource { std::set out_links; std::vector> functional_unit_storage; // Owns FUs. std::set functional_units; // Non-owning, for fast lookup. + RegisterFileCluster *register_file_cluster = nullptr; }; //===----------------------------------------------------------------------===// diff --git a/include/NeuraDialect/Mapping/HeuristicMapping/HeuristicMapping.h b/include/NeuraDialect/Mapping/HeuristicMapping/HeuristicMapping.h index 87facfaa..494352fe 100644 --- a/include/NeuraDialect/Mapping/HeuristicMapping/HeuristicMapping.h +++ b/include/NeuraDialect/Mapping/HeuristicMapping/HeuristicMapping.h @@ -13,14 +13,20 @@ class HeuristicMapping : public MappingStrategy { public: HeuristicMapping(int max_location_to_try = 5, int max_backtrack_depth = 3) : max_location_to_try(max_location_to_try), max_backtrack_depth(3) {} + bool map(std::vector &sorted_ops, const Architecture &architecture, MappingState &mapping_state) override; + std::string getName() const override { - if (max_backtrack_depth == 1 && max_location_to_try == INT_MAX) { + if (max_location_to_try == 1 && + max_backtrack_depth == 1) { + return "simple"; + } else if (max_location_to_try == INT_MAX && + max_backtrack_depth == 1) { return "greedy"; - } else if (max_backtrack_depth == INT_MAX && - max_location_to_try == INT_MAX) { + } else if (max_location_to_try == INT_MAX && + max_backtrack_depth == INT_MAX) { return "exhaustive"; } else { return "heuristic"; diff --git a/include/NeuraDialect/Mapping/MappingState.h b/include/NeuraDialect/Mapping/MappingState.h index 1530a4d6..dc439770 100644 --- a/include/NeuraDialect/Mapping/MappingState.h +++ b/include/NeuraDialect/Mapping/MappingState.h @@ -18,13 +18,19 @@ struct MappingLoc { int time_step; bool operator==(const MappingLoc &other) const { - return resource == other.resource && time_step == other.time_step; + return resource->getKind() == other.resource->getKind() && + resource->getId() == other.resource->getId() && + time_step == other.time_step; } bool operator<(const MappingLoc &other) const { - if (time_step != other.time_step) - return time_step < other.time_step; - return resource->getId() < other.resource->getId(); + if (resource->getKind() != other.resource->getKind()) { + return resource->getKind() < other.resource->getKind(); + } + if (resource->getId() != other.resource->getId()) { + return resource->getId() < other.resource->getId(); + } + return time_step < other.time_step; } }; @@ -34,9 +40,10 @@ struct MappingLoc { namespace std { template <> struct hash { std::size_t operator()(const mlir::neura::MappingLoc &loc) const { - std::size_t h1 = std::hash()(loc.resource); - std::size_t h2 = std::hash()(loc.time_step); - return h1 ^ (h2 << 1); + std::size_t h1 = std::hash()(static_cast(loc.resource->getKind())); + std::size_t h2 = std::hash()(loc.resource->getId()); + std::size_t h3 = std::hash()(loc.time_step); + return h1 ^ (h2 << 1) ^ (h3 << 2); } }; } // namespace std @@ -61,15 +68,21 @@ class MappingState { // it will check (tile 2, step 1), (tile 2, step 5), (tile 2, step 9), etc. bool isAvailableAcrossTime(const MappingLoc &loc) const; + // Checks if a hardware resource is available across a time range. + // This function leverages the isAvailableAcrossTime function in each + // time step. + bool isAvailableAcrossTimeInRange(BasicResource *resource, + int start_time, + int exclusive_end_time) const; + // Gets the operation at a specific (tile/link, time_step) location. std::optional getOpAt(MappingLoc loc) const; + std::optional getOpAtLocAcrossTime(MappingLoc loc) const; + // Counts the number of operations at a specific resource across time steps. int countOpsAtResource(BasicResource *resource) const; - // Gets all MRRG nodes. - const std::set &getAllLocs() const; - // Gets all MRRG nodes allocated to a given op. const std::vector &getAllLocsOfOp(Operation *op) const; @@ -126,7 +139,6 @@ class MappingState { int II; static constexpr int kMaxSteps = 10; - std::set all_locs; std::set occupied_locs; std::map loc_to_op; std::map> op_to_locs; diff --git a/include/NeuraDialect/Mapping/mapping_util.h b/include/NeuraDialect/Mapping/mapping_util.h index 1864dd5e..ad997a61 100644 --- a/include/NeuraDialect/Mapping/mapping_util.h +++ b/include/NeuraDialect/Mapping/mapping_util.h @@ -84,5 +84,13 @@ bool canReachLocInTime(const std::vector &producers, int deadline_step, const MappingState &mapping_state); +// Gets an available register (for the given time range) in the given tile. +// The end_time is exclusive, meaning the register should be available +// until end_time - 1. Returns nullptr if no available register found. +Register *getAvailableRegister(const MappingState &mapping_state, + Tile *tile, + int start_time, + int exclusive_end_time); + } // namespace neura } // namespace mlir diff --git a/lib/NeuraDialect/Architecture/Architecture.cpp b/lib/NeuraDialect/Architecture/Architecture.cpp index b0138167..0c08d9a8 100644 --- a/lib/NeuraDialect/Architecture/Architecture.cpp +++ b/lib/NeuraDialect/Architecture/Architecture.cpp @@ -42,6 +42,41 @@ const std::set &Tile::getOutLinks() const { return out_links; } const std::set &Tile::getInLinks() const { return in_links; } +void Tile::addRegisterFileCluster(RegisterFileCluster* register_file_cluster) { + assert(register_file_cluster && "Cannot add null register file cluster"); + if (this->register_file_cluster != nullptr) { + llvm::errs() << "Warning: Overwriting existing register file cluster (" + << this->register_file_cluster->getId() << ") in Tile " + << this->id << "\n"; + } + assert(this->register_file_cluster == nullptr && + "Register file cluster already exists"); + this->register_file_cluster = register_file_cluster; + register_file_cluster->setTile(this); +} + +const RegisterFileCluster* Tile::getRegisterFileCluster() const { + return register_file_cluster; +} + +const std::vector Tile::getRegisterFiles() const { + std::vector all_register_files; + for (const auto& [id, file] : this->register_file_cluster->getRegisterFiles()) { + all_register_files.push_back(file); + } + return all_register_files; +} + +const std::vector Tile::getRegisters() const { + std::vector all_registers; + for (const auto& [reg_file_id, reg_file] : this->register_file_cluster->getRegisterFiles()) { + for (const auto& [reg_id, reg] : reg_file->getRegisters()) { + all_registers.push_back(reg); + } + } + return all_registers; +} + //===----------------------------------------------------------------------===// // Link //===----------------------------------------------------------------------===// @@ -81,18 +116,22 @@ Tile *FunctionUnit::getTile() const { // 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; } +Tile *Register::getTile() const { + return this->register_file ? register_file->getTile() : nullptr; +} + void Register::setRegisterFile(RegisterFile* register_file) { this->register_file = register_file; } +RegisterFile *Register::getRegisterFile() const { + return this->register_file; +} + //===----------------------------------------------------------------------===// // Register File //===----------------------------------------------------------------------===// @@ -117,14 +156,15 @@ void RegisterFile::addRegister(Register* reg) { const std::map& RegisterFile::getRegisters() const { return this->registers; } -//===----------------------------------------------------------------------===// -// Register File Cluster -//===----------------------------------------------------------------------===// RegisterFileCluster* RegisterFile::getRegisterFileCluster() const { return this->register_file_cluster; } +//===----------------------------------------------------------------------===// +// Register File Cluster +//===----------------------------------------------------------------------===// + RegisterFileCluster::RegisterFileCluster(int id) { this->id = id; } int RegisterFileCluster::getId() const { return id; } @@ -153,24 +193,64 @@ const std::map& RegisterFileCluster::getRegisterFiles() cons Architecture::Architecture(int width, int height) { const int num_tiles = width * height; + // Initializes tiles. tile_storage.reserve(num_tiles); - - for (int i = 0; i < width; ++i) { - for (int j = 0; j < height; ++j) { - const int id = i * width + j; - auto tile = std::make_unique(id, i, j); + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + const int id = y * width + x; + // const int id = x * width + y; + auto tile = std::make_unique(id, x, y); id_to_tile[id] = tile.get(); - coord_to_tile[{i, j}] = tile.get(); + coord_to_tile[{x, y}] = tile.get(); tile_storage.push_back(std::move(tile)); } } + // Initializes register file cluster for each tile. + int reg_id = 0; + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + // Gets the tile by coordinates. + Tile *tile = getTile(x, y); + + // Creates registers as a register file. + // FIXME: We have to assign different IDs due to the hash function + // cannot distinguish between different register files.. + Register *register_0 = new Register(reg_id++); + Register *register_1 = new Register(reg_id++); + RegisterFile *register_file_0 = new RegisterFile(0); + register_file_0->addRegister(register_0); + register_file_0->addRegister(register_1); + + // Creates registers as a register file. + Register *register_2 = new Register(reg_id++); + Register *register_3 = new Register(reg_id++); + RegisterFile *register_file_1 = new RegisterFile(1); + register_file_1->addRegister(register_2); + register_file_1->addRegister(register_3); + + // Assembles register files into a cluster. + RegisterFileCluster *register_file_cluster = new RegisterFileCluster(y * width + x); + register_file_cluster->addRegisterFile(register_file_0); + register_file_cluster->addRegisterFile(register_file_1); + + // Adds register file cluster to the tile. + tile->addRegisterFileCluster(register_file_cluster); + llvm::errs() << "Tile (" << x << ", " << y + << ") added register file cluster with ID: " + << register_file_cluster->getId() << "\n"; + } + } + // TODO: Model topology based on the architecture specs. // https://github.com/coredac/dataflow/issues/52. int link_id = 0; - for (int i = 0; i < width; ++i) { - for (int j = 0; j < height; ++j) { + for (int j = 0; j < height; ++j) { + for (int i = 0; i < width; ++i) { + // Gets the tile by coordinates. Tile *tile = getTile(i, j); + + // Creates links to neighboring tiles. if (i > 0) { auto link_towards_left = std::make_unique(link_id++); link_towards_left->connect(tile, getTile(i - 1, j)); diff --git a/lib/NeuraDialect/Mapping/MappingState.cpp b/lib/NeuraDialect/Mapping/MappingState.cpp index 265f7730..c80f5866 100644 --- a/lib/NeuraDialect/Mapping/MappingState.cpp +++ b/lib/NeuraDialect/Mapping/MappingState.cpp @@ -5,16 +5,7 @@ using namespace mlir; using namespace mlir::neura; -MappingState::MappingState(const Architecture &arch, int II) : II(II) { - // TODO: Use number of operations to determine the max steps for constructing - // MRRG. - for (Tile *tile : arch.getAllTiles()) { - for (int t = 0; t < II * kMaxSteps; ++t) { - MappingLoc loc = {tile, t}; - all_locs.insert(loc); - } - } -} +MappingState::MappingState(const Architecture &arch, int II) : II(II) {} bool MappingState::bindOp(const MappingLoc &loc, Operation *op) { loc_to_op[loc] = op; @@ -40,10 +31,24 @@ void MappingState::unbindOp(Operation *op) { } bool MappingState::isAvailableAcrossTime(const MappingLoc &loc) const { + // Checks the availability across time domain. for (int t = loc.time_step % II; t < II * kMaxSteps; t += II) { - MappingLoc checkLoc = loc; - checkLoc.time_step = t; - if (occupied_locs.find(checkLoc) != occupied_locs.end()) { + MappingLoc check_loc = {loc.resource, t}; + if (occupied_locs.find(check_loc) != occupied_locs.end()) { + return false; + } + } + return true; +} + +bool MappingState::isAvailableAcrossTimeInRange(BasicResource *resource, + int start_time, + int exclusive_end_time) const { + // Checks the availability for each time step across time domain. + for (int t = start_time; t < exclusive_end_time; ++t) { + MappingLoc check_loc = {resource, t}; + // Checks the availability across time domain. + if (!isAvailableAcrossTime(check_loc)) { return false; } } @@ -58,6 +63,17 @@ std::optional MappingState::getOpAt(MappingLoc loc) const { return it->second; } +std::optional MappingState::getOpAtLocAcrossTime(MappingLoc loc) const { + for (int t = loc.time_step % II; t < II * kMaxSteps; t += II) { + MappingLoc check_loc = {loc.resource, t}; + auto it = loc_to_op.find(check_loc); + if (it != loc_to_op.end()) { + return it->second; + } + } + return std::nullopt; +} + int MappingState::countOpsAtResource(BasicResource *resource) const { int count = 0; for (const auto &[loc, op] : loc_to_op) { @@ -68,12 +84,7 @@ int MappingState::countOpsAtResource(BasicResource *resource) const { return count; } -const std::set &MappingState::getAllLocs() const { - return all_locs; -} - -const std::vector & -MappingState::getAllLocsOfOp(Operation *op) const { +const std::vector &MappingState::getAllLocsOfOp(Operation *op) const { auto it = op_to_locs.find(op); if (it != op_to_locs.end()) { return it->second; @@ -119,8 +130,7 @@ std::vector MappingState::getNextStepTiles(MappingLoc loc) const { // return it != current_step_tiles.end() ? it->second : empty; // } -std::vector -MappingState::getCurrentStepLinks(MappingLoc loc) const { +std::vector MappingState::getCurrentStepLinks(MappingLoc loc) const { assert((loc.resource->getKind() == ResourceKind::Tile) && "Current step links can only be queried for tiles"); std::vector current_step_links; @@ -234,6 +244,20 @@ void MappingState::encodeMappingState() { mlir::IntegerAttr::get(mlir::IntegerType::get(ctx, 32), loc.time_step))}); mapping_entries.push_back(dict); + } else if (loc.resource->getKind() == ResourceKind::Register) { + kind_str = "register"; + auto dict = mlir::DictionaryAttr::get( + ctx, {mlir::NamedAttribute(mlir::StringAttr::get(ctx, "resource"), + mlir::StringAttr::get(ctx, kind_str)), + mlir::NamedAttribute( + mlir::StringAttr::get(ctx, "id"), + mlir::IntegerAttr::get(mlir::IntegerType::get(ctx, 32), + loc.resource->getId())), + mlir::NamedAttribute( + mlir::StringAttr::get(ctx, "time_step"), + mlir::IntegerAttr::get(mlir::IntegerType::get(ctx, 32), + loc.time_step))}); + mapping_entries.push_back(dict); } else { kind_str = "unknown"; auto dict = mlir::DictionaryAttr::get( diff --git a/lib/NeuraDialect/Mapping/mapping_util.cpp b/lib/NeuraDialect/Mapping/mapping_util.cpp index 816d3fd5..117796f6 100644 --- a/lib/NeuraDialect/Mapping/mapping_util.cpp +++ b/lib/NeuraDialect/Mapping/mapping_util.cpp @@ -121,8 +121,9 @@ int mlir::neura::calculateResMii(Operation *func_op, // Count all "compute" operations (non-terminators, non-block ops). func_op->walk([&](Operation *op) { // Skips non-materialized ops. - if (isa(op) || isa(op)) { + if (isa(op) || isa(op)) { return; } ++num_ops; @@ -289,6 +290,19 @@ bool mlir::neura::tryRouteBackwardMove(Operation *mov_op, MappingLoc src_loc, return tryRouteDataMove(mov_op, src_loc, dst_loc, true, state, path_out); } +Register *mlir::neura::getAvailableRegister( + const MappingState &state, Tile *tile, int start_time, int exclusive_end_time) { + for (Register *reg : tile->getRegisters()) { + // FIXME: We may need constrain the register availability to the conflicting + // input channel (either the input channel or a register file on the same input + // direction could be active at one time). + if (state.isAvailableAcrossTimeInRange(reg, start_time, exclusive_end_time)) { + return reg; + } + } + return nullptr; +} + bool mlir::neura::tryRouteDataMove(Operation *mov_op, MappingLoc src_loc, MappingLoc dst_loc, bool is_backward_move, const MappingState &state, @@ -319,43 +333,53 @@ bool mlir::neura::tryRouteDataMove(Operation *mov_op, MappingLoc src_loc, // BFS-style search for a path from src_tile to dst_tile. while (!queue.empty()) { - auto [current_tile, current_time, current_path] = queue.front(); + auto [current_tile, current_step, current_path] = queue.front(); queue.pop(); if (current_tile == dst_tile) { // Confirms path reaches the target tile no later than deadline step. - if (current_time <= deadline_step) { + if (current_step <= deadline_step) { // Either arrives exactly right before the dst starts computation. - // So the current_time on the target tile is the same as deadline step. - if (current_time == deadline_step) { + // So the current_step on the target tile is the same as deadline step. + if (current_step == deadline_step) { path_out = current_path; return true; } - // The last link can be held from arrival_time to dst_time - 1. - // TODO: We actually don't need to occupy the last link if the registers - // within the tile can be explicitly represented. - // https://github.com/coredac/dataflow/issues/52. - bool all_free = true; assert(!current_path.empty() && "Path should not be empty when checking last link"); - MappingLoc last_link = current_path.back(); - std::vector last_link_occupying; - for (int t = current_time; t < deadline_step; ++t) { - MappingLoc repeated{last_link.resource, t}; - last_link_occupying.push_back(repeated); - if (!state.isAvailableAcrossTime(repeated)) { - all_free = false; - break; - } + + Register *available_register = + getAvailableRegister(state, dst_tile, current_step, deadline_step); + if (!available_register) { + llvm::errs() << "[tryRouteDataMove] No available register found for " + << "dst_tile: " << dst_tile->getId() + << " from time step: " << current_step + << " till deadline step: " << deadline_step << "\n"; + // None of the register is available, skip this route and try others. + continue; } - if (all_free) { - path_out = current_path; - path_out.insert(path_out.end(), last_link_occupying.begin(), - last_link_occupying.end()); - return true; + // llvm::errs() << "[tryRouteDataMove] Found available register: " + // << available_register->getId() + // << " in register_file: " + // << available_register->getRegisterFile()->getId() + // << " at tile: " << dst_tile->getId() + // << " from time step: " << current_step + // << " till deadline step: " << deadline_step << "\n"; + // Register is available, so we can occupy the specific register across remaining time steps. + std::vector register_occupyings; + for (int t = current_step; t < deadline_step; ++t) { + MappingLoc register_loc{available_register, t}; + register_occupyings.push_back(register_loc); + // Double-checks if the register is available across the time steps. + assert(state.isAvailableAcrossTime(register_loc)); } + path_out = current_path; + path_out.insert(path_out.end(), register_occupyings.begin(), + register_occupyings.end()); + return true; + } else { // Arrives too late, not schedulable. continue; @@ -363,13 +387,13 @@ bool mlir::neura::tryRouteDataMove(Operation *mov_op, MappingLoc src_loc, } for (MappingLoc current_step_next_link : - state.getCurrentStepLinks({current_tile, current_time})) { + state.getCurrentStepLinks({current_tile, current_step})) { if (!state.isAvailableAcrossTime(current_step_next_link)) { continue; } Link *next_link = dyn_cast(current_step_next_link.resource); Tile *next_tile = next_link->getDstTile(); - int next_time = current_time + 1; + int next_step = current_step + 1; if (!visited.insert(next_tile).second) { continue; @@ -377,7 +401,7 @@ bool mlir::neura::tryRouteDataMove(Operation *mov_op, MappingLoc src_loc, std::vector extended_path = current_path; extended_path.push_back(current_step_next_link); - queue.push({next_tile, next_time, std::move(extended_path)}); + queue.push({next_tile, next_step, std::move(extended_path)}); } } @@ -394,48 +418,6 @@ Operation *mlir::neura::getMaterializedProducer(Value operand) { return materialized_producer; } -bool mlir::neura::tryHeuristicMapping(std::vector &sorted_ops, - const Architecture &architecture, - MappingState &mapping_state) { - DenseSet visited; - - for (Operation *op : sorted_ops) { - // TODO: Build up util func to distinguish materialized and non-materialized - // ops. - if (isa(op)) { - continue; - } - - std::vector sorted_locs = - calculateAward(op, architecture, mapping_state); - // auto target_loc = getLocWithMinCost(loc_with_cost); - if (sorted_locs.empty()) { - llvm::errs() << "[DEBUG] No locations found for op: " << *op << "\n"; - return false; // No locations available for this operation. - } - assert(!sorted_locs.empty() && - "No locations found for the operation to map"); - MappingLoc target_loc = sorted_locs.front(); - if (placeAndRoute(op, target_loc, mapping_state)) { - llvm::errs() << "[DEBUG] Successfully scheduled op: " << *op - << " at loc: " << target_loc.resource->getType() << "#" - << target_loc.resource->getId() - << " @t=" << target_loc.time_step << "\n"; - continue; - } else { - llvm::errs() << "[DEBUG] Failed to schedule op: " << *op - << "; target loc: " << target_loc.resource->getType() << "#" - << target_loc.resource->getId() - << " @t=" << target_loc.time_step << "\n"; - } - // TODO: Optimization -- backtrack a few times if failed to schedule the op. - // https://github.com/coredac/dataflow/issues/59 - return false; - } - - return true; -} - bool mlir::neura::canReachLocInTime(const std::vector &producers, const MappingLoc &target_loc, int deadline_step, @@ -473,7 +455,7 @@ bool mlir::neura::canReachLocInTime(const MappingLoc &src_loc, struct QueueEntry { MappingLoc loc; - int current_time; + int current_step; }; std::queue queue; @@ -483,44 +465,49 @@ bool mlir::neura::canReachLocInTime(const MappingLoc &src_loc, visited.insert(dyn_cast(src_loc.resource)); while (!queue.empty()) { - auto [current_loc, current_time] = queue.front(); + auto [current_loc, current_step] = queue.front(); queue.pop(); // If we reach the destination tile and time step is not after dst_loc if (current_loc.resource == dst_loc.resource && - current_time <= dst_loc.time_step && + current_step <= dst_loc.time_step && dst_loc.time_step <= deadline_step) { return true; } - if (current_time >= deadline_step) { + if (current_step >= deadline_step) { continue; } + // // Explores all next step tiles from the current location. + // for (const MappingLoc &next_loc_tile : + // mapping_state.getNextStepTiles(current_loc)) { + // Explores all next step tiles from the current location. - for (const MappingLoc &next_loc : - mapping_state.getNextStepTiles(current_loc)) { - if (!mapping_state.isAvailableAcrossTime(next_loc)) { + for (const MappingLoc ¤t_loc_out_link : + mapping_state.getCurrentStepLinks(current_loc)) { + + // Makes sure the link is not occupied. + if (!mapping_state.isAvailableAcrossTime(current_loc_out_link)) { continue; } - int next_time = current_time + 1; - if (next_time > deadline_step) { + // Skips if already miss the deadline. + int next_step = current_step + 1; + if (next_step > deadline_step) { continue; } - Tile *next_tile = llvm::dyn_cast(next_loc.resource); + // Records the tile for further exploration. + Tile *next_tile = llvm::dyn_cast(current_loc_out_link.resource)->getDstTile(); assert(next_tile && "Next location must be a Tile"); if (visited.contains(next_tile)) { continue; } visited.insert(next_tile); - - MappingLoc next_step_loc = next_loc; - next_step_loc.time_step = next_time; - - queue.push({next_step_loc, next_time}); + MappingLoc next_loc_tile_with_step = {next_tile, next_step}; + queue.push({next_loc_tile_with_step, next_step}); } } @@ -661,6 +648,10 @@ bool mlir::neura::placeAndRoute(Operation *op, const MappingLoc &target_loc, if (mapping_state.bindOp(target_loc, op)) { std::vector routed_operands; std::vector routed_ctrl_movs; + llvm::errs() << "[DEBUG] Schedule op " << *op << " onto loc: " + << target_loc.resource->getType() << "#" + << target_loc.resource->getId() + << " @t=" << target_loc.time_step << "\n"; // Tries to route the data move operations. for (Value operand : op->getOperands()) { llvm::errs() << "Processing operand: " << operand << "\n"; @@ -693,7 +684,7 @@ bool mlir::neura::placeAndRoute(Operation *op, const MappingLoc &target_loc, << src_loc.resource->getId() << " @t=" << src_loc.time_step << " to " << target_loc.resource->getType() << "#" << target_loc.resource->getId() - << " @t=" << target_loc.time_step << "\n"; + << " @t=" << target_loc.time_step << "; so unschedule op\n"; mapping_state.unbindOp(op); for (Operation *routed_op : routed_operands) { llvm::errs() << "[DEBUG] Releasing route for routed operand: " @@ -727,9 +718,11 @@ bool mlir::neura::placeAndRoute(Operation *op, const MappingLoc &target_loc, continue; } llvm::errs() << "[DEBUG] Failed to route ctrl_mov: " << *ctrl_mov + << " from " << target_loc.resource->getType() << "#" + << target_loc.resource->getId() << " @t=" << target_loc.time_step << " to " << backward_loc.resource->getType() << "#" << backward_loc.resource->getId() - << " @t=" << backward_loc.time_step << "\n"; + << " @t=" << backward_loc.time_step << "; so unschedule op\n"; mapping_state.unbindOp(op); for (Operation *routed_ctrl_mov : routed_ctrl_movs) { llvm::errs() << "[DEBUG] Releasing route for routed ctrl_mov: " diff --git a/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp b/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp index 36fd4302..93f8bb77 100644 --- a/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp +++ b/lib/NeuraDialect/Transforms/MapToAcceleratorPass.cpp @@ -52,7 +52,9 @@ struct MapToAcceleratorPass StringRef mappingStrategy_stringRef(mappingStrategy.getValue()); // Creates a mapping strategy based on the provided option. std::unique_ptr mapping_strategy; - if (mappingStrategy_stringRef == "greedy") { + if (mappingStrategy_stringRef == "simple") { + mapping_strategy = std::make_unique(1, 1); + } else if (mappingStrategy_stringRef == "greedy") { mapping_strategy = std::make_unique(INT_MAX, 1); } else if (mappingStrategy_stringRef == "exhaustive") { mapping_strategy = std::make_unique(INT_MAX, INT_MAX); @@ -140,13 +142,16 @@ struct MapToAcceleratorPass IntegerAttr::get(IntegerType::get(func.getContext(), 32), res_mii); func->setAttr("ResMII", res_mii_attr); - const int minII = std::min(rec_mii, res_mii); + const int possibleMinII = std::max(rec_mii, res_mii); constexpr int maxII = 10; std::vector sorted_ops = getTopologicallySortedOps(func); for (Operation *op : sorted_ops) { llvm::outs() << "[MapToAcceleratorPass] sorted op: " << *op << "\n"; } - for (int ii = minII; ii <= maxII; ++ii) { + for (int ii = possibleMinII; ii <= maxII; ++ii) { + llvm::errs() << "[MapToAcceleratorPass] Start mapping with target II of " + << ii << "\n"; + // Creates a mapping state for the current II. MappingState mapping_state(architecture, ii); if (mapping_strategy->map(sorted_ops, architecture, mapping_state)) { // success diff --git a/test/neura/ctrl/branch_for.mlir b/test/neura/ctrl/branch_for.mlir index d93befed..6c2e203d 100644 --- a/test/neura/ctrl/branch_for.mlir +++ b/test/neura/ctrl/branch_for.mlir @@ -35,7 +35,7 @@ // RUN: --leverage-predicated-value \ // RUN: --transform-ctrl-to-data-flow \ // RUN: --insert-data-mov \ -// RUN: --map-to-accelerator="mapping-strategy=heuristic" \ +// RUN: --map-to-accelerator="mapping-strategy=simple" \ // RUN: | FileCheck %s -check-prefix=MAPPING // RUN: mlir-neura-opt %s \ @@ -45,7 +45,7 @@ // RUN: --leverage-predicated-value \ // RUN: --transform-ctrl-to-data-flow \ // RUN: --insert-data-mov \ -// RUN: --map-to-accelerator="mapping-strategy=heuristic" \ +// RUN: --map-to-accelerator="mapping-strategy=simple" \ // RUN: --generate-code // RUN: FileCheck %s --input-file=generated-instructions.json -check-prefix=INST @@ -217,80 +217,80 @@ func.func @loop_test() -> f32 { // MOV-NEXT: "neura.return"(%65) : (!neura.data) -> () // MOV-NEXT: } -// MAPPING: func.func @loop_test() -> f32 attributes {CompiledII = 6 : i32, RecMII = 4 : i32, ResMII = 2 : i32, accelerator = "neura"} { -// MAPPING-NEXT: %0 = "neura.constant"() <{predicate = true, value = 10 : i64}> {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 0 : i32, x = 1 : i32, y = 1 : i32}]} : () -> !neura.data -// MAPPING-NEXT: %1 = "neura.data_mov"(%0) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %2 = "neura.grant_always"(%1) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %3 = "neura.data_mov"(%0) {mapping_locs = [{id = 16 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %4 = "neura.grant_once"(%3) {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 2 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %5 = "neura.constant"() <{predicate = true, value = 0 : i64}> {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 0 : i32, x = 1 : i32, y = 2 : i32}]} : () -> !neura.data -// MAPPING-NEXT: %6 = "neura.data_mov"(%5) {mapping_locs = [{id = 20 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %7 = "neura.grant_once"(%6) {mapping_locs = [{id = 7 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 3 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %8 = "neura.constant"() <{predicate = true, value = 1 : i64}> {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 0 : i32, x = 2 : i32, y = 2 : i32}]} : () -> !neura.data -// MAPPING-NEXT: %9 = "neura.data_mov"(%8) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %10 = "neura.grant_always"(%9) {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 1 : i32, x = 2 : i32, y = 2 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %11 = "neura.data_mov"(%8) {mapping_locs = [{id = 33 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %12 = "neura.grant_once"(%11) {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 1 : i32, x = 2 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %13 = "neura.constant"() <{predicate = true, value = 3.000000e+00 : f32}> {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 0 : i32, x = 2 : i32, y = 1 : i32}]} : () -> !neura.data -// MAPPING-NEXT: %14 = "neura.data_mov"(%13) {mapping_locs = [{id = 28 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %15 = "neura.grant_always"(%14) {mapping_locs = [{id = 13 : i32, resource = "tile", time_step = 1 : i32, x = 3 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %16 = "neura.data_mov"(%13) {mapping_locs = [{id = 29 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %17 = "neura.grant_once"(%16) {mapping_locs = [{id = 8 : i32, resource = "tile", time_step = 1 : i32, x = 2 : i32, y = 0 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %18 = "neura.constant"() <{predicate = true, value = 0.000000e+00 : f32}> {mapping_locs = [{id = 14 : i32, resource = "tile", time_step = 0 : i32, x = 3 : i32, y = 2 : i32}]} : () -> !neura.data -// MAPPING-NEXT: %19 = "neura.data_mov"(%18) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %20 = "neura.grant_once"(%19) {mapping_locs = [{id = 14 : i32, resource = "tile", time_step = 1 : i32, x = 3 : i32, y = 2 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %21 = neura.reserve : !neura.data -// MAPPING-NEXT: %22 = "neura.data_mov"(%4) {mapping_locs = [{id = 19 : i32, resource = "link", time_step = 1 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %23 = "neura.phi"(%21, %22) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 2 : i32, x = 1 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %24 = neura.reserve : !neura.data -// MAPPING-NEXT: %25 = "neura.data_mov"(%12) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %26 = "neura.phi"(%24, %25) {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %27 = neura.reserve : !neura.data -// MAPPING-NEXT: %28 = "neura.data_mov"(%17) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %29 = "neura.phi"(%27, %28) {mapping_locs = [{id = 8 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 0 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %30 = neura.reserve : !neura.data -// MAPPING-NEXT: %31 = "neura.data_mov"(%20) {mapping_locs = [{id = 43 : i32, resource = "link", time_step = 1 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %32 = "neura.phi"(%30, %31) {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 2 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %33 = neura.reserve : !neura.data -// MAPPING-NEXT: %34 = "neura.data_mov"(%7) {mapping_locs = [{id = 23 : i32, resource = "link", time_step = 1 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %35 = "neura.phi"(%33, %34) {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 2 : i32, x = 1 : i32, y = 2 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %36 = "neura.data_mov"(%32) {mapping_locs = [{id = 31 : i32, resource = "link", time_step = 2 : i32}, {id = 19 : i32, resource = "link", time_step = 3 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %37 = "neura.data_mov"(%29) {mapping_locs = [{id = 24 : i32, resource = "link", time_step = 2 : i32}, {id = 12 : i32, resource = "link", time_step = 3 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %38 = "neura.fadd"(%36, %37) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 4 : i32, x = 1 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %39 = "neura.data_mov"(%35) {mapping_locs = [{id = 18 : i32, resource = "link", time_step = 2 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %40 = "neura.data_mov"(%26) {mapping_locs = [{id = 30 : i32, resource = "link", time_step = 2 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %41 = "neura.add"(%39, %40) {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 3 : i32, x = 2 : i32, y = 2 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %42 = "neura.data_mov"(%41) {mapping_locs = [{id = 33 : i32, resource = "link", time_step = 3 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %43 = "neura.data_mov"(%23) {mapping_locs = [{id = 14 : i32, resource = "link", time_step = 2 : i32}, {id = 14 : i32, resource = "link", time_step = 3 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %44 = "neura.icmp"(%42, %43) <{cmpType = "slt"}> {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 4 : i32, x = 2 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data -// MAPPING-NEXT: %45 = "neura.data_mov"(%41) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %46 = "neura.data_mov"(%44) {mapping_locs = [{id = 30 : i32, resource = "link", time_step = 4 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %47 = neura.grant_predicate %45, %46 {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 5 : i32, x = 2 : i32, y = 2 : i32}]} : !neura.data, !neura.data -> !neura.data -// MAPPING-NEXT: neura.ctrl_mov %47 -> %33 {mapping_locs = [{id = 31 : i32, resource = "link", time_step = 5 : i32}, {id = 31 : i32, resource = "link", time_step = 6 : i32}, {id = 31 : i32, resource = "link", time_step = 7 : i32}]} : !neura.data !neura.data -// MAPPING-NEXT: %48 = "neura.data_mov"(%38) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %49 = "neura.data_mov"(%44) {mapping_locs = [{id = 27 : i32, resource = "link", time_step = 4 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %50 = neura.grant_predicate %48, %49 {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 5 : i32, x = 1 : i32, y = 1 : i32}]} : !neura.data, !neura.data -> !neura.data -// MAPPING-NEXT: neura.ctrl_mov %50 -> %30 {mapping_locs = [{id = 14 : i32, resource = "link", time_step = 5 : i32}, {id = 30 : i32, resource = "link", time_step = 6 : i32}, {id = 30 : i32, resource = "link", time_step = 7 : i32}]} : !neura.data !neura.data -// MAPPING-NEXT: %51 = "neura.data_mov"(%17) {mapping_locs = [{id = 25 : i32, resource = "link", time_step = 1 : i32}, {id = 39 : i32, resource = "link", time_step = 2 : i32}, {id = 39 : i32, resource = "link", time_step = 3 : i32}, {id = 39 : i32, resource = "link", time_step = 4 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %52 = "neura.data_mov"(%44) {mapping_locs = [{id = 28 : i32, resource = "link", time_step = 4 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %53 = neura.grant_predicate %51, %52 {mapping_locs = [{id = 13 : i32, resource = "tile", time_step = 5 : i32, x = 3 : i32, y = 1 : i32}]} : !neura.data, !neura.data -> !neura.data -// MAPPING-NEXT: neura.ctrl_mov %53 -> %27 {mapping_locs = [{id = 41 : i32, resource = "link", time_step = 5 : i32}, {id = 38 : i32, resource = "link", time_step = 6 : i32}, {id = 38 : i32, resource = "link", time_step = 7 : i32}]} : !neura.data !neura.data -// MAPPING-NEXT: %54 = "neura.data_mov"(%12) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %55 = "neura.data_mov"(%44) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %56 = neura.grant_predicate %54, %55 {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 9 : i32, x = 2 : i32, y = 1 : i32}]} : !neura.data, !neura.data -> !neura.data -// MAPPING-NEXT: neura.ctrl_mov %56 -> %24 {mapping_locs = []} : !neura.data !neura.data -// MAPPING-NEXT: %57 = "neura.data_mov"(%4) {mapping_locs = [{id = 18 : i32, resource = "link", time_step = 1 : i32}, {id = 33 : i32, resource = "link", time_step = 2 : i32}, {id = 27 : i32, resource = "link", time_step = 3 : i32}, {id = 15 : i32, resource = "link", time_step = 4 : i32}, {id = 15 : i32, resource = "link", time_step = 5 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %58 = "neura.data_mov"(%44) {mapping_locs = [{id = 29 : i32, resource = "link", time_step = 4 : i32}, {id = 24 : i32, resource = "link", time_step = 5 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %59 = neura.grant_predicate %57, %58 {mapping_locs = [{id = 4 : i32, resource = "tile", time_step = 6 : i32, x = 1 : i32, y = 0 : i32}]} : !neura.data, !neura.data -> !neura.data -// MAPPING-NEXT: neura.ctrl_mov %59 -> %21 {mapping_locs = [{id = 12 : i32, resource = "link", time_step = 6 : i32}, {id = 12 : i32, resource = "link", time_step = 7 : i32}]} : !neura.data !neura.data -// MAPPING-NEXT: %60 = "neura.data_mov"(%44) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %61 = "neura.not"(%60) {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 5 : i32, x = 2 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %62 = "neura.data_mov"(%38) {mapping_locs = [{id = 13 : i32, resource = "link", time_step = 4 : i32}, {id = 3 : i32, resource = "link", time_step = 5 : i32}, {id = 0 : i32, resource = "link", time_step = 6 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %63 = "neura.data_mov"(%61) {mapping_locs = [{id = 27 : i32, resource = "link", time_step = 5 : i32}, {id = 15 : i32, resource = "link", time_step = 6 : i32}]} : (!neura.data) -> !neura.data -// MAPPING-NEXT: %64 = neura.grant_predicate %62, %63 {mapping_locs = [{id = 4 : i32, resource = "tile", time_step = 7 : i32, x = 1 : i32, y = 0 : i32}]} : !neura.data, !neura.data -> !neura.data -// MAPPING-NEXT: %65 = "neura.data_mov"(%64) {mapping_locs = []} : (!neura.data) -> !neura.data -// MAPPING-NEXT: "neura.return"(%65) {mapping_locs = [{id = 4 : i32, resource = "tile", time_step = 8 : i32, x = 1 : i32, y = 0 : i32}]} : (!neura.data) -> () -// MAPPING-NEXT: } +// MAPPING: func.func @loop_test() -> f32 attributes {CompiledII = 7 : i32, RecMII = 4 : i32, ResMII = 2 : i32, accelerator = "neura"} { +// MAPPING-NEXT: %0 = "neura.constant"() <{predicate = true, value = 10 : i64}> {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 0 : i32, x = 2 : i32, y = 1 : i32}]} : () -> !neura.data +// MAPPING-NEXT: %1 = "neura.data_mov"(%0) {mapping_locs = [{id = 20 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %2 = "neura.grant_always"(%1) {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 1 : i32, x = 2 : i32, y = 2 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %3 = "neura.data_mov"(%0) {mapping_locs = [{id = 17 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %4 = "neura.grant_once"(%3) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %5 = "neura.constant"() <{predicate = true, value = 0 : i64}> {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 0 : i32, x = 2 : i32, y = 2 : i32}]} : () -> !neura.data +// MAPPING-NEXT: %6 = "neura.data_mov"(%5) {mapping_locs = [{id = 31 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %7 = "neura.grant_once"(%6) {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 2 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %8 = "neura.constant"() <{predicate = true, value = 1 : i64}> {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 0 : i32, x = 1 : i32, y = 2 : i32}]} : () -> !neura.data +// MAPPING-NEXT: %9 = "neura.data_mov"(%8) {mapping_locs = [{id = 30 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %10 = "neura.grant_always"(%9) {mapping_locs = [{id = 13 : i32, resource = "tile", time_step = 1 : i32, x = 1 : i32, y = 3 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %11 = "neura.data_mov"(%8) {mapping_locs = []} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %12 = "neura.grant_once"(%11) {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 2 : i32, x = 1 : i32, y = 2 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %13 = "neura.constant"() <{predicate = true, value = 3.000000e+00 : f32}> {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 0 : i32, x = 1 : i32, y = 1 : i32}]} : () -> !neura.data +// MAPPING-NEXT: %14 = "neura.data_mov"(%13) {mapping_locs = [{id = 14 : i32, resource = "link", time_step = 0 : i32}, {id = 24 : i32, resource = "register", time_step = 1 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %15 = "neura.grant_always"(%14) {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %16 = "neura.data_mov"(%13) {mapping_locs = [{id = 13 : i32, resource = "link", time_step = 0 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %17 = "neura.grant_once"(%16) {mapping_locs = [{id = 4 : i32, resource = "tile", time_step = 1 : i32, x = 0 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %18 = "neura.constant"() <{predicate = true, value = 0.000000e+00 : f32}> {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 1 : i32, x = 2 : i32, y = 1 : i32}]} : () -> !neura.data +// MAPPING-NEXT: %19 = "neura.data_mov"(%18) {mapping_locs = [{id = 17 : i32, resource = "link", time_step = 1 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %20 = "neura.grant_once"(%19) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 2 : i32, x = 1 : i32, y = 1 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %21 = neura.reserve : !neura.data +// MAPPING-NEXT: %22 = "neura.data_mov"(%4) {mapping_locs = [{id = 16 : i32, resource = "link", time_step = 1 : i32}, {id = 36 : i32, resource = "register", time_step = 2 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %23 = "neura.phi"(%21, %22) {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 3 : i32, x = 1 : i32, y = 2 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %24 = neura.reserve : !neura.data +// MAPPING-NEXT: %25 = "neura.data_mov"(%12) {mapping_locs = [{id = 28 : i32, resource = "link", time_step = 2 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %26 = "neura.phi"(%24, %25) {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 3 : i32, x = 2 : i32, y = 2 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %27 = neura.reserve : !neura.data +// MAPPING-NEXT: %28 = "neura.data_mov"(%17) {mapping_locs = [{id = 10 : i32, resource = "link", time_step = 1 : i32}, {id = 14 : i32, resource = "link", time_step = 2 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %29 = "neura.phi"(%27, %28) {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 3 : i32, x = 2 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %30 = neura.reserve : !neura.data +// MAPPING-NEXT: %31 = "neura.data_mov"(%20) {mapping_locs = []} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %32 = "neura.phi"(%30, %31) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 3 : i32, x = 1 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %33 = neura.reserve : !neura.data +// MAPPING-NEXT: %34 = "neura.data_mov"(%7) {mapping_locs = [{id = 28 : i32, resource = "link", time_step = 1 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %35 = "neura.phi"(%33, %34) {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 2 : i32, x = 2 : i32, y = 2 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %36 = "neura.data_mov"(%32) {mapping_locs = []} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %37 = "neura.data_mov"(%29) {mapping_locs = [{id = 17 : i32, resource = "link", time_step = 3 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %38 = "neura.fadd"(%36, %37) {mapping_locs = [{id = 5 : i32, resource = "tile", time_step = 4 : i32, x = 1 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %39 = "neura.data_mov"(%35) {mapping_locs = [{id = 33 : i32, resource = "link", time_step = 2 : i32}, {id = 24 : i32, resource = "register", time_step = 3 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %40 = "neura.data_mov"(%26) {mapping_locs = [{id = 33 : i32, resource = "link", time_step = 3 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %41 = "neura.add"(%39, %40) {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 4 : i32, x = 2 : i32, y = 1 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %42 = "neura.data_mov"(%41) {mapping_locs = [{id = 20 : i32, resource = "link", time_step = 4 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %43 = "neura.data_mov"(%23) {mapping_locs = [{id = 28 : i32, resource = "link", time_step = 3 : i32}, {id = 40 : i32, resource = "register", time_step = 4 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %44 = "neura.icmp"(%42, %43) <{cmpType = "slt"}> {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 5 : i32, x = 2 : i32, y = 2 : i32}]} : (!neura.data, !neura.data) -> !neura.data +// MAPPING-NEXT: %45 = "neura.data_mov"(%41) {mapping_locs = [{id = 17 : i32, resource = "link", time_step = 4 : i32}, {id = 16 : i32, resource = "link", time_step = 5 : i32}, {id = 28 : i32, resource = "link", time_step = 6 : i32}, {id = 40 : i32, resource = "register", time_step = 7 : i32}, {id = 40 : i32, resource = "register", time_step = 8 : i32}, {id = 40 : i32, resource = "register", time_step = 9 : i32}, {id = 40 : i32, resource = "register", time_step = 10 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %46 = "neura.data_mov"(%44) {mapping_locs = []} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %47 = neura.grant_predicate %45, %46 {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 11 : i32, x = 2 : i32, y = 2 : i32}]} : !neura.data, !neura.data -> !neura.data +// MAPPING-NEXT: neura.ctrl_mov %47 -> %33 {mapping_locs = []} : !neura.data !neura.data +// MAPPING-NEXT: %48 = "neura.data_mov"(%38) {mapping_locs = [{id = 14 : i32, resource = "link", time_step = 4 : i32}, {id = 18 : i32, resource = "link", time_step = 5 : i32}, {id = 23 : i32, resource = "link", time_step = 6 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %49 = "neura.data_mov"(%44) {mapping_locs = [{id = 32 : i32, resource = "link", time_step = 5 : i32}, {id = 44 : i32, resource = "register", time_step = 6 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %50 = neura.grant_predicate %48, %49 {mapping_locs = [{id = 11 : i32, resource = "tile", time_step = 7 : i32, x = 3 : i32, y = 2 : i32}]} : !neura.data, !neura.data -> !neura.data +// MAPPING-NEXT: neura.ctrl_mov %50 -> %30 {mapping_locs = [{id = 35 : i32, resource = "link", time_step = 7 : i32}, {id = 31 : i32, resource = "link", time_step = 8 : i32}, {id = 29 : i32, resource = "link", time_step = 9 : i32}]} : !neura.data !neura.data +// MAPPING-NEXT: %51 = "neura.data_mov"(%17) {mapping_locs = [{id = 12 : i32, resource = "link", time_step = 1 : i32}, {id = 24 : i32, resource = "link", time_step = 2 : i32}, {id = 30 : i32, resource = "link", time_step = 3 : i32}, {id = 41 : i32, resource = "link", time_step = 4 : i32}, {id = 56 : i32, resource = "register", time_step = 5 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %52 = "neura.data_mov"(%44) {mapping_locs = [{id = 34 : i32, resource = "link", time_step = 5 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %53 = neura.grant_predicate %51, %52 {mapping_locs = [{id = 14 : i32, resource = "tile", time_step = 6 : i32, x = 2 : i32, y = 3 : i32}]} : !neura.data, !neura.data -> !neura.data +// MAPPING-NEXT: neura.ctrl_mov %53 -> %27 {mapping_locs = [{id = 45 : i32, resource = "link", time_step = 6 : i32}, {id = 33 : i32, resource = "link", time_step = 7 : i32}, {id = 26 : i32, resource = "register", time_step = 8 : i32}, {id = 26 : i32, resource = "register", time_step = 9 : i32}]} : !neura.data !neura.data +// MAPPING-NEXT: %54 = "neura.data_mov"(%12) {mapping_locs = [{id = 30 : i32, resource = "link", time_step = 2 : i32}, {id = 41 : i32, resource = "link", time_step = 3 : i32}, {id = 45 : i32, resource = "link", time_step = 4 : i32}, {id = 40 : i32, resource = "register", time_step = 5 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %55 = "neura.data_mov"(%44) {mapping_locs = []} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %56 = neura.grant_predicate %54, %55 {mapping_locs = [{id = 10 : i32, resource = "tile", time_step = 6 : i32, x = 2 : i32, y = 2 : i32}]} : !neura.data, !neura.data -> !neura.data +// MAPPING-NEXT: neura.ctrl_mov %56 -> %24 {mapping_locs = []} : !neura.data !neura.data +// MAPPING-NEXT: %57 = "neura.data_mov"(%4) {mapping_locs = [{id = 14 : i32, resource = "link", time_step = 1 : i32}, {id = 25 : i32, resource = "register", time_step = 2 : i32}, {id = 25 : i32, resource = "register", time_step = 3 : i32}, {id = 25 : i32, resource = "register", time_step = 4 : i32}, {id = 25 : i32, resource = "register", time_step = 5 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %58 = "neura.data_mov"(%44) {mapping_locs = [{id = 33 : i32, resource = "link", time_step = 5 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %59 = neura.grant_predicate %57, %58 {mapping_locs = [{id = 6 : i32, resource = "tile", time_step = 6 : i32, x = 2 : i32, y = 1 : i32}]} : !neura.data, !neura.data -> !neura.data +// MAPPING-NEXT: neura.ctrl_mov %59 -> %21 {mapping_locs = [{id = 17 : i32, resource = "link", time_step = 6 : i32}, {id = 16 : i32, resource = "link", time_step = 7 : i32}, {id = 37 : i32, resource = "register", time_step = 8 : i32}, {id = 37 : i32, resource = "register", time_step = 9 : i32}]} : !neura.data !neura.data +// MAPPING-NEXT: %60 = "neura.data_mov"(%44) {mapping_locs = [{id = 31 : i32, resource = "link", time_step = 5 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %61 = "neura.not"(%60) {mapping_locs = [{id = 9 : i32, resource = "tile", time_step = 6 : i32, x = 1 : i32, y = 2 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %62 = "neura.data_mov"(%38) {mapping_locs = [{id = 13 : i32, resource = "link", time_step = 4 : i32}, {id = 12 : i32, resource = "link", time_step = 5 : i32}, {id = 32 : i32, resource = "register", time_step = 6 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %63 = "neura.data_mov"(%61) {mapping_locs = [{id = 27 : i32, resource = "link", time_step = 6 : i32}]} : (!neura.data) -> !neura.data +// MAPPING-NEXT: %64 = neura.grant_predicate %62, %63 {mapping_locs = [{id = 8 : i32, resource = "tile", time_step = 7 : i32, x = 0 : i32, y = 2 : i32}]} : !neura.data, !neura.data -> !neura.data +// MAPPING-NEXT: %65 = "neura.data_mov"(%64) {mapping_locs = []} : (!neura.data) -> !neura.data +// MAPPING-NEXT: "neura.return"(%65) {mapping_locs = [{id = 8 : i32, resource = "tile", time_step = 8 : i32, x = 0 : i32, y = 2 : i32}]} : (!neura.data) -> () +// MAPPING-NEXT: } // INST: "name": "neura.fadd", // INST-NEXT: "operands": [