Hash table refactoring

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-04-14 10:14:51 +01:00
parent 2912860c97
commit 4e346ecfba
10 changed files with 53 additions and 62 deletions

View File

@ -20,6 +20,7 @@ option(EXTERNAL_CHIPDB "Create build with pre-built chipdb binaries" OFF)
option(WERROR "pass -Werror to compiler (used for CI)" OFF)
option(PROFILER "Link against libprofiler" OFF)
option(USE_IPO "Compile nextpnr with IPO" ON)
option(USE_ABSEIL "Compile nextpnr with Abseil for faster hash map" OFF)
if (USE_IPO)
if (ipo_supported)
@ -198,7 +199,7 @@ if (NOT DEFINED CURRENT_GIT_VERSION)
)
endif()
if (NOT WASI)
if (USE_ABSEIL)
add_subdirectory(3rdparty/abseil-cpp EXCLUDE_FROM_ALL)
endif()
@ -251,7 +252,10 @@ else()
endif()
set(EXTRA_LIB_DEPS)
if (USE_THREADS)
if (USE_ABSEIL)
if (NOT USE_THREADS)
message(FATAL_ERROR "Abseil without threads is not supported")
endif()
list(APPEND EXTRA_LIB_DEPS absl::flat_hash_map)
list(APPEND EXTRA_LIB_DEPS absl::flat_hash_set)
endif()
@ -332,6 +336,9 @@ foreach (family ${ARCH})
target_compile_definitions(${target} PRIVATE QT_NO_KEYWORDS)
target_link_libraries(${target} LINK_PUBLIC gui_${family} ${GUI_LIBRARY_FILES_${ufamily}})
endif()
if (USE_ABSEIL)
target_compile_definitions(${target} PRIVATE USE_ABSEIL)
endif()
if (BUILD_PYTHON)
target_link_libraries(${target} LINK_PUBLIC ${PYTHON_LIBRARIES})
if (STATIC_BUILD)

View File

@ -20,29 +20,44 @@
#ifndef HASH_TABLE_H
#define HASH_TABLE_H
#if defined(NPNR_DISABLE_THREADS)
#include <unordered_map>
#include <unordered_set>
#else
#if defined(USE_ABSEIL)
#include <absl/container/flat_hash_map.h>
#include <absl/container/flat_hash_set.h>
#else
#include <unordered_map>
#include <unordered_set>
#endif
#include <boost/functional/hash.hpp>
#include "nextpnr_namespaces.h"
NEXTPNR_NAMESPACE_BEGIN
namespace HashTables {
#if defined(NPNR_DISABLE_THREADS)
template <typename Key, typename Value> using HashMap = std::unordered_map<Key, Value>;
template <typename Value> using HashSet = std::unordered_set<Value>;
#if defined(USE_ABSEIL)
template <typename Key, typename Value, typename Hash = std::hash<Key>>
using HashMap = absl::flat_hash_map<Key, Value, Hash>;
template <typename Value, typename Hash = std::hash<Value>> using HashSet = absl::flat_hash_set<Value, Hash>;
#else
template <typename Key, typename Value> using HashMap = absl::flat_hash_map<Key, Value>;
template <typename Value> using HashSet = absl::flat_hash_set<Value>;
template <typename Key, typename Value, typename Hash = std::hash<Key>>
using HashMap = std::unordered_map<Key, Value, Hash>;
template <typename Value, typename Hash = std::hash<Value>> using HashSet = std::unordered_set<Value, Hash>;
#endif
}; // namespace HashTables
struct PairHash
{
template <typename T1, typename T2> std::size_t operator()(const std::pair<T1, T2> &idp) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, std::hash<T1>()(idp.first));
boost::hash_combine(seed, std::hash<T2>()(idp.second));
return seed;
}
};
NEXTPNR_NAMESPACE_END
#endif /* HASH_TABLE_H */

View File

@ -35,44 +35,7 @@
#include "timing.h"
#include "util.h"
namespace std {
template <> struct hash<std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, NEXTPNR_NAMESPACE_PREFIX IdString>>
{
std::size_t operator()(
const std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, NEXTPNR_NAMESPACE_PREFIX IdString> &idp) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(idp.first));
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(idp.second));
return seed;
}
};
template <> struct hash<std::pair<int, NEXTPNR_NAMESPACE_PREFIX BelId>>
{
std::size_t operator()(const std::pair<int, NEXTPNR_NAMESPACE_PREFIX BelId> &idp) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<int>()(idp.first));
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX BelId>()(idp.second));
return seed;
}
};
#if !defined(ARCH_GOWIN)
template <> struct hash<std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, NEXTPNR_NAMESPACE_PREFIX BelId>>
{
std::size_t
operator()(const std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, NEXTPNR_NAMESPACE_PREFIX BelId> &idp) const noexcept
{
std::size_t seed = 0;
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(idp.first));
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX BelId>()(idp.second));
return seed;
}
};
#endif
} // namespace std
#include "hash_table.h"
NEXTPNR_NAMESPACE_BEGIN
@ -478,9 +441,9 @@ class TimingOptimiser
// Actual BFS path optimisation algorithm
std::unordered_map<IdString, std::unordered_map<BelId, delay_t>> cumul_costs;
std::unordered_map<std::pair<IdString, BelId>, std::pair<IdString, BelId>> backtrace;
std::unordered_map<std::pair<IdString, BelId>, std::pair<IdString, BelId>, PairHash> backtrace;
std::queue<std::pair<int, BelId>> visit;
std::unordered_set<std::pair<int, BelId>> to_visit;
std::unordered_set<std::pair<int, BelId>, PairHash> to_visit;
for (auto startbel : cell_neighbour_bels[path_cells.front()]) {
// Swap for legality check
@ -609,7 +572,7 @@ class TimingOptimiser
std::unordered_map<IdString, std::unordered_set<BelId>> cell_neighbour_bels;
std::unordered_map<BelId, std::unordered_set<IdString>> bel_candidate_cells;
// Map cell ports to net delay limit
std::unordered_map<std::pair<IdString, IdString>, delay_t> max_net_delay;
std::unordered_map<std::pair<IdString, IdString>, delay_t, PairHash> max_net_delay;
Context *ctx;
TimingOptCfg cfg;
TimingAnalyser tmg;

View File

@ -42,7 +42,7 @@ struct CellParameters
bool compare_property(const Context *ctx, IdString cell_type, IdString parameter, const Property &property,
IdString value_to_compare) const;
HashTables::HashMap<std::pair<IdString, IdString>, const CellParameterPOD *> parameters;
HashTables::HashMap<std::pair<IdString, IdString>, const CellParameterPOD *, PairHash> parameters;
std::regex verilog_binary_re;
std::regex verilog_hex_re;

View File

@ -121,7 +121,7 @@ delay_t CostMap::get_delay(const Context *ctx, WireId src_wire, WireId dst_wire)
}
void CostMap::set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
const HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t> &delays)
const HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash> &delays)
{
CostMapEntry delay_matrix;

View File

@ -39,7 +39,7 @@ class CostMap
public:
delay_t get_delay(const Context *ctx, WireId src, WireId dst) const;
void set_cost_map(const Context *ctx, const TypeWirePair &wire_pair,
const HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t> &delays);
const HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash> &delays);
void from_reader(lookahead_storage::CostMap::Reader reader);
void to_builder(lookahead_storage::CostMap::Builder builder) const;

View File

@ -250,7 +250,7 @@ static void expand_input_type(const Context *ctx, DeterministicRNG *rng, const S
struct DelayStorage
{
HashTables::HashMap<TypeWirePair, HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t>> storage;
HashTables::HashMap<TypeWirePair, HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash>> storage;
int32_t max_explore_depth;
};
@ -996,7 +996,8 @@ void Lookahead::build_lookahead(const Context *ctx, DeterministicRNG *rng)
#if defined(NEXTPNR_USE_TBB) // Run parallely
tbb::parallel_for_each(
all_tiles_storage.storage,
[&](const std::pair<TypeWirePair, HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t>> &type_pair) {
[&](const std::pair<TypeWirePair, HashTables::HashMap<std::pair<int32_t, int32_t>, delay_t, PairHash>>
&type_pair) {
#else
for (const auto &type_pair : all_tiles_storage.storage) {
#endif

View File

@ -98,7 +98,7 @@ struct PseudoPipData
const std::vector<PseudoPipBel> &get_logic_bels_for_pip(const Context *ctx, int32_t site, PipId pip) const;
HashTables::HashMap<int32_t, size_t> max_pseudo_pip_for_tile_type;
HashTables::HashMap<std::pair<int32_t, int32_t>, std::vector<size_t>> possibles_sites_for_pip;
HashTables::HashMap<std::pair<int32_t, int32_t>, std::vector<size_t>, PairHash> possibles_sites_for_pip;
HashTables::HashMap<LogicBelKey, std::vector<PseudoPipBel>> logic_bels_for_pip;
};

View File

@ -988,7 +988,7 @@ static void apply_routing(Context *ctx, const SiteArch &site_arch)
}
static bool map_luts_in_site(const SiteInformation &site_info,
HashTables::HashSet<std::pair<IdString, IdString>> *blocked_wires)
HashTables::HashSet<std::pair<IdString, IdString>, PairHash> *blocked_wires)
{
const Context *ctx = site_info.ctx;
const std::vector<LutElement> &lut_elements = ctx->lut_elements.at(site_info.tile_type);
@ -1031,7 +1031,7 @@ static bool map_luts_in_site(const SiteInformation &site_info,
// Block outputs of unavailable LUTs to prevent site router from using them.
static void block_lut_outputs(SiteArch *site_arch,
const HashTables::HashSet<std::pair<IdString, IdString>> &blocked_wires)
const HashTables::HashSet<std::pair<IdString, IdString>, PairHash> &blocked_wires)
{
const Context *ctx = site_arch->site_info->ctx;
auto &tile_info = ctx->chip_info->tile_types[site_arch->site_info->tile_type];
@ -1112,7 +1112,7 @@ bool SiteRouter::checkSiteRouting(const Context *ctx, const TileStatus &tile_sta
}
SiteInformation site_info(ctx, tile, site, cells_in_site);
HashTables::HashSet<std::pair<IdString, IdString>> blocked_wires;
HashTables::HashSet<std::pair<IdString, IdString>, PairHash> blocked_wires;
if (!map_luts_in_site(site_info, &blocked_wires)) {
site_ok = false;
return site_ok;
@ -1190,7 +1190,7 @@ void SiteRouter::bindSiteRouting(Context *ctx)
}
SiteInformation site_info(ctx, tile, site, cells_in_site);
HashTables::HashSet<std::pair<IdString, IdString>> blocked_wires;
HashTables::HashSet<std::pair<IdString, IdString>, PairHash> blocked_wires;
NPNR_ASSERT(map_luts_in_site(site_info, &blocked_wires));
SiteArch site_arch(&site_info);

View File

@ -39,6 +39,11 @@ if (BUILD_PYTHON)
endif()
target_compile_definitions(gui_${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family} QT_NO_KEYWORDS)
if (USE_ABSEIL)
target_compile_definitions(gui_${family} PRIVATE USE_ABSEIL)
endif()
target_link_libraries(gui_${family} Qt5::Widgets)
foreach(lib_dep ${EXTRA_LIB_DEPS})