Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3aa6cf2
Remove per-layer bounding box support from NetCostHandler
soheilshahrouz Aug 27, 2026
f4bdcae
Remove --place_bounding_box_mode option and cube_bb placement context…
soheilshahrouz Aug 27, 2026
a175ce1
Remove unused inter_layer_connections_limited_to_opin helper
soheilshahrouz Aug 27, 2026
81e54f2
Remove nightly tasks that set --place_bounding_box_mode
soheilshahrouz Aug 27, 2026
171ca33
Remove --place_bounding_box_mode from command line documentation
soheilshahrouz Aug 27, 2026
9807cd0
Make get_chanxy_cost_fac_ a non-template function
soheilshahrouz Aug 27, 2026
aa62100
make format
soheilshahrouz Aug 27, 2026
c64441b
Replace auto with explicit types in net_cost_handler.cpp
soheilshahrouz Aug 27, 2026
0e2260b
Mark vtr::Range accessors noexcept
soheilshahrouz Aug 27, 2026
7396448
Add Netlist::non_ignored_nets() view
soheilshahrouz Aug 27, 2026
c9164c4
Use Netlist::non_ignored_nets() in NetCostHandler
soheilshahrouz Aug 27, 2026
2243436
Keep vtr::Range::empty() non-const
soheilshahrouz Aug 27, 2026
2f6404e
Merge branch 'master' into remove_per_layer_bb
soheilshahrouz Aug 28, 2026
df2f086
Remove unused per-layer sink pin counts from NetCostHandler
soheilshahrouz Aug 28, 2026
f5a7dba
Const-qualify route tree iterator comparisons and make vtr::Range::em…
soheilshahrouz Aug 28, 2026
cafae92
Mark vtr::Range as a borrowed range so temporaries can be piped into …
soheilshahrouz Aug 29, 2026
f8fb902
Let blifexplorer inherit C++20 from the root CMakeLists
soheilshahrouz Aug 30, 2026
663b253
Remove unused MAX_NUM_LAYERS constant and its layer count assertion
soheilshahrouz Sep 2, 2026
828e124
Update 3d_cb_titan_other_auto_bb golden results for cube bounding box…
soheilshahrouz Sep 2, 2026
3a02a43
Drop the auto_bb suffix from the 3D titan_other nightly task names
soheilshahrouz Sep 2, 2026
c800558
Merge branch 'master' into remove_per_layer_bb
soheilshahrouz Sep 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions blifexplorer/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,6 @@ cmake_minimum_required(VERSION 3.16)

project("blifexplorer")

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

find_package(Qt5Widgets)
find_package(Qt5Gui)
find_package(Qt5Core)
Expand Down
13 changes: 0 additions & 13 deletions doc/src/vpr/command_line_usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1018,19 +1018,6 @@ If any of init_t, exit_t or alpha_t is specified, the user schedule, with a fixe

**Default:** ``criticality_timing``

.. option:: --place_bounding_box_mode {auto_bb | cube_bb | per_layer_bb}

Specifies the type of the wirelength estimator used during placement. For single layer architectures, cube_bb (a 3D bounding box) is always used (and is the same as per_layer_bb).
For 3D architectures, cube_bb is appropriate if you can cross between layers at switch blocks, while if you can only cross between layers at output pins per_layer_bb (one bounding box per layer) is more accurate and appropriate.

``auto_bb``: The bounding box type is determined automatically based on the cross-layer connections.

``cube_bb``: ``cube_bb`` bounding box is used to estimate the wirelength.

``per_layer_bb``: ``per_layer_bb`` bounding box is used to estimate the wirelength

**Default:** ``auto_bb``

.. option:: --place_frequency {once | always}

Specifies how often placement is performed during the minimum channel width search.
Expand Down
22 changes: 0 additions & 22 deletions libs/librrgraph/src/base/rr_graph_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,28 +239,6 @@ void rr_set_sink_locs(const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_buil
}
}

bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph) {
bool limited_to_opin = true;

for (const RRNodeId from_node : rr_graph.nodes()) {
e_rr_type from_type = rr_graph.node_type(from_node);
for (t_edge_size edge : rr_graph.edges(from_node)) {
RRNodeId to_node = rr_graph.edge_sink_node(from_node, edge);
e_rr_type to_type = rr_graph.node_type(to_node);

if (to_type == e_rr_type::CHANZ && from_type != e_rr_type::OPIN) {
limited_to_opin = false;
break;
}
}
if (!limited_to_opin) {
break;
}
}

return limited_to_opin;
}

bool chanx_chany_nodes_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId node2) {
e_rr_type type1 = rr_graph.node_type(node1);
e_rr_type type2 = rr_graph.node_type(node2);
Expand Down
10 changes: 0 additions & 10 deletions libs/librrgraph/src/base/rr_graph_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,6 @@ int seg_index_of_cblock(const RRGraphView& rr_graph, e_rr_type from_rr_type, int
*/
int seg_index_of_sblock(const RRGraphView& rr_graph, int from_node, int to_node);

/**
* @brief This function checks whether all inter-die connections are form OPINs. Return "true"
* if that is the case. Can be used for multiple purposes. For example, to determine which type of bounding
* box to be used to estimate the wire-length of a net.
*
* @param rr_graph The routing resource graph
* @return True if inter-die 3D connections are driven only by OPIN nodes; otherwise, false.
*/
bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph);

/**
* @brief Check if a CHANX and a CHANY node are adjacent, regardless of their order.
*
Expand Down
21 changes: 16 additions & 5 deletions libs/libvtrutil/src/vtr_range.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <iterator>
#include <ranges>

namespace vtr {
/**
Expand Down Expand Up @@ -45,15 +46,15 @@ class Range {
: begin_(b)
, end_(e) {}
///@brief Return an iterator to the start of the range
constexpr T begin() { return begin_; }
constexpr T begin() noexcept { return begin_; }
///@brief Return an iterator to the end of the range
constexpr T end() { return end_; }
constexpr T end() noexcept { return end_; }
///@brief Return an iterator to the start of the range (immutable)
constexpr const T begin() const { return begin_; }
constexpr const T begin() const noexcept { return begin_; }
///@brief Return an iterator to the end of the range (immutable)
constexpr const T end() const { return end_; }
constexpr const T end() const noexcept { return end_; }
///@brief Return true if empty
constexpr bool empty() { return begin_ == end_; }
constexpr bool empty() const noexcept { return begin_ == end_; }
///@brief Return the range size
constexpr size_t size() const { return std::distance(begin_, end_); }

Expand Down Expand Up @@ -81,3 +82,13 @@ template<typename Container>
inline auto make_range(const Container& c) { return make_range(std::begin(c), std::end(c)); }

} // namespace vtr

/**
* @brief Mark vtr::Range as a borrowed range.
*
* A vtr::Range only holds a pair of iterators, so those iterators stay valid
* after the Range object itself is destroyed. This lets temporary ranges be
* passed directly to std::ranges algorithms and views (e.g. std::views::filter).
*/
template<typename T>
inline constexpr bool std::ranges::enable_borrowed_range<vtr::Range<T>> = true;
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ AnnealerDetailedPlacer::AnnealerDetailedPlacer(const BlkLocRegistry& curr_cluste
FlatPlacementInfo(),
place_delay_model,
vpr_setup.PlacerOpts.place_auto_init_t_scale,
g_vpr_ctx.placement().cube_bb,
false /*is_flat*/,
false /*quiet*/);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ WindowedBiMatchingDetailedPlacer::WindowedBiMatchingDetailedPlacer(
const t_placer_opts& placer_opts)
: placer_state_(false)
, net_cost_handler_(placer_state_,
g_vpr_ctx.placement().cube_bb,
e_place_algorithm::BOUNDING_BOX_PLACE,
placer_opts.congestion_chan_util_threshold) {
BlkLocRegistry& blk_loc_registry = placer_state_.mutable_blk_loc_registry();
Expand Down
7 changes: 3 additions & 4 deletions vpr/src/analytical_place/full_legalization/full_legalizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ void FlatRecon::create_clusters(ClusterLegalizer& cluster_legalizer,

void FlatRecon::place_clusters(const PartialPlacement& p_placement) {
// Setup the global variables for placement.
g_vpr_ctx.mutable_placement().init_placement_context(vpr_setup_.PlacerOpts, arch_.directs);
g_vpr_ctx.mutable_placement().init_placement_context(arch_.directs);
g_vpr_ctx.mutable_floorplanning().update_floorplanning_context_pre_place(*g_vpr_ctx.placement().place_macros);

// The placement will be stored in the global block loc registry.
Expand Down Expand Up @@ -1225,8 +1225,7 @@ void NaiveFullLegalizer::legalize(const PartialPlacement& p_placement) {
const ClusteredNetlist& clb_nlist = g_vpr_ctx.clustering().clb_nlist;

// Initialize the placement context.
g_vpr_ctx.mutable_placement().init_placement_context(vpr_setup_.PlacerOpts,
arch_.directs);
g_vpr_ctx.mutable_placement().init_placement_context(arch_.directs);

const PlaceMacros& place_macros = *g_vpr_ctx.placement().place_macros;

Expand Down Expand Up @@ -1305,7 +1304,7 @@ void APPack::legalize(const PartialPlacement& p_placement) {
vpr_setup_noc(vpr_setup_, arch_);

// Setup the global variables for placement.
g_vpr_ctx.mutable_placement().init_placement_context(vpr_setup_.PlacerOpts, arch_.directs);
g_vpr_ctx.mutable_placement().init_placement_context(arch_.directs);
g_vpr_ctx.mutable_floorplanning().update_floorplanning_context_pre_place(*g_vpr_ctx.placement().place_macros);

// The placement will be stored in the global block loc registry.
Expand Down
6 changes: 6 additions & 0 deletions vpr/src/base/netlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@
* The derived functions based off of the virtual functions have suffix *_impl()
*
*/
#include <ranges>
#include <string>
#include <vector>
#include <unordered_map>
Expand Down Expand Up @@ -702,6 +703,11 @@ class Netlist {
///@brief Returns a range consisting of all nets in the netlist
net_range nets() const;

///@brief Returns a view over the nets that are not ignored.
auto non_ignored_nets() const {
return nets() | std::views::filter([this](NetId net_id) { return !net_is_ignored(net_id); });
}

Comment on lines +706 to +710

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm 90% sure this is the reason behind the performance regression. the views library, in particular views::filter has terrible performance compared to raw loops. No fundamental reason other than that current compilers are just not good enough yet and they emit awful assembly.

https://lemire.me/blog/2025/10/05/stdranges-may-not-deliver-the-performance-that-you-expect/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

non_ignored_nets() is only called in periodic paths where the cost is computed from scratch, not in a per-swap hot loop. The article's benchmarks uses chained views with lazy evaluation. Here, we have a single filter.

///@brief Returns a range consisting of all pins in the netlist
pin_range pins() const;

Expand Down
49 changes: 0 additions & 49 deletions vpr/src/base/read_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -666,41 +666,6 @@ struct ParseInterposerStageNetCostType {
}
};

struct ParsePlaceBoundingBox {
ConvertedValue<e_place_bounding_box_mode> from_str(const std::string& str) {
ConvertedValue<e_place_bounding_box_mode> conv_value;
if (str == "auto_bb") {
conv_value.set_value(e_place_bounding_box_mode::AUTO_BB);
} else if (str == "cube_bb") {
conv_value.set_value(e_place_bounding_box_mode::CUBE_BB);
} else if (str == "per_layer_bb") {
conv_value.set_value(e_place_bounding_box_mode::PER_LAYER_BB);
} else {
std::stringstream msg;
msg << "Invalid conversion from '" << str << "' to e_place_algorithm (expected one of: " << argparse::join(default_choices(), ", ") << ")";
conv_value.set_error(msg.str());
}
return conv_value;
}

ConvertedValue<std::string> to_str(e_place_bounding_box_mode val) {
ConvertedValue<std::string> conv_value;
if (val == e_place_bounding_box_mode::AUTO_BB) {
conv_value.set_value("auto_bb");
} else if (val == e_place_bounding_box_mode::CUBE_BB) {
conv_value.set_value("cube_bb");
} else {
VTR_ASSERT(val == e_place_bounding_box_mode::PER_LAYER_BB);
conv_value.set_value("per_layer_bb");
}
return conv_value;
}

std::vector<std::string> default_choices() {
return {"auto_bb", "cube_bb", "per_layer_bb"};
}
};

struct ParsePlacementFreq {
ConvertedValue<e_place_freq> from_str(const std::string& str) {
ConvertedValue<e_place_freq> conv_value;
Expand Down Expand Up @@ -2667,20 +2632,6 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio
.default_value("10")
.show_in(argparse::ShowIn::HELP_ONLY);

place_grp.add_argument<e_place_bounding_box_mode, ParsePlaceBoundingBox>(args.place_bounding_box_mode, "--place_bounding_box_mode")
.help(
"Specifies the type of bounding box to be used in 3D architectures.\n"
"\n"
"MODE options:\n"
" auto_bb : Automatically determine the appropriate bounding box based on the connections between layers.\n"
" cube_bb : Use 3D bounding boxes.\n"
" per_layer_bb : Use per-layer bounding boxes.\n"
"\n"
"Choose one of the available modes to define the behavior of bounding boxes in your 3D architecture. The default mode is 'automatic'.")
.default_value("auto_bb")
.choices({"auto_bb", "cube_bb", "per_layer_bb"})
.show_in(argparse::ShowIn::HELP_ONLY);

place_grp.add_argument<e_place_freq, ParsePlacementFreq>(args.place_placement_freq, "--place_frequency")
.help("Run placement every time or only once during channel width search.")
.default_value("once")
Expand Down
1 change: 0 additions & 1 deletion vpr/src/base/read_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,6 @@ struct t_options {
argparse::ArgValue<e_place_delta_delay_algorithm> place_delta_delay_matrix_calculation_method;
argparse::ArgValue<std::vector<float>> place_static_move_prob;
argparse::ArgValue<int> place_high_fanout_net;
argparse::ArgValue<e_place_bounding_box_mode> place_bounding_box_mode;
argparse::ArgValue<e_place_freq> place_placement_freq;

argparse::ArgValue<bool> RL_agent_placement;
Expand Down
1 change: 0 additions & 1 deletion vpr/src/base/setup_vpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,6 @@ static void setup_placer_opts(const t_options& Options, t_placer_opts* PlacerOpt
PlacerOpts->place_static_move_prob = vtr::vector<e_move_type, float>(Options.place_static_move_prob.value().begin(),
Options.place_static_move_prob.value().end());
PlacerOpts->place_high_fanout_net = Options.place_high_fanout_net;
PlacerOpts->place_bounding_box_mode = Options.place_bounding_box_mode;
PlacerOpts->RL_agent_placement = Options.RL_agent_placement;
PlacerOpts->place_agent_multistate = Options.place_agent_multistate;
PlacerOpts->place_checkpointing = Options.place_checkpointing;
Expand Down
41 changes: 1 addition & 40 deletions vpr/src/base/vpr_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,9 @@
#include "physical_types.h"
#include "place_constraints.h"
#include "place_macro.h"
#include "rr_graph_utils.h"
#include "vpr_types.h"
#include "vtr_memory.h"

/**
* @brief determine the type of the bounding box used by the placer to predict
* the wirelength.
*
* @param place_bb_mode The bounding box mode passed by the CLI
* @param rr_graph The routing resource graph
*/
static bool is_cube_bb(const e_place_bounding_box_mode place_bb_mode,
const RRGraphView& rr_graph);

void FloorplanningContext::update_floorplanning_context_post_pack() {
// Initialize the cluster_constraints using the constraints loaded from the
// user and clustering generated from packing.
Expand All @@ -52,14 +41,11 @@ void FloorplanningContext::clean_floorplanning_context_post_place() {
vtr::release_memory(compressed_cluster_constraints);
}

void PlacementContext::init_placement_context(const t_placer_opts& placer_opts,
const std::vector<t_direct_inf>& directs) {
void PlacementContext::init_placement_context(const std::vector<t_direct_inf>& directs) {
const AtomContext& atom_ctx = g_vpr_ctx.atom();
const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering();
const DeviceContext& device_ctx = g_vpr_ctx.device();

cube_bb = is_cube_bb(placer_opts.place_bounding_box_mode, device_ctx.rr_graph);

compressed_block_grids = create_compressed_block_grids();

// Alloc and load the placement macros.
Expand All @@ -70,31 +56,6 @@ void PlacementContext::init_placement_context(const t_placer_opts& placer_opts,
atom_ctx.lookup());
}

static bool is_cube_bb(const e_place_bounding_box_mode place_bb_mode,
const RRGraphView& rr_graph) {
bool cube_bb;
const int number_layers = g_vpr_ctx.device().grid.get_num_layers();

if (place_bb_mode == e_place_bounding_box_mode::AUTO_BB) {
// If the auto_bb is used, we analyze the RR graph to see whether is there any inter-layer connection that is not
// originated from OPIN. If there is any, cube BB is chosen, otherwise, per-layer bb is chosen.
if (number_layers > 1 && inter_layer_connections_limited_to_opin(rr_graph)) {
cube_bb = false;
} else {
cube_bb = true;
}
} else if (place_bb_mode == e_place_bounding_box_mode::CUBE_BB) {
// The user has specifically asked for CUBE_BB
cube_bb = true;
} else {
// The user has specifically asked for PER_LAYER_BB
VTR_ASSERT(place_bb_mode == e_place_bounding_box_mode::PER_LAYER_BB);
cube_bb = false;
}

return cube_bb;
}

void PlacementContext::clean_placement_context_post_place() {
// The compressed block grids are currently only used during placement.
vtr::release_memory(compressed_block_grids);
Expand Down
11 changes: 1 addition & 10 deletions vpr/src/base/vpr_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -454,13 +454,10 @@ struct PlacementContext : public Context {
* must be called before performing placement, but must be called
* after the clusters are loaded.
*
* @param placer_opts
* The options passed into the placer.
* @param directs
* A list of the direct connections in the architecture.
*/
void init_placement_context(const t_placer_opts& placer_opts,
const std::vector<t_direct_inf>& directs);
void init_placement_context(const std::vector<t_direct_inf>& directs);

/**
* @brief Clean variables from the placement context which are not used
Expand Down Expand Up @@ -560,12 +557,6 @@ struct PlacementContext : public Context {
* placer_debug_net or placer_debug_block parameters in the command line.
*/
bool f_placer_debug = false;

/**
* Set this variable to true if the type of the bounding box used in placement is of the type cube. If it is false,
* it would mean that per-layer bounding box is used. For the 2D architecture, the cube bounding box would be used.
*/
bool cube_bb = false;
};

/**
Expand Down
Loading
Loading