diff options
Diffstat (limited to 'common')
-rw-r--r-- | common/archcheck.cc | 18 | ||||
-rw-r--r-- | common/base_arch.h | 18 | ||||
-rw-r--r-- | common/basectx.h | 27 | ||||
-rw-r--r-- | common/chain_utils.h | 4 | ||||
-rw-r--r-- | common/command.cc | 4 | ||||
-rw-r--r-- | common/command.h | 2 | ||||
-rw-r--r-- | common/constraints.h | 4 | ||||
-rw-r--r-- | common/context.cc | 4 | ||||
-rw-r--r-- | common/context.h | 2 | ||||
-rw-r--r-- | common/fast_bels.h | 4 | ||||
-rw-r--r-- | common/hash_table.h | 63 | ||||
-rw-r--r-- | common/hashlib.h | 1196 | ||||
-rw-r--r-- | common/idstring.h | 12 | ||||
-rw-r--r-- | common/idstringlist.h | 21 | ||||
-rw-r--r-- | common/log.cc | 2 | ||||
-rw-r--r-- | common/log.h | 20 | ||||
-rw-r--r-- | common/nextpnr_base_types.h | 17 | ||||
-rw-r--r-- | common/nextpnr_types.h | 23 | ||||
-rw-r--r-- | common/place_common.cc | 24 | ||||
-rw-r--r-- | common/placer1.cc | 63 | ||||
-rw-r--r-- | common/placer_heap.cc | 85 | ||||
-rw-r--r-- | common/placer_heap.h | 4 | ||||
-rw-r--r-- | common/pybindings.cc | 14 | ||||
-rw-r--r-- | common/router1.cc | 63 | ||||
-rw-r--r-- | common/router2.cc | 19 | ||||
-rw-r--r-- | common/sdf.cc | 8 | ||||
-rw-r--r-- | common/timing.cc | 61 | ||||
-rw-r--r-- | common/timing.h | 61 | ||||
-rw-r--r-- | common/timing_opt.cc | 24 | ||||
-rw-r--r-- | common/timing_opt.h | 2 | ||||
-rw-r--r-- | common/util.h | 41 |
31 files changed, 1451 insertions, 459 deletions
diff --git a/common/archcheck.cc b/common/archcheck.cc index f46db95c..89a61007 100644 --- a/common/archcheck.cc +++ b/common/archcheck.cc @@ -108,7 +108,7 @@ void archcheck_locs(const Context *ctx) for (int x = 0; x < ctx->getGridDimX(); x++) for (int y = 0; y < ctx->getGridDimY(); y++) { dbg("> %d %d\n", x, y); - std::unordered_set<int> usedz; + pool<int> usedz; for (int z = 0; z < ctx->getTileBelDimZ(x, y); z++) { BelId bel = ctx->getBelByLocation(Loc(x, y, z)); @@ -162,10 +162,10 @@ struct LruWireCacheMap // list is oldest wire in cache. std::list<WireId> last_access_list; // Quick wire -> list element lookup. - std::unordered_map<WireId, std::list<WireId>::iterator> last_access_map; + dict<WireId, std::list<WireId>::iterator> last_access_map; - std::unordered_map<PipId, WireId> pips_downhill; - std::unordered_map<PipId, WireId> pips_uphill; + dict<PipId, WireId> pips_downhill; + dict<PipId, WireId> pips_uphill; void removeWireFromCache(WireId wire_to_remove) { @@ -255,8 +255,8 @@ void archcheck_conn(const Context *ctx) log_info("Checking all wires...\n"); #ifndef USING_LRU_CACHE - std::unordered_map<PipId, WireId> pips_downhill; - std::unordered_map<PipId, WireId> pips_uphill; + dict<PipId, WireId> pips_downhill; + dict<PipId, WireId> pips_uphill; #endif for (WireId wire : ctx->getWires()) { @@ -347,7 +347,7 @@ void archcheck_buckets(const Context *ctx) for (BelBucketId bucket : ctx->getBelBuckets()) { // Find out which cell types are in this bucket. - std::unordered_set<IdString> cell_types_in_bucket; + pool<IdString> cell_types_in_bucket; for (IdString cell_type : ctx->getCellTypes()) { if (ctx->getBelBucketForCellType(cell_type) == bucket) { cell_types_in_bucket.insert(cell_type); @@ -356,9 +356,9 @@ void archcheck_buckets(const Context *ctx) // Make sure that all cell types in this bucket have at least one // BelId they can be placed at. - std::unordered_set<IdString> cell_types_unused; + pool<IdString> cell_types_unused; - std::unordered_set<BelId> bels_in_bucket; + pool<BelId> bels_in_bucket; for (BelId bel : ctx->getBelsInBucket(bucket)) { BelBucketId bucket2 = ctx->getBelBucketForBel(bel); log_assert(bucket == bucket2); diff --git a/common/base_arch.h b/common/base_arch.h index fbafee99..457e6582 100644 --- a/common/base_arch.h +++ b/common/base_arch.h @@ -148,7 +148,7 @@ template <typename R> struct BaseArch : ArchAPI<R> virtual char getNameDelimiter() const override { return ' '; } // Bel methods - virtual uint32_t getBelChecksum(BelId bel) const override { return uint32_t(std::hash<BelId>()(bel)); } + virtual uint32_t getBelChecksum(BelId bel) const override { return bel.hash(); } virtual void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) override { NPNR_ASSERT(bel != BelId()); @@ -196,7 +196,7 @@ template <typename R> struct BaseArch : ArchAPI<R> { return empty_if_possible<typename R::WireAttrsRangeT>(); } - virtual uint32_t getWireChecksum(WireId wire) const override { return uint32_t(std::hash<WireId>()(wire)); } + virtual uint32_t getWireChecksum(WireId wire) const override { return wire.hash(); } virtual void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) override { @@ -244,7 +244,7 @@ template <typename R> struct BaseArch : ArchAPI<R> { return empty_if_possible<typename R::PipAttrsRangeT>(); } - virtual uint32_t getPipChecksum(PipId pip) const override { return uint32_t(std::hash<PipId>()(pip)); } + virtual uint32_t getPipChecksum(PipId pip) const override { return pip.hash(); } virtual void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) override { NPNR_ASSERT(pip != PipId()); @@ -441,23 +441,23 @@ template <typename R> struct BaseArch : ArchAPI<R> // -------------------------------------------------------------- // These structures are used to provide default implementations of bel/wire/pip binding. Arches might want to - // replace them with their own, for example to use faster access structures than unordered_map. Arches might also + // replace them with their own, for example to use faster access structures than dict. Arches might also // want to add extra checks around these functions - std::unordered_map<BelId, CellInfo *> base_bel2cell; - std::unordered_map<WireId, NetInfo *> base_wire2net; - std::unordered_map<PipId, NetInfo *> base_pip2net; + dict<BelId, CellInfo *> base_bel2cell; + dict<WireId, NetInfo *> base_wire2net; + dict<PipId, NetInfo *> base_pip2net; // For the default cell/bel bucket implementations std::vector<IdString> cell_types; std::vector<BelBucketId> bel_buckets; - std::unordered_map<BelBucketId, std::vector<BelId>> bucket_bels; + dict<BelBucketId, std::vector<BelId>> bucket_bels; // Arches that want to use the default cell types and bel buckets *must* call these functions in their constructor bool cell_types_initialised = false; bool bel_buckets_initialised = false; void init_cell_types() { - std::unordered_set<IdString> bel_types; + pool<IdString> bel_types; for (auto bel : this->getBels()) bel_types.insert(this->getBelType(bel)); std::copy(bel_types.begin(), bel_types.end(), std::back_inserter(cell_types)); diff --git a/common/basectx.h b/common/basectx.h index fccd12af..12f63f98 100644 --- a/common/basectx.h +++ b/common/basectx.h @@ -28,6 +28,7 @@ #include <boost/thread.hpp> #endif +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" #include "nextpnr_types.h" @@ -59,29 +60,29 @@ struct BaseCtx mutable StrRingBuffer log_strs; // Project settings and config switches - std::unordered_map<IdString, Property> settings; + dict<IdString, Property> settings; // Placed nets and cells. - std::unordered_map<IdString, std::unique_ptr<NetInfo>> nets; - std::unordered_map<IdString, std::unique_ptr<CellInfo>> cells; + dict<IdString, std::unique_ptr<NetInfo>> nets; + dict<IdString, std::unique_ptr<CellInfo>> cells; // Hierarchical (non-leaf) cells by full path - std::unordered_map<IdString, HierarchicalCell> hierarchy; + dict<IdString, HierarchicalCell> hierarchy; // This is the root of the above structure IdString top_module; // Aliases for nets, which may have more than one name due to assignments and hierarchy - std::unordered_map<IdString, IdString> net_aliases; + dict<IdString, IdString> net_aliases; // Top-level ports - std::unordered_map<IdString, PortInfo> ports; - std::unordered_map<IdString, CellInfo *> port_cells; + dict<IdString, PortInfo> ports; + dict<IdString, CellInfo *> port_cells; // Floorplanning regions - std::unordered_map<IdString, std::unique_ptr<Region>> region; + dict<IdString, std::unique_ptr<Region>> region; // Context meta data - std::unordered_map<IdString, Property> attrs; + dict<IdString, Property> attrs; Context *as_ctx = nullptr; @@ -186,10 +187,10 @@ struct BaseCtx bool allUiReload = true; bool frameUiReload = false; - std::unordered_set<BelId> belUiReload; - std::unordered_set<WireId> wireUiReload; - std::unordered_set<PipId> pipUiReload; - std::unordered_set<GroupId> groupUiReload; + pool<BelId> belUiReload; + pool<WireId> wireUiReload; + pool<PipId> pipUiReload; + pool<GroupId> groupUiReload; void refreshUi() { allUiReload = true; } diff --git a/common/chain_utils.h b/common/chain_utils.h index 300d96a1..1bd95c9e 100644 --- a/common/chain_utils.h +++ b/common/chain_utils.h @@ -37,10 +37,10 @@ std::vector<CellChain> find_chains(const Context *ctx, F1 cell_type_predicate, F { std::set<IdString> chained; std::vector<CellChain> chains; - for (auto cell : sorted(ctx->cells)) { + for (auto &cell : ctx->cells) { if (chained.find(cell.first) != chained.end()) continue; - CellInfo *ci = cell.second; + CellInfo *ci = cell.second.get(); if (cell_type_predicate(ctx, ci)) { CellInfo *start = ci; CellInfo *prev_start = ci; diff --git a/common/command.cc b/common/command.cc index f48d6adf..27e59260 100644 --- a/common/command.cc +++ b/common/command.cc @@ -458,7 +458,7 @@ int CommandHandler::exec() if (executeBeforeContext()) return 0; - std::unordered_map<std::string, Property> values; + dict<std::string, Property> values; std::unique_ptr<Context> ctx = createContext(values); setupContext(ctx.get()); setupArchContext(ctx.get()); @@ -475,7 +475,7 @@ int CommandHandler::exec() std::unique_ptr<Context> CommandHandler::load_json(std::string filename) { - std::unordered_map<std::string, Property> values; + dict<std::string, Property> values; std::unique_ptr<Context> ctx = createContext(values); setupContext(ctx.get()); setupArchContext(ctx.get()); diff --git a/common/command.h b/common/command.h index 36b6d8ab..ba606ea2 100644 --- a/common/command.h +++ b/common/command.h @@ -42,7 +42,7 @@ class CommandHandler protected: virtual void setupArchContext(Context *ctx) = 0; - virtual std::unique_ptr<Context> createContext(std::unordered_map<std::string, Property> &values) = 0; + virtual std::unique_ptr<Context> createContext(dict<std::string, Property> &values) = 0; virtual po::options_description getArchOptions() = 0; virtual void validate(){}; virtual void customAfterLoad(Context *ctx){}; diff --git a/common/constraints.h b/common/constraints.h index 9ec8372d..65abf12c 100644 --- a/common/constraints.h +++ b/common/constraints.h @@ -21,11 +21,11 @@ #define CONSTRAINTS_H #include <cstdint> -#include <unordered_map> #include <vector> #include "archdefs.h" #include "exclusive_state_groups.h" +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" @@ -53,7 +53,7 @@ template <std::size_t StateCount, typename StateType = int8_t, typename CountTyp }; typedef ExclusiveStateGroup<StateCount, StateType, CountType> TagState; - std::unordered_map<uint32_t, std::vector<typename TagState::Definition>> definitions; + dict<uint32_t, std::vector<typename TagState::Definition>> definitions; template <typename ConstraintRange> void bindBel(TagState *tags, const ConstraintRange constraints); diff --git a/common/context.cc b/common/context.cc index 05c1e094..115b333a 100644 --- a/common/context.cc +++ b/common/context.cc @@ -389,8 +389,8 @@ struct FixupHierarchyWorker // Update hierarchy structure for nets and cells that have hiercell set void rebuild_hierarchy() { - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); if (ci->hierpath == IdString()) ci->hierpath = ctx->top_module; auto &hc = ctx->hierarchy.at(ci->hierpath); diff --git a/common/context.h b/common/context.h index a5553422..102dc221 100644 --- a/common/context.h +++ b/common/context.h @@ -50,7 +50,7 @@ struct Context : Arch, DeterministicRNG // provided by router1.cc bool checkRoutedDesign() const; bool getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay = nullptr, - std::unordered_map<WireId, PipId> *route = nullptr, bool useEstimate = true); + dict<WireId, PipId> *route = nullptr, bool useEstimate = true); // -------------------------------------------------------------- // call after changing hierpath or adding/removing nets and cells diff --git a/common/fast_bels.h b/common/fast_bels.h index 0425f92a..b49c4c6c 100644 --- a/common/fast_bels.h +++ b/common/fast_bels.h @@ -178,10 +178,10 @@ struct FastBels const bool check_bel_available; const int minBelsForGridPick; - std::unordered_map<IdString, TypeData> cell_types; + dict<IdString, TypeData> cell_types; std::vector<std::unique_ptr<FastBelsData>> fast_bels_by_cell_type; - std::unordered_map<BelBucketId, TypeData> partition_types; + dict<BelBucketId, TypeData> partition_types; std::vector<std::unique_ptr<FastBelsData>> fast_bels_by_partition_type; }; diff --git a/common/hash_table.h b/common/hash_table.h deleted file mode 100644 index 21ca8887..00000000 --- a/common/hash_table.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2021 Symbiflow Authors - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#ifndef HASH_TABLE_H -#define HASH_TABLE_H - -#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(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, 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 */ diff --git a/common/hashlib.h b/common/hashlib.h new file mode 100644 index 00000000..063df78f --- /dev/null +++ b/common/hashlib.h @@ -0,0 +1,1196 @@ +// This is free and unencumbered software released into the public domain. +// +// Anyone is free to copy, modify, publish, use, compile, sell, or +// distribute this software, either in source code form or as a compiled +// binary, for any purpose, commercial or non-commercial, and by any +// means. + +// ------------------------------------------------------- +// Written by Claire Xen <claire@clairexen.net> in 2014 +// ------------------------------------------------------- + +#ifndef HASHLIB_H +#define HASHLIB_H + +#include <algorithm> +#include <stdexcept> +#include <string> +#include <vector> + +#include "nextpnr_assertions.h" +#include "nextpnr_namespaces.h" + +NEXTPNR_NAMESPACE_BEGIN + +const int hashtable_size_trigger = 2; +const int hashtable_size_factor = 3; + +// The XOR version of DJB2 +inline unsigned int mkhash(unsigned int a, unsigned int b) { return ((a << 5) + a) ^ b; } + +// traditionally 5381 is used as starting value for the djb2 hash +const unsigned int mkhash_init = 5381; + +// The ADD version of DJB2 +// (use this version for cache locality in b) +inline unsigned int mkhash_add(unsigned int a, unsigned int b) { return ((a << 5) + a) + b; } + +inline unsigned int mkhash_xorshift(unsigned int a) +{ + if (sizeof(a) == 4) { + a ^= a << 13; + a ^= a >> 17; + a ^= a << 5; + } else if (sizeof(a) == 8) { + a ^= a << 13; + a ^= a >> 7; + a ^= a << 17; + } else + NPNR_ASSERT_FALSE("mkhash_xorshift() only implemented for 32 bit and 64 bit ints"); + return a; +} + +template <typename T> struct hash_ops +{ + static inline bool cmp(const T &a, const T &b) { return a == b; } + static inline unsigned int hash(const T &a) { return a.hash(); } +}; + +struct hash_int_ops +{ + template <typename T> static inline bool cmp(T a, T b) { return a == b; } +}; + +template <> struct hash_ops<bool> : hash_int_ops +{ + static inline unsigned int hash(bool a) { return a ? 1 : 0; } +}; +template <> struct hash_ops<int32_t> : hash_int_ops +{ + static inline unsigned int hash(int32_t a) { return a; } +}; +template <> struct hash_ops<int64_t> : hash_int_ops +{ + static inline unsigned int hash(int64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); } +}; + +template <> struct hash_ops<uint32_t> : hash_int_ops +{ + static inline unsigned int hash(uint32_t a) { return a; } +}; +template <> struct hash_ops<uint64_t> : hash_int_ops +{ + static inline unsigned int hash(uint64_t a) { return mkhash((unsigned int)(a), (unsigned int)(a >> 32)); } +}; + +template <> struct hash_ops<std::string> +{ + static inline bool cmp(const std::string &a, const std::string &b) { return a == b; } + static inline unsigned int hash(const std::string &a) + { + unsigned int v = 0; + for (auto c : a) + v = mkhash(v, c); + return v; + } +}; + +template <typename P, typename Q> struct hash_ops<std::pair<P, Q>> +{ + static inline bool cmp(std::pair<P, Q> a, std::pair<P, Q> b) { return a == b; } + static inline unsigned int hash(std::pair<P, Q> a) + { + return mkhash(hash_ops<P>::hash(a.first), hash_ops<Q>::hash(a.second)); + } +}; + +template <typename... T> struct hash_ops<std::tuple<T...>> +{ + static inline bool cmp(std::tuple<T...> a, std::tuple<T...> b) { return a == b; } + template <size_t I = 0> + static inline typename std::enable_if<I == sizeof...(T), unsigned int>::type hash(std::tuple<T...>) + { + return mkhash_init; + } + template <size_t I = 0> + static inline typename std::enable_if<I != sizeof...(T), unsigned int>::type hash(std::tuple<T...> a) + { + typedef hash_ops<typename std::tuple_element<I, std::tuple<T...>>::type> element_ops_t; + return mkhash(hash<I + 1>(a), element_ops_t::hash(std::get<I>(a))); + } +}; + +template <typename T> struct hash_ops<std::vector<T>> +{ + static inline bool cmp(std::vector<T> a, std::vector<T> b) { return a == b; } + static inline unsigned int hash(std::vector<T> a) + { + unsigned int h = mkhash_init; + for (auto k : a) + h = mkhash(h, hash_ops<T>::hash(k)); + return h; + } +}; + +struct hash_cstr_ops +{ + static inline bool cmp(const char *a, const char *b) + { + for (int i = 0; a[i] || b[i]; i++) + if (a[i] != b[i]) + return false; + return true; + } + static inline unsigned int hash(const char *a) + { + unsigned int hash = mkhash_init; + while (*a) + hash = mkhash(hash, *(a++)); + return hash; + } +}; + +struct hash_ptr_ops +{ + static inline bool cmp(const void *a, const void *b) { return a == b; } + static inline unsigned int hash(const void *a) { return (uintptr_t)a; } +}; + +struct hash_obj_ops +{ + static inline bool cmp(const void *a, const void *b) { return a == b; } + template <typename T> static inline unsigned int hash(const T *a) { return a ? a->hash() : 0; } +}; + +template <typename T> inline unsigned int mkhash(const T &v) { return hash_ops<T>().hash(v); } + +inline int hashtable_size(int min_size) +{ + static std::vector<int> zero_and_some_primes = { + 0, 23, 29, 37, 47, 59, 79, 101, 127, 163, + 211, 269, 337, 431, 541, 677, 853, 1069, 1361, 1709, + 2137, 2677, 3347, 4201, 5261, 6577, 8231, 10289, 12889, 16127, + 20161, 25219, 31531, 39419, 49277, 61603, 77017, 96281, 120371, 150473, + 188107, 235159, 293957, 367453, 459317, 574157, 717697, 897133, 1121423, 1401791, + 1752239, 2190299, 2737937, 3422429, 4278037, 5347553, 6684443, 8355563, 10444457, 13055587, + 16319519, 20399411, 25499291, 31874149, 39842687, 49803361, 62254207, 77817767, 97272239, 121590311, + 151987889, 189984863, 237481091, 296851369, 371064217}; + + for (auto p : zero_and_some_primes) + if (p >= min_size) + return p; + + if (sizeof(int) == 4) + throw std::length_error("hash table exceeded maximum size. use a ILP64 abi for larger tables."); + + for (auto p : zero_and_some_primes) + if (100129 * p > min_size) + return 100129 * p; + + throw std::length_error("hash table exceeded maximum size."); +} + +template <typename K, typename T, typename OPS = hash_ops<K>> class dict; +template <typename K, int offset = 0, typename OPS = hash_ops<K>> class idict; +template <typename K, typename OPS = hash_ops<K>> class pool; +template <typename K, typename OPS = hash_ops<K>> class mfp; + +template <typename K, typename T, typename OPS> class dict +{ + struct entry_t + { + std::pair<K, T> udata; + int next; + + entry_t() {} + entry_t(const std::pair<K, T> &udata, int next) : udata(udata), next(next) {} + entry_t(std::pair<K, T> &&udata, int next) : udata(std::move(udata)), next(next) {} + bool operator<(const entry_t &other) const { return udata.first < other.udata.first; } + }; + + std::vector<int> hashtable; + std::vector<entry_t> entries; + OPS ops; + +#ifdef NDEBUG + static inline void do_assert(bool) {} +#else + static inline void do_assert(bool cond) { NPNR_ASSERT(cond); } +#endif + + int do_hash(const K &key) const + { + unsigned int hash = 0; + if (!hashtable.empty()) + hash = ops.hash(key) % (unsigned int)(hashtable.size()); + return hash; + } + + void do_rehash() + { + hashtable.clear(); + hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1); + + for (int i = 0; i < int(entries.size()); i++) { + do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); + int hash = do_hash(entries[i].udata.first); + entries[i].next = hashtable[hash]; + hashtable[hash] = i; + } + } + + int do_erase(int index, int hash) + { + do_assert(index < int(entries.size())); + if (hashtable.empty() || index < 0) + return 0; + + int k = hashtable[hash]; + do_assert(0 <= k && k < int(entries.size())); + + if (k == index) { + hashtable[hash] = entries[index].next; + } else { + while (entries[k].next != index) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = entries[index].next; + } + + int back_idx = entries.size() - 1; + + if (index != back_idx) { + int back_hash = do_hash(entries[back_idx].udata.first); + + k = hashtable[back_hash]; + do_assert(0 <= k && k < int(entries.size())); + + if (k == back_idx) { + hashtable[back_hash] = index; + } else { + while (entries[k].next != back_idx) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = index; + } + + entries[index] = std::move(entries[back_idx]); + } + + entries.pop_back(); + + if (entries.empty()) + hashtable.clear(); + + return 1; + } + + int do_lookup(const K &key, int &hash) const + { + if (hashtable.empty()) + return -1; + + if (entries.size() * hashtable_size_trigger > hashtable.size()) { + ((dict *)this)->do_rehash(); + hash = do_hash(key); + } + + int index = hashtable[hash]; + + while (index >= 0 && !ops.cmp(entries[index].udata.first, key)) { + index = entries[index].next; + do_assert(-1 <= index && index < int(entries.size())); + } + + return index; + } + + int do_insert(const K &key, int &hash) + { + if (hashtable.empty()) { + entries.emplace_back(std::pair<K, T>(key, T()), -1); + do_rehash(); + hash = do_hash(key); + } else { + entries.emplace_back(std::pair<K, T>(key, T()), hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + int do_insert(const std::pair<K, T> &value, int &hash) + { + if (hashtable.empty()) { + entries.emplace_back(value, -1); + do_rehash(); + hash = do_hash(value.first); + } else { + entries.emplace_back(value, hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + int do_insert(std::pair<K, T> &&rvalue, int &hash) + { + if (hashtable.empty()) { + auto key = rvalue.first; + entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), -1); + do_rehash(); + hash = do_hash(key); + } else { + entries.emplace_back(std::forward<std::pair<K, T>>(rvalue), hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + public: + using key_type = K; + using mapped_type = T; + using value_type = std::pair<K, T>; + + class const_iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>> + { + friend class dict; + + protected: + const dict *ptr; + int index; + const_iterator(const dict *ptr, int index) : ptr(ptr), index(index) {} + + public: + const_iterator() {} + const_iterator operator++() + { + index--; + return *this; + } + const_iterator operator+=(int amt) + { + index -= amt; + return *this; + } + bool operator<(const const_iterator &other) const { return index > other.index; } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; } + const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; } + }; + + class iterator : public std::iterator<std::forward_iterator_tag, std::pair<K, T>> + { + friend class dict; + + protected: + dict *ptr; + int index; + iterator(dict *ptr, int index) : ptr(ptr), index(index) {} + + public: + iterator() {} + iterator operator++() + { + index--; + return *this; + } + iterator operator+=(int amt) + { + index -= amt; + return *this; + } + bool operator<(const iterator &other) const { return index > other.index; } + bool operator==(const iterator &other) const { return index == other.index; } + bool operator!=(const iterator &other) const { return index != other.index; } + std::pair<K, T> &operator*() { return ptr->entries[index].udata; } + std::pair<K, T> *operator->() { return &ptr->entries[index].udata; } + const std::pair<K, T> &operator*() const { return ptr->entries[index].udata; } + const std::pair<K, T> *operator->() const { return &ptr->entries[index].udata; } + operator const_iterator() const { return const_iterator(ptr, index); } + }; + + dict() {} + + dict(const dict &other) + { + entries = other.entries; + do_rehash(); + } + + dict(dict &&other) { swap(other); } + + dict &operator=(const dict &other) + { + entries = other.entries; + do_rehash(); + return *this; + } + + dict &operator=(dict &&other) + { + clear(); + swap(other); + return *this; + } + + dict(const std::initializer_list<std::pair<K, T>> &list) + { + for (auto &it : list) + insert(it); + } + + template <class InputIterator> dict(InputIterator first, InputIterator last) { insert(first, last); } + + template <class InputIterator> void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair<iterator, bool> insert(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(key, hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> insert(const std::pair<K, T> &value) + { + int hash = do_hash(value.first); + int i = do_lookup(value.first, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(value, hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> insert(std::pair<K, T> &&rvalue) + { + int hash = do_hash(rvalue.first); + int i = do_lookup(rvalue.first, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(std::forward<std::pair<K, T>>(rvalue), hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> emplace(K const &key, T const &value) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(std::make_pair(key, value), hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> emplace(K const &key, T &&rvalue) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(std::make_pair(key, std::forward<T>(rvalue)), hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> emplace(K &&rkey, T const &value) + { + int hash = do_hash(rkey); + int i = do_lookup(rkey, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(std::make_pair(std::forward<K>(rkey), value), hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> emplace(K &&rkey, T &&rvalue) + { + int hash = do_hash(rkey); + int i = do_lookup(rkey, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(std::make_pair(std::forward<K>(rkey), std::forward<T>(rvalue)), hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + int erase(const K &key) + { + int hash = do_hash(key); + int index = do_lookup(key, hash); + return do_erase(index, hash); + } + + iterator erase(iterator it) + { + int hash = do_hash(it->first); + do_erase(it.index, hash); + return ++it; + } + + int count(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 ? 0 : 1; + } + + int count(const K &key, const_iterator it) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 || i > it.index ? 0 : 1; + } + + iterator find(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return iterator(this, i); + } + + const_iterator find(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return const_iterator(this, i); + } + + T &at(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + + const T &at(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + throw std::out_of_range("dict::at()"); + return entries[i].udata.second; + } + + const T &at(const K &key, const T &defval) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return defval; + return entries[i].udata.second; + } + + T &operator[](const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + i = do_insert(std::pair<K, T>(key, T()), hash); + return entries[i].udata.second; + } + + template <typename Compare = std::less<K>> void sort(Compare comp = Compare()) + { + std::sort(entries.begin(), entries.end(), + [comp](const entry_t &a, const entry_t &b) { return comp(b.udata.first, a.udata.first); }); + do_rehash(); + } + + void swap(dict &other) + { + hashtable.swap(other.hashtable); + entries.swap(other.entries); + } + + bool operator==(const dict &other) const + { + if (size() != other.size()) + return false; + for (auto &it : entries) { + auto oit = other.find(it.udata.first); + if (oit == other.end() || !(oit->second == it.udata.second)) + return false; + } + return true; + } + + bool operator!=(const dict &other) const { return !operator==(other); } + + unsigned int hash() const + { + unsigned int h = mkhash_init; + for (auto &entry : entries) { + h ^= hash_ops<K>::hash(entry.udata.first); + h ^= hash_ops<T>::hash(entry.udata.second); + } + return h; + } + + void reserve(size_t n) { entries.reserve(n); } + size_t size() const { return entries.size(); } + bool empty() const { return entries.empty(); } + void clear() + { + hashtable.clear(); + entries.clear(); + } + + iterator begin() { return iterator(this, int(entries.size()) - 1); } + iterator element(int n) { return iterator(this, int(entries.size()) - 1 - n); } + iterator end() { return iterator(nullptr, -1); } + + const_iterator begin() const { return const_iterator(this, int(entries.size()) - 1); } + const_iterator element(int n) const { return const_iterator(this, int(entries.size()) - 1 - n); } + const_iterator end() const { return const_iterator(nullptr, -1); } +}; + +template <typename K, typename OPS> class pool +{ + template <typename, int, typename> friend class idict; + + protected: + struct entry_t + { + K udata; + int next; + + entry_t() {} + entry_t(const K &udata, int next) : udata(udata), next(next) {} + entry_t(K &&udata, int next) : udata(std::move(udata)), next(next) {} + }; + + std::vector<int> hashtable; + std::vector<entry_t> entries; + OPS ops; + +#ifdef NDEBUG + static inline void do_assert(bool) {} +#else + static inline void do_assert(bool cond) { NPNR_ASSERT(cond); } +#endif + + int do_hash(const K &key) const + { + unsigned int hash = 0; + if (!hashtable.empty()) + hash = ops.hash(key) % (unsigned int)(hashtable.size()); + return hash; + } + + void do_rehash() + { + hashtable.clear(); + hashtable.resize(hashtable_size(entries.capacity() * hashtable_size_factor), -1); + + for (int i = 0; i < int(entries.size()); i++) { + do_assert(-1 <= entries[i].next && entries[i].next < int(entries.size())); + int hash = do_hash(entries[i].udata); + entries[i].next = hashtable[hash]; + hashtable[hash] = i; + } + } + + int do_erase(int index, int hash) + { + do_assert(index < int(entries.size())); + if (hashtable.empty() || index < 0) + return 0; + + int k = hashtable[hash]; + if (k == index) { + hashtable[hash] = entries[index].next; + } else { + while (entries[k].next != index) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = entries[index].next; + } + + int back_idx = entries.size() - 1; + + if (index != back_idx) { + int back_hash = do_hash(entries[back_idx].udata); + + k = hashtable[back_hash]; + if (k == back_idx) { + hashtable[back_hash] = index; + } else { + while (entries[k].next != back_idx) { + k = entries[k].next; + do_assert(0 <= k && k < int(entries.size())); + } + entries[k].next = index; + } + + entries[index] = std::move(entries[back_idx]); + } + + entries.pop_back(); + + if (entries.empty()) + hashtable.clear(); + + return 1; + } + + int do_lookup(const K &key, int &hash) const + { + if (hashtable.empty()) + return -1; + + if (entries.size() * hashtable_size_trigger > hashtable.size()) { + ((pool *)this)->do_rehash(); + hash = do_hash(key); + } + + int index = hashtable[hash]; + + while (index >= 0 && !ops.cmp(entries[index].udata, key)) { + index = entries[index].next; + do_assert(-1 <= index && index < int(entries.size())); + } + + return index; + } + + int do_insert(const K &value, int &hash) + { + if (hashtable.empty()) { + entries.emplace_back(value, -1); + do_rehash(); + hash = do_hash(value); + } else { + entries.emplace_back(value, hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + int do_insert(K &&rvalue, int &hash) + { + if (hashtable.empty()) { + entries.emplace_back(std::forward<K>(rvalue), -1); + do_rehash(); + hash = do_hash(rvalue); + } else { + entries.emplace_back(std::forward<K>(rvalue), hashtable[hash]); + hashtable[hash] = entries.size() - 1; + } + return entries.size() - 1; + } + + public: + class const_iterator : public std::iterator<std::forward_iterator_tag, K> + { + friend class pool; + + protected: + const pool *ptr; + int index; + const_iterator(const pool *ptr, int index) : ptr(ptr), index(index) {} + + public: + const_iterator() {} + const_iterator operator++() + { + index--; + return *this; + } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const K &operator*() const { return ptr->entries[index].udata; } + const K *operator->() const { return &ptr->entries[index].udata; } + }; + + class iterator : public std::iterator<std::forward_iterator_tag, K> + { + friend class pool; + + protected: + pool *ptr; + int index; + iterator(pool *ptr, int index) : ptr(ptr), index(index) {} + + public: + iterator() {} + iterator operator++() + { + index--; + return *this; + } + bool operator==(const iterator &other) const { return index == other.index; } + bool operator!=(const iterator &other) const { return index != other.index; } + K &operator*() { return ptr->entries[index].udata; } + K *operator->() { return &ptr->entries[index].udata; } + const K &operator*() const { return ptr->entries[index].udata; } + const K *operator->() const { return &ptr->entries[index].udata; } + operator const_iterator() const { return const_iterator(ptr, index); } + }; + + pool() {} + + pool(const pool &other) + { + entries = other.entries; + do_rehash(); + } + + pool(pool &&other) { swap(other); } + + pool &operator=(const pool &other) + { + entries = other.entries; + do_rehash(); + return *this; + } + + pool &operator=(pool &&other) + { + clear(); + swap(other); + return *this; + } + + pool(const std::initializer_list<K> &list) + { + for (auto &it : list) + insert(it); + } + + template <class InputIterator> pool(InputIterator first, InputIterator last) { insert(first, last); } + + template <class InputIterator> void insert(InputIterator first, InputIterator last) + { + for (; first != last; ++first) + insert(*first); + } + + std::pair<iterator, bool> insert(const K &value) + { + int hash = do_hash(value); + int i = do_lookup(value, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(value, hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + std::pair<iterator, bool> insert(K &&rvalue) + { + int hash = do_hash(rvalue); + int i = do_lookup(rvalue, hash); + if (i >= 0) + return std::pair<iterator, bool>(iterator(this, i), false); + i = do_insert(std::forward<K>(rvalue), hash); + return std::pair<iterator, bool>(iterator(this, i), true); + } + + template <typename... Args> std::pair<iterator, bool> emplace(Args &&...args) + { + return insert(K(std::forward<Args>(args)...)); + } + + int erase(const K &key) + { + int hash = do_hash(key); + int index = do_lookup(key, hash); + return do_erase(index, hash); + } + + iterator erase(iterator it) + { + int hash = do_hash(*it); + do_erase(it.index, hash); + return ++it; + } + + int count(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 ? 0 : 1; + } + + int count(const K &key, const_iterator it) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i < 0 || i > it.index ? 0 : 1; + } + + iterator find(const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return iterator(this, i); + } + + const_iterator find(const K &key) const + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + if (i < 0) + return end(); + return const_iterator(this, i); + } + + bool operator[](const K &key) + { + int hash = do_hash(key); + int i = do_lookup(key, hash); + return i >= 0; + } + + template <typename Compare = std::less<K>> void sort(Compare comp = Compare()) + { + std::sort(entries.begin(), entries.end(), + [comp](const entry_t &a, const entry_t &b) { return comp(b.udata, a.udata); }); + do_rehash(); + } + + K pop() + { + iterator it = begin(); + K ret = *it; + erase(it); + return ret; + } + + void swap(pool &other) + { + hashtable.swap(other.hashtable); + entries.swap(other.entries); + } + + bool operator==(const pool &other) const + { + if (size() != other.size()) + return false; + for (auto &it : entries) + if (!other.count(it.udata)) + return false; + return true; + } + + bool operator!=(const pool &other) const { return !operator==(other); } + + bool hash() const + { + unsigned int hashval = mkhash_init; + for (auto &it : entries) + hashval ^= ops.hash(it.udata); + return hashval; + } + + void reserve(size_t n) { entries.reserve(n); } + size_t size() const { return entries.size(); } + bool empty() const { return entries.empty(); } + void clear() + { + hashtable.clear(); + entries.clear(); + } + + iterator begin() { return iterator(this, int(entries.size()) - 1); } + iterator element(int n) { return iterator(this, int(entries.size()) - 1 - n); } + iterator end() { return iterator(nullptr, -1); } + + const_iterator begin() const { return const_iterator(this, int(entries.size()) - 1); } + const_iterator element(int n) const { return const_iterator(this, int(entries.size()) - 1 - n); } + const_iterator end() const { return const_iterator(nullptr, -1); } +}; + +template <typename K, int offset, typename OPS> class idict +{ + pool<K, OPS> database; + + public: + class const_iterator : public std::iterator<std::forward_iterator_tag, K> + { + friend class idict; + + protected: + const idict &container; + int index; + const_iterator(const idict &container, int index) : container(container), index(index) {} + + public: + const_iterator() {} + const_iterator operator++() + { + index++; + return *this; + } + bool operator==(const const_iterator &other) const { return index == other.index; } + bool operator!=(const const_iterator &other) const { return index != other.index; } + const K &operator*() const { return container[index]; } + const K *operator->() const { return &container[index]; } + }; + + int operator()(const K &key) + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + if (i < 0) + i = database.do_insert(key, hash); + return i + offset; + } + + int at(const K &key) const + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + if (i < 0) + throw std::out_of_range("idict::at()"); + return i + offset; + } + + int at(const K &key, int defval) const + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + if (i < 0) + return defval; + return i + offset; + } + + int count(const K &key) const + { + int hash = database.do_hash(key); + int i = database.do_lookup(key, hash); + return i < 0 ? 0 : 1; + } + + void expect(const K &key, int i) + { + int j = (*this)(key); + if (i != j) + throw std::out_of_range("idict::expect()"); + } + + const K &operator[](int index) const { return database.entries.at(index - offset).udata; } + + void swap(idict &other) { database.swap(other.database); } + + void reserve(size_t n) { database.reserve(n); } + size_t size() const { return database.size(); } + bool empty() const { return database.empty(); } + void clear() { database.clear(); } + + const_iterator begin() const { return const_iterator(*this, offset); } + const_iterator element(int n) const { return const_iterator(*this, n); } + const_iterator end() const { return const_iterator(*this, offset + size()); } +}; + +template <typename K, typename OPS> class mfp +{ + mutable idict<K, 0, OPS> database; + mutable std::vector<int> parents; + + public: + typedef typename idict<K, 0, OPS>::const_iterator const_iterator; + + int operator()(const K &key) const + { + int i = database(key); + parents.resize(database.size(), -1); + return i; + } + + const K &operator[](int index) const { return database[index]; } + + int ifind(int i) const + { + int p = i, k = i; + + while (parents[p] != -1) + p = parents[p]; + + while (k != p) { + int next_k = parents[k]; + parents[k] = p; + k = next_k; + } + + return p; + } + + void imerge(int i, int j) + { + i = ifind(i); + j = ifind(j); + + if (i != j) + parents[i] = j; + } + + void ipromote(int i) + { + int k = i; + + while (k != -1) { + int next_k = parents[k]; + parents[k] = i; + k = next_k; + } + + parents[i] = -1; + } + + int lookup(const K &a) const { return ifind((*this)(a)); } + + const K &find(const K &a) const + { + int i = database.at(a, -1); + if (i < 0) + return a; + return (*this)[ifind(i)]; + } + + void merge(const K &a, const K &b) { imerge((*this)(a), (*this)(b)); } + + void promote(const K &a) + { + int i = database.at(a, -1); + if (i >= 0) + ipromote(i); + } + + void swap(mfp &other) + { + database.swap(other.database); + parents.swap(other.parents); + } + + void reserve(size_t n) { database.reserve(n); } + size_t size() const { return database.size(); } + bool empty() const { return database.empty(); } + void clear() + { + database.clear(); + parents.clear(); + } + + const_iterator begin() const { return database.begin(); } + const_iterator element(int n) const { return database.element(n); } + const_iterator end() const { return database.end(); } +}; + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/common/idstring.h b/common/idstring.h index c3ccbc6b..5a7719fa 100644 --- a/common/idstring.h +++ b/common/idstring.h @@ -56,18 +56,10 @@ struct IdString bool operator!=(const IdString &other) const { return index != other.index; } bool empty() const { return index == 0; } + + unsigned int hash() const { return index; } }; NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash<NEXTPNR_NAMESPACE_PREFIX IdString> -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdString &obj) const noexcept - { - return std::hash<int>()(obj.index); - } -}; -} // namespace std - #endif /* IDSTRING_H */ diff --git a/common/idstringlist.h b/common/idstringlist.h index 24a46731..f101ecca 100644 --- a/common/idstringlist.h +++ b/common/idstringlist.h @@ -22,6 +22,7 @@ #define IDSTRING_LIST_H #include <boost/functional/hash.hpp> +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" #include "sso_array.h" @@ -67,22 +68,16 @@ struct IdStringList static IdStringList concat(IdStringList a, IdStringList b); IdStringList slice(size_t s, size_t e) const; -}; - -NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash<NEXTPNR_NAMESPACE_PREFIX IdStringList> -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX IdStringList &obj) const noexcept + unsigned int hash() const { - std::size_t seed = 0; - boost::hash_combine(seed, hash<size_t>()(obj.size())); - for (auto &id : obj) - boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(id)); - return seed; + unsigned int h = mkhash_init; + for (const auto &val : ids) + h = mkhash(h, val.hash()); + return h; } }; -} // namespace std + +NEXTPNR_NAMESPACE_END #endif /* IDSTRING_LIST_H */ diff --git a/common/log.cc b/common/log.cc index 01aec79a..a429d172 100644 --- a/common/log.cc +++ b/common/log.cc @@ -38,7 +38,7 @@ log_write_type log_write_function = nullptr; std::string log_last_error; void (*log_error_atexit)() = NULL; -std::unordered_map<LogLevel, int> message_count_by_level; +dict<LogLevel, int, loglevel_hash_ops> message_count_by_level; static int log_newline_count = 0; bool had_nonfatal_error = false; diff --git a/common/log.h b/common/log.h index 7dfdf165..e9237446 100644 --- a/common/log.h +++ b/common/log.h @@ -26,8 +26,8 @@ #include <stdarg.h> #include <stdio.h> #include <string> -#include <unordered_map> #include <vector> +#include "hashlib.h" #include "nextpnr_namespaces.h" NEXTPNR_NAMESPACE_BEGIN @@ -51,13 +51,19 @@ enum class LogLevel ALWAYS_MSG }; +struct loglevel_hash_ops +{ + static inline bool cmp(LogLevel a, LogLevel b) { return a == b; } + static inline unsigned int hash(LogLevel a) { return unsigned(a); } +}; + extern std::vector<std::pair<std::ostream *, LogLevel>> log_streams; extern log_write_type log_write_function; extern std::string log_last_error; extern void (*log_error_atexit)(); extern bool had_nonfatal_error; -extern std::unordered_map<LogLevel, int> message_count_by_level; +extern dict<LogLevel, int, loglevel_hash_ops> message_count_by_level; std::string stringf(const char *fmt, ...); std::string vstringf(const char *fmt, va_list ap); @@ -83,14 +89,4 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash<NEXTPNR_NAMESPACE_PREFIX LogLevel> -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX LogLevel &loglevel) const noexcept - { - return std::hash<int>()((int)loglevel); - } -}; -} // namespace std - #endif diff --git a/common/nextpnr_base_types.h b/common/nextpnr_base_types.h index 1a15bfcb..1707559b 100644 --- a/common/nextpnr_base_types.h +++ b/common/nextpnr_base_types.h @@ -30,6 +30,7 @@ #include <boost/functional/hash.hpp> #include <string> +#include "hashlib.h" #include "idstring.h" #include "nextpnr_namespaces.h" @@ -89,6 +90,7 @@ struct Loc bool operator==(const Loc &other) const { return (x == other.x) && (y == other.y) && (z == other.z); } bool operator!=(const Loc &other) const { return (x != other.x) || (y != other.y) || (z != other.z); } + unsigned int hash() const { return mkhash(x, mkhash(y, z)); } }; struct ArcBounds @@ -128,19 +130,4 @@ enum PlaceStrength NEXTPNR_NAMESPACE_END -namespace std { -template <> struct hash<NEXTPNR_NAMESPACE_PREFIX Loc> -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Loc &obj) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash<int>()(obj.x)); - boost::hash_combine(seed, hash<int>()(obj.y)); - boost::hash_combine(seed, hash<int>()(obj.z)); - return seed; - } -}; - -} // namespace std - #endif /* NEXTPNR_BASE_TYPES_H */ diff --git a/common/nextpnr_types.h b/common/nextpnr_types.h index 67e60c50..4770f8ae 100644 --- a/common/nextpnr_types.h +++ b/common/nextpnr_types.h @@ -28,6 +28,7 @@ #include <unordered_set> #include "archdefs.h" +#include "hashlib.h" #include "nextpnr_base_types.h" #include "nextpnr_namespaces.h" #include "property.h" @@ -56,9 +57,9 @@ struct Region bool constr_wires = false; bool constr_pips = false; - std::unordered_set<BelId> bels; - std::unordered_set<WireId> wires; - std::unordered_set<Loc> piplocs; + pool<BelId> bels; + pool<WireId> wires; + pool<Loc> piplocs; }; struct PipMap @@ -128,10 +129,10 @@ struct NetInfo : ArchNetInfo PortRef driver; std::vector<PortRef> users; - std::unordered_map<IdString, Property> attrs; + dict<IdString, Property> attrs; // wire -> uphill_pip - std::unordered_map<WireId, PipMap> wires; + dict<WireId, PipMap> wires; std::vector<IdString> aliases; // entries in net_aliases that point to this net @@ -159,8 +160,8 @@ struct CellInfo : ArchCellInfo IdString name, type, hierpath; int32_t udata; - std::unordered_map<IdString, PortInfo> ports; - std::unordered_map<IdString, Property> attrs, params; + dict<IdString, PortInfo> ports; + dict<IdString, Property> attrs, params; BelId bel; PlaceStrength belStrength = STRENGTH_NONE; @@ -232,13 +233,13 @@ struct HierarchicalCell { IdString name, type, parent, fullpath; // Name inside cell instance -> global name - std::unordered_map<IdString, IdString> leaf_cells, nets; + dict<IdString, IdString> leaf_cells, nets; // Global name -> name inside cell instance - std::unordered_map<IdString, IdString> leaf_cells_by_gname, nets_by_gname; + dict<IdString, IdString> leaf_cells_by_gname, nets_by_gname; // Cell port to net - std::unordered_map<IdString, HierarchicalPort> ports; + dict<IdString, HierarchicalPort> ports; // Name inside cell instance -> global name - std::unordered_map<IdString, IdString> hier_cells; + dict<IdString, IdString> hier_cells; }; NEXTPNR_NAMESPACE_END diff --git a/common/place_common.cc b/common/place_common.cc index 7cbeca65..9a6c6158 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -178,8 +178,8 @@ class ConstraintLegaliseWorker private: Context *ctx; std::set<IdString> rippedCells; - std::unordered_map<IdString, Loc> oldLocations; - std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells; + dict<IdString, Loc> oldLocations; + dict<ClusterId, std::vector<CellInfo *>> cluster2cells; class IncreasingDiameterSearch { @@ -227,10 +227,10 @@ class ConstraintLegaliseWorker int sign = 0; }; - typedef std::unordered_map<IdString, Loc> CellLocations; + typedef dict<IdString, Loc> CellLocations; // Check if a location would be suitable for a cell and all its constrained children - bool valid_loc_for(const CellInfo *cell, Loc loc, CellLocations &solution, std::unordered_set<Loc> &usedLocations) + bool valid_loc_for(const CellInfo *cell, Loc loc, CellLocations &solution, pool<Loc> &usedLocations) { BelId locBel = ctx->getBelByLocation(loc); if (locBel == BelId()) @@ -324,7 +324,7 @@ class ConstraintLegaliseWorker } CellLocations solution; - std::unordered_set<Loc> used; + pool<Loc> used; if (valid_loc_for(cell, rootLoc, solution, used)) { for (auto cp : solution) { // First unbind all cells @@ -377,9 +377,9 @@ class ConstraintLegaliseWorker public: ConstraintLegaliseWorker(Context *ctx) : ctx(ctx) { - for (auto cell : sorted(ctx->cells)) { + for (auto &cell : ctx->cells) { if (cell.second->cluster != ClusterId()) - cluster2cells[cell.second->cluster].push_back(cell.second); + cluster2cells[cell.second->cluster].push_back(cell.second.get()); } }; @@ -414,11 +414,11 @@ class ConstraintLegaliseWorker int legalise_constraints() { log_info("Legalising relative constraints...\n"); - for (auto cell : sorted(ctx->cells)) { + for (auto &cell : ctx->cells) { oldLocations[cell.first] = ctx->getBelLocation(cell.second->bel); } - for (auto cell : sorted(ctx->cells)) { - bool res = legalise_cell(cell.second); + for (auto &cell : ctx->cells) { + bool res = legalise_cell(cell.second.get()); if (!res) { log_error("failed to place chain starting at cell '%s'\n", cell.first.c_str(ctx)); return -1; @@ -434,8 +434,8 @@ class ConstraintLegaliseWorker } } auto score = print_stats("replacing ripped up cells"); - for (auto cell : sorted(ctx->cells)) - if (get_constraints_distance(ctx, cell.second) != 0) + for (auto &cell : ctx->cells) + if (get_constraints_distance(ctx, cell.second.get()) != 0) log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel)); return score; diff --git a/common/placer1.cc b/common/placer1.cc index a3e7a696..a832e08f 100644 --- a/common/placer1.cc +++ b/common/placer1.cc @@ -46,19 +46,6 @@ #include "timing.h" #include "util.h" -namespace std { -template <> struct hash<std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, std::size_t>> -{ - std::size_t operator()(const std::pair<NEXTPNR_NAMESPACE_PREFIX IdString, std::size_t> &idp) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(idp.first)); - boost::hash_combine(seed, hash<std::size_t>()(idp.second)); - return seed; - } -}; -} // namespace std - NEXTPNR_NAMESPACE_BEGIN class SAPlacer @@ -87,8 +74,8 @@ class SAPlacer } diameter = std::max(max_x, max_y) + 1; - std::unordered_set<IdString> cell_types_in_use; - for (auto cell : sorted(ctx->cells)) { + pool<IdString> cell_types_in_use; + for (auto &cell : ctx->cells) { IdString cell_type = cell.second->type; cell_types_in_use.insert(cell_type); } @@ -108,8 +95,8 @@ class SAPlacer net.second->udata = n++; net_by_udata.push_back(net.second.get()); } - for (auto ®ion : sorted(ctx->region)) { - Region *r = region.second; + for (auto ®ion : ctx->region) { + Region *r = region.second.get(); BoundingBox bb; if (r->constr_bels) { bb.x0 = std::numeric_limits<int>::max(); @@ -360,12 +347,12 @@ class SAPlacer // Only increase temperature if something was moved autoplaced.clear(); chain_basis.clear(); - for (auto cell : sorted(ctx->cells)) { + for (auto &cell : ctx->cells) { if (cell.second->belStrength <= STRENGTH_STRONG && cell.second->cluster != ClusterId() && - ctx->getClusterRootCell(cell.second->cluster) == cell.second) - chain_basis.push_back(cell.second); + ctx->getClusterRootCell(cell.second->cluster) == cell.second.get()) + chain_basis.push_back(cell.second.get()); else if (cell.second->belStrength < STRENGTH_STRONG) - autoplaced.push_back(cell.second); + autoplaced.push_back(cell.second.get()); } // temp = post_legalise_temp; // diameter = std::min<int>(M, diameter * post_legalise_dia_scale); @@ -421,8 +408,8 @@ class SAPlacer } } } - for (auto cell : sorted(ctx->cells)) - if (get_constraints_distance(ctx, cell.second) != 0) + for (auto &cell : ctx->cells) + if (get_constraints_distance(ctx, cell.second.get()) != 0) log_error("constraint satisfaction check failed for cell '%s' at Bel '%s'\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel)); timing_analysis(ctx); @@ -629,7 +616,7 @@ class SAPlacer bool try_swap_chain(CellInfo *cell, BelId newBase) { std::vector<std::pair<CellInfo *, Loc>> cell_rel; - std::unordered_set<IdString> cells; + pool<IdString> cells; std::vector<std::pair<CellInfo *, BelId>> moves_made; std::vector<std::pair<CellInfo *, BelId>> dest_bels; double delta = 0; @@ -831,8 +818,8 @@ class SAPlacer // Set up the cost maps void setup_costs() { - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); if (ignore_net(ni)) continue; net_bounds[ni->udata] = get_net_bounds(ni); @@ -1065,7 +1052,7 @@ class SAPlacer mc.already_changed_arcs[pn->udata][i] = true; } } else if (port.second.type == PORT_IN) { - auto usr = fast_port_to_user.at(&port.second); + auto usr = fast_port_to_user.at(std::make_pair(cell->name, port.first)); if (!mc.already_changed_arcs[pn->udata][usr]) { mc.changed_arcs.emplace_back(std::make_pair(pn->udata, usr)); mc.already_changed_arcs[pn->udata][usr] = true; @@ -1118,11 +1105,11 @@ class SAPlacer // Build the cell port -> user index void build_port_index() { - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); for (size_t i = 0; i < ni->users.size(); i++) { auto &usr = ni->users.at(i); - fast_port_to_user[&(usr.cell->ports.at(usr.port))] = i; + fast_port_to_user[std::make_pair(usr.cell->name, usr.port)] = i; } } } @@ -1130,13 +1117,13 @@ class SAPlacer // Simple routeability driven placement const int large_cell_thresh = 50; int total_net_share = 0; - std::vector<std::vector<std::unordered_map<IdString, int>>> nets_by_tile; + std::vector<std::vector<dict<IdString, int>>> nets_by_tile; void setup_nets_by_tile() { total_net_share = 0; - nets_by_tile.resize(max_x + 1, std::vector<std::unordered_map<IdString, int>>(max_y + 1)); - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; + nets_by_tile.resize(max_x + 1, std::vector<dict<IdString, int>>(max_y + 1)); + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); if (int(ci->ports.size()) > large_cell_thresh) continue; Loc loc = ctx->getBelLocation(ci->bel); @@ -1194,7 +1181,7 @@ class SAPlacer std::vector<std::vector<double>> net_arc_tcost; // Fast lookup for cell port to net user index - std::unordered_map<const PortInfo *, size_t> fast_port_to_user; + dict<std::pair<IdString, IdString>, size_t> fast_port_to_user; // Wirelength and timing cost at last and current iteration wirelen_t last_wirelen_cost, curr_wirelen_cost; @@ -1207,10 +1194,10 @@ class SAPlacer bool improved = false; int n_move, n_accept; int diameter = 35, max_x = 1, max_y = 1; - std::unordered_map<IdString, std::tuple<int, int>> bel_types; - std::unordered_map<IdString, BoundingBox> region_bounds; + dict<IdString, std::tuple<int, int>> bel_types; + dict<IdString, BoundingBox> region_bounds; FastBels fast_bels; - std::unordered_set<BelId> locked_bels; + pool<BelId> locked_bels; std::vector<NetInfo *> net_by_udata; std::vector<decltype(NetInfo::udata)> old_udata; bool require_legal = true; diff --git a/common/placer_heap.cc b/common/placer_heap.cc index 2f7c7ccb..f1419bdb 100644 --- a/common/placer_heap.cc +++ b/common/placer_heap.cc @@ -43,7 +43,6 @@ #include <numeric> #include <queue> #include <tuple> -#include <unordered_map> #include "fast_bels.h" #include "log.h" #include "nextpnr.h" @@ -146,9 +145,9 @@ class HeAPPlacer tmg.setup_only = true; tmg.setup(); - for (auto cell : sorted(ctx->cells)) + for (auto &cell : ctx->cells) if (cell.second->cluster != ClusterId()) - cluster2cells[cell.second->cluster].push_back(cell.second); + cluster2cells[cell.second->cluster].push_back(cell.second.get()); } bool place() @@ -188,14 +187,14 @@ class HeAPPlacer std::vector<std::tuple<CellInfo *, BelId, PlaceStrength>> solution; - std::vector<std::unordered_set<BelBucketId>> heap_runs; - std::unordered_set<BelBucketId> all_buckets; - std::unordered_map<BelBucketId, int> bucket_count; + std::vector<pool<BelBucketId>> heap_runs; + pool<BelBucketId> all_buckets; + dict<BelBucketId, int> bucket_count; for (auto cell : place_cells) { BelBucketId bucket = ctx->getBelBucketForCellType(cell->type); if (!all_buckets.count(bucket)) { - heap_runs.push_back(std::unordered_set<BelBucketId>{bucket}); + heap_runs.push_back(pool<BelBucketId>{bucket}); all_buckets.insert(bucket); } bucket_count[bucket]++; @@ -253,9 +252,9 @@ class HeAPPlacer for (const auto &group : cfg.cellGroups) CutSpreader(this, group).run(); - for (auto type : sorted(run)) + for (auto type : run) if (std::all_of(cfg.cellGroups.begin(), cfg.cellGroups.end(), - [type](const std::unordered_set<BelBucketId> &grp) { return !grp.count(type); })) + [type](const pool<BelBucketId> &grp) { return !grp.count(type); })) CutSpreader(this, {type}).run(); // Run strict legalisation to find a valid bel for all cells @@ -283,8 +282,8 @@ class HeAPPlacer stalled = 0; // Save solution solution.clear(); - for (auto cell : sorted(ctx->cells)) { - solution.emplace_back(cell.second, cell.second->bel, cell.second->belStrength); + for (auto &cell : ctx->cells) { + solution.emplace_back(cell.second.get(), cell.second->bel, cell.second->belStrength); } } else { ++stalled; @@ -311,10 +310,10 @@ class HeAPPlacer ctx->bindBel(bel, cell, strength); } - for (auto cell : sorted(ctx->cells)) { + for (auto &cell : ctx->cells) { if (cell.second->bel == BelId()) log_error("Found unbound cell %s\n", cell.first.c_str(ctx)); - if (ctx->getBoundBelCell(cell.second->bel) != cell.second) + if (ctx->getBoundBelCell(cell.second->bel) != cell.second.get()) log_error("Found cell %s with mismatched binding\n", cell.first.c_str(ctx)); if (ctx->debug) log_info("AP soln: %s -> %s\n", cell.first.c_str(ctx), ctx->nameOfBel(cell.second->bel)); @@ -360,7 +359,7 @@ class HeAPPlacer int max_x = 0, max_y = 0; FastBels fast_bels; - std::unordered_map<IdString, std::tuple<int, int>> bel_types; + dict<IdString, std::tuple<int, int>> bel_types; TimingAnalyser tmg; @@ -370,7 +369,7 @@ class HeAPPlacer int x0 = 0, x1 = 0, y0 = 0, y1 = 0; }; - std::unordered_map<IdString, BoundingBox> constraint_region_bounds; + dict<IdString, BoundingBox> constraint_region_bounds; // In some cases, we can't use bindBel because we allow overlap in the earlier stages. So we use this custom // structure instead @@ -381,7 +380,7 @@ class HeAPPlacer double rawx, rawy; bool locked, global; }; - std::unordered_map<IdString, CellLocation> cell_locs; + dict<IdString, CellLocation> cell_locs; // The set of cells that we will actually place. This excludes locked cells and children cells of macros/chains // (only the root of each macro is placed.) std::vector<CellInfo *> place_cells; @@ -390,8 +389,8 @@ class HeAPPlacer // cells of a certain type) std::vector<CellInfo *> solve_cells; - std::unordered_map<ClusterId, std::vector<CellInfo *>> cluster2cells; - std::unordered_map<ClusterId, int> chain_size; + dict<ClusterId, std::vector<CellInfo *>> cluster2cells; + dict<ClusterId, int> chain_size; // Performance counting double solve_time = 0, cl_time = 0, sl_time = 0; @@ -448,9 +447,9 @@ class HeAPPlacer max_y = std::max(max_y, loc.y); } - std::unordered_set<IdString> cell_types_in_use; - std::unordered_set<BelBucketId> buckets_in_use; - for (auto cell : sorted(ctx->cells)) { + pool<IdString> cell_types_in_use; + pool<BelBucketId> buckets_in_use; + for (auto &cell : ctx->cells) { IdString cell_type = cell.second->type; cell_types_in_use.insert(cell_type); BelBucketId bucket = ctx->getBelBucketForCellType(cell_type); @@ -465,8 +464,8 @@ class HeAPPlacer } // Determine bounding boxes of region constraints - for (auto ®ion : sorted(ctx->region)) { - Region *r = region.second; + for (auto ®ion : ctx->region) { + Region *r = region.second.get(); BoundingBox bb; if (r->constr_bels) { bb.x0 = std::numeric_limits<int>::max(); @@ -515,13 +514,13 @@ class HeAPPlacer // FIXME: Are there better approaches to the initial placement (e.g. greedy?) void seed_placement() { - std::unordered_set<IdString> cell_types; + pool<IdString> cell_types; for (const auto &cell : ctx->cells) { cell_types.insert(cell.second->type); } - std::unordered_set<BelId> bels_used; - std::unordered_map<IdString, std::deque<BelId>> available_bels; + pool<BelId> bels_used; + dict<IdString, std::deque<BelId>> available_bels; for (auto bel : ctx->getBels()) { if (!ctx->checkBelAvail(bel)) { @@ -539,8 +538,8 @@ class HeAPPlacer ctx->shuffle(t.second.begin(), t.second.end()); } - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); if (ci->bel != BelId()) { Loc loc = ctx->getBelLocation(ci->bel); cell_locs[cell.first].x = loc.x; @@ -591,7 +590,7 @@ class HeAPPlacer cell_locs[cell.first].global = ctx->getBelGlobalBuf(bel); // FIXME - if (has_connectivity(cell.second) && !cfg.ioBufTypes.count(ci->type)) { + if (has_connectivity(cell.second.get()) && !cfg.ioBufTypes.count(ci->type)) { bels_used.insert(bel); place_cells.push_back(ci); placed = true; @@ -612,12 +611,12 @@ class HeAPPlacer } // Setup the cells to be solved, returns the number of rows - int setup_solve_cells(std::unordered_set<BelBucketId> *buckets = nullptr) + int setup_solve_cells(pool<BelBucketId> *buckets = nullptr) { int row = 0; solve_cells.clear(); // First clear the udata of all cells - for (auto cell : sorted(ctx->cells)) + for (auto &cell : ctx->cells) cell.second->udata = dont_solve; // Then update cells to be placed, which excludes cell children for (auto cell : place_cells) { @@ -671,8 +670,8 @@ class HeAPPlacer es.reset(); - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); if (ni->driver.cell == nullptr) continue; if (ni->users.empty()) @@ -783,8 +782,8 @@ class HeAPPlacer wirelen_t total_hpwl() { wirelen_t hpwl = 0; - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); if (ni->driver.cell == nullptr) continue; CellLocation &drvloc = cell_locs.at(ni->driver.cell->name); @@ -809,8 +808,8 @@ class HeAPPlacer auto startt = std::chrono::high_resolution_clock::now(); // Unbind all cells placed in this solution - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); if (ci->bel != BelId() && (ci->udata != dont_solve || (ci->cluster != ClusterId() && ctx->getClusterRootCell(ci->cluster)->udata != dont_solve))) @@ -1106,11 +1105,11 @@ class HeAPPlacer class CutSpreader { public: - CutSpreader(HeAPPlacer *p, const std::unordered_set<BelBucketId> &buckets) : p(p), ctx(p->ctx), buckets(buckets) + CutSpreader(HeAPPlacer *p, const pool<BelBucketId> &buckets) : p(p), ctx(p->ctx), buckets(buckets) { // Get fast BELs data for all buckets being Cut/Spread. size_t idx = 0; - for (BelBucketId bucket : sorted(buckets)) { + for (BelBucketId bucket : buckets) { type_index[bucket] = idx; FastBels::FastBelsData *fast_bels; p->fast_bels.getBelsForBelBucket(bucket, &fast_bels); @@ -1198,8 +1197,8 @@ class HeAPPlacer private: HeAPPlacer *p; Context *ctx; - std::unordered_set<BelBucketId> buckets; - std::unordered_map<BelBucketId, size_t> type_index; + pool<BelBucketId> buckets; + dict<BelBucketId, size_t> type_index; std::vector<std::vector<std::vector<int>>> occupancy; std::vector<std::vector<int>> groups; std::vector<std::vector<ChainExtent>> chaines; @@ -1208,7 +1207,7 @@ class HeAPPlacer std::vector<std::vector<std::vector<std::vector<BelId>>> *> fb; std::vector<SpreaderRegion> regions; - std::unordered_set<int> merged_regions; + pool<int> merged_regions; // Cells at a location, sorted by real (not integer) x and y std::vector<std::vector<std::vector<CellInfo *>>> cells_at_location; @@ -1490,7 +1489,7 @@ class HeAPPlacer } } if (!changed) { - for (auto bucket : sorted(buckets)) { + for (auto bucket : buckets) { if (reg.cells > reg.bels) { IdString bucket_name = ctx->getBelBucketName(bucket); log_error("Failed to expand region (%d, %d) |_> (%d, %d) of %d %ss\n", reg.x0, reg.y0, diff --git a/common/placer_heap.h b/common/placer_heap.h index 00913062..9b3c3ed0 100644 --- a/common/placer_heap.h +++ b/common/placer_heap.h @@ -46,10 +46,10 @@ struct PlacerHeapCfg int spread_scale_x, spread_scale_y; // These cell types will be randomly locked to prevent singular matrices - std::unordered_set<IdString> ioBufTypes; + pool<IdString> ioBufTypes; // These cell types are part of the same unit (e.g. slices split into // components) so will always be spread together - std::vector<std::unordered_set<BelBucketId>> cellGroups; + std::vector<pool<BelBucketId>> cellGroups; }; extern bool placer_heap(Context *ctx, PlacerHeapCfg cfg); diff --git a/common/pybindings.cc b/common/pybindings.cc index 504074e1..00ebe66e 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -164,10 +164,10 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m) .def("maxFallDelay", &DelayQuad::maxFallDelay) .def("delayPair", &DelayQuad::delayPair); - typedef std::unordered_map<IdString, Property> AttrMap; - typedef std::unordered_map<IdString, PortInfo> PortMap; - typedef std::unordered_map<IdString, IdString> IdIdMap; - typedef std::unordered_map<IdString, std::unique_ptr<Region>> RegionMap; + typedef dict<IdString, Property> AttrMap; + typedef dict<IdString, PortInfo> PortMap; + typedef dict<IdString, IdString> IdIdMap; + typedef dict<IdString, std::unique_ptr<Region>> RegionMap; py::class_<BaseCtx>(m, "BaseCtx"); @@ -218,9 +218,9 @@ PYBIND11_EMBEDDED_MODULE(MODULE_NAME, m) pass_through<PortType>>::def_wrap(pi_cls, "type"); typedef std::vector<PortRef> PortRefVector; - typedef std::unordered_map<WireId, PipMap> WireMap; - typedef std::unordered_set<BelId> BelSet; - typedef std::unordered_set<WireId> WireSet; + typedef dict<WireId, PipMap> WireMap; + typedef pool<BelId> BelSet; + typedef pool<WireId> WireSet; auto ni_cls = py::class_<ContextualWrapper<NetInfo &>>(m, "NetInfo"); readwrite_wrapper<NetInfo &, decltype(&NetInfo::name), &NetInfo::name, conv_to_str<IdString>, diff --git a/common/router1.cc b/common/router1.cc index 11107a40..374f7455 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -49,16 +49,13 @@ struct arc_key : net_info->name < other.net_info->name; } - struct Hash + unsigned int hash() const { - std::size_t operator()(const arc_key &arg) const noexcept - { - std::size_t seed = std::hash<NetInfo *>()(arg.net_info); - seed ^= std::hash<int>()(arg.user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - seed ^= std::hash<int>()(arg.phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; + std::size_t seed = std::hash<NetInfo *>()(net_info); + seed ^= std::hash<int>()(user_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + seed ^= std::hash<int>()(phys_idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } }; struct arc_entry @@ -107,15 +104,15 @@ struct Router1 const Router1Cfg &cfg; std::priority_queue<arc_entry, std::vector<arc_entry>, arc_entry::Less> arc_queue; - std::unordered_map<WireId, std::unordered_set<arc_key, arc_key::Hash>> wire_to_arcs; - std::unordered_map<arc_key, std::unordered_set<WireId>, arc_key::Hash> arc_to_wires; - std::unordered_set<arc_key, arc_key::Hash> queued_arcs; + dict<WireId, pool<arc_key>> wire_to_arcs; + dict<arc_key, pool<WireId>> arc_to_wires; + pool<arc_key> queued_arcs; - std::unordered_map<WireId, QueuedWire> visited; + dict<WireId, QueuedWire> visited; std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; - std::unordered_map<WireId, int> wireScores; - std::unordered_map<NetInfo *, int> netScores; + dict<WireId, int> wireScores; + dict<NetInfo *, int, hash_ptr_ops> netScores; int arcs_with_ripup = 0; int arcs_without_ripup = 0; @@ -295,11 +292,11 @@ struct Router1 void check() { - std::unordered_set<arc_key, arc_key::Hash> valid_arcs; + pool<arc_key> valid_arcs; for (auto &net_it : ctx->nets) { NetInfo *net_info = net_it.second.get(); - std::unordered_set<WireId> valid_wires_for_net; + pool<WireId> valid_wires_for_net; if (skip_net(net_info)) continue; @@ -357,8 +354,8 @@ struct Router1 void setup() { - std::unordered_map<WireId, NetInfo *> src_to_net; - std::unordered_map<WireId, arc_key> dst_to_arc; + dict<WireId, NetInfo *> src_to_net; + dict<WireId, arc_key> dst_to_arc; std::vector<IdString> net_names; for (auto &net_it : ctx->nets) @@ -472,7 +469,7 @@ struct Router1 // unbind wires that are currently used exclusively by this arc - std::unordered_set<WireId> old_arc_wires; + pool<WireId> old_arc_wires; old_arc_wires.swap(arc_to_wires[arc]); for (WireId wire : old_arc_wires) { @@ -720,7 +717,7 @@ struct Router1 // bind resulting route (and maybe unroute other nets) - std::unordered_set<WireId> unassign_wires = arc_to_wires[arc]; + pool<WireId> unassign_wires = arc_to_wires[arc]; WireId cursor = dst_wire; delay_t accumulated_path_delay = 0; @@ -919,10 +916,10 @@ bool Context::checkRoutedDesign() const struct ExtraWireInfo { int order_num = 0; - std::unordered_set<WireId> children; + pool<WireId> children; }; - std::unordered_map<WireId, ExtraWireInfo> db; + dict<WireId, std::unique_ptr<ExtraWireInfo>> db; for (auto &it : net_info->wires) { WireId w = it.first; @@ -930,7 +927,7 @@ bool Context::checkRoutedDesign() const if (p != PipId()) { log_assert(ctx->getPipDstWire(p) == w); - db[ctx->getPipSrcWire(p)].children.insert(w); + db.emplace(ctx->getPipSrcWire(p), std::make_unique<ExtraWireInfo>()).first->second->children.insert(w); } } @@ -948,7 +945,7 @@ bool Context::checkRoutedDesign() const found_unrouted = true; } - std::unordered_map<WireId, int> dest_wires; + dict<WireId, int> dest_wires; for (int user_idx = 0; user_idx < int(net_info->users.size()); user_idx++) { for (auto dst_wire : ctx->getNetinfoSinkWires(net_info, net_info->users[user_idx])) { log_assert(dst_wire != WireId()); @@ -963,10 +960,10 @@ bool Context::checkRoutedDesign() const } std::function<void(WireId, int)> setOrderNum; - std::unordered_set<WireId> logged_wires; + pool<WireId> logged_wires; setOrderNum = [&](WireId w, int num) { - auto &db_entry = db[w]; + auto &db_entry = *db.emplace(w, std::make_unique<ExtraWireInfo>()).first->second; if (db_entry.order_num != 0) { found_loop = true; log(" %*s=> loop\n", 2 * num, ""); @@ -998,10 +995,10 @@ bool Context::checkRoutedDesign() const } setOrderNum(src_wire, 1); - std::unordered_set<WireId> dangling_wires; + pool<WireId> dangling_wires; for (auto &it : db) { - auto &db_entry = it.second; + auto &db_entry = *it.second; if (db_entry.order_num == 0) dangling_wires.insert(it.first); } @@ -1010,10 +1007,10 @@ bool Context::checkRoutedDesign() const if (dangling_wires.empty()) { log(" no dangling wires.\n"); } else { - std::unordered_set<WireId> root_wires = dangling_wires; + pool<WireId> root_wires = dangling_wires; for (WireId w : dangling_wires) { - for (WireId c : db[w].children) + for (WireId c : db[w]->children) root_wires.erase(c); } @@ -1064,8 +1061,8 @@ bool Context::checkRoutedDesign() const return true; } -bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay, - std::unordered_map<WireId, PipId> *route, bool useEstimate) +bool Context::getActualRouteDelay(WireId src_wire, WireId dst_wire, delay_t *delay, dict<WireId, PipId> *route, + bool useEstimate) { // FIXME return false; diff --git a/common/router2.cc b/common/router2.cc index 2156ce28..e1d3e75b 100644 --- a/common/router2.cc +++ b/common/router2.cc @@ -35,7 +35,6 @@ #include <fstream> #include <queue> -#include "hash_table.h" #include "log.h" #include "nextpnr.h" #include "router1.h" @@ -131,8 +130,8 @@ struct Router2 nets.resize(ctx->nets.size()); nets_by_udata.resize(ctx->nets.size()); size_t i = 0; - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); ni->udata = i; nets_by_udata.at(i) = ni; nets.at(i).arcs.resize(ni->users.size()); @@ -198,7 +197,7 @@ struct Router2 } } - HashTables::HashMap<WireId, int> wire_to_idx; + dict<WireId, int> wire_to_idx; std::vector<PerWireData> flat_wires; PerWireData &wire_data(WireId w) { return flat_wires[wire_to_idx.at(w)]; } @@ -231,8 +230,8 @@ struct Router2 flat_wires.push_back(pwd); } - for (auto net_pair : sorted(ctx->nets)) { - auto *net = net_pair.second; + for (auto &net_pair : ctx->nets) { + auto *net = net_pair.second.get(); auto &nd = nets.at(net->udata); for (size_t usr = 0; usr < net->users.size(); usr++) { auto &ad = nd.arcs.at(usr); @@ -284,7 +283,7 @@ struct Router2 std::priority_queue<QueuedWire, std::vector<QueuedWire>, QueuedWire::Greater> queue; // Special case where one net has multiple logical arcs to the same physical sink - std::unordered_set<WireId> processed_sinks; + pool<WireId> processed_sinks; // Backwards routing std::queue<int> backwards_queue; @@ -465,7 +464,7 @@ struct Router2 bool did_something = false; WireId src = ctx->getNetinfoSourceWire(net); for (auto sink : ctx->getNetinfoSinkWires(net, net->users.at(i))) { - std::unordered_set<WireId> rsv; + pool<WireId> rsv; WireId cursor = sink; bool done = false; if (ctx->debug) @@ -1083,7 +1082,7 @@ struct Router2 void write_wiretype_heatmap(std::ostream &out) { - std::unordered_map<IdString, std::vector<int>> cong_by_type; + dict<IdString, std::vector<int>> cong_by_type; size_t max_cong = 0; // Build histogram for (auto &wd : flat_wires) { @@ -1099,7 +1098,7 @@ struct Router2 for (size_t i = 0; i <= max_cong; i++) out << "bound=" << i << ","; out << std::endl; - for (auto &ty : sorted_ref(cong_by_type)) { + for (auto &ty : cong_by_type) { out << ctx->nameOf(ty.first) << ","; for (int count : ty.second) out << count << ","; diff --git a/common/sdf.cc b/common/sdf.cc index 5c3d0a5a..814bf09a 100644 --- a/common/sdf.cc +++ b/common/sdf.cc @@ -254,9 +254,9 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const return rf; }; - for (auto cell : sorted(cells)) { + for (const auto &cell : cells) { Cell sc; - const CellInfo *ci = cell.second; + const CellInfo *ci = cell.second.get(); sc.instance = ci->name.str(this); sc.celltype = ci->type.str(this); for (auto port : ci->ports) { @@ -313,8 +313,8 @@ void Context::writeSDF(std::ostream &out, bool cvc_mode) const wr.cells.push_back(sc); } - for (auto net : sorted(nets)) { - NetInfo *ni = net.second; + for (auto &net : nets) { + NetInfo *ni = net.second.get(); if (ni->driver.cell == nullptr) continue; for (auto &usr : ni->users) { diff --git a/common/timing.cc b/common/timing.cc index ef5977de..1670bc7d 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -23,7 +23,6 @@ #include <boost/range/adaptor/reversed.hpp> #include <deque> #include <map> -#include <unordered_map> #include <utility> #include "log.h" #include "util.h" @@ -52,17 +51,17 @@ void TimingAnalyser::run() void TimingAnalyser::init_ports() { // Per cell port structures - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; - for (auto port : sorted_ref(ci->ports)) { + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + for (auto &port : ci->ports) { auto &data = ports[CellPortKey(ci->name, port.first)]; data.type = port.second.type; data.cell_port = CellPortKey(ci->name, port.first); } } // Cell port to net port mapping - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); if (ni->driver.cell != nullptr) ports[CellPortKey(ni->driver)].net_port = NetPortKey(ni->name); for (size_t i = 0; i < ni->users.size(); i++) @@ -138,8 +137,8 @@ void TimingAnalyser::get_cell_delays() void TimingAnalyser::get_route_delays() { - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId()) continue; for (auto &usr : ni->users) { @@ -272,7 +271,7 @@ void TimingAnalyser::setup_port_domains() void TimingAnalyser::reset_times() { for (auto &port : ports) { - auto do_reset = [&](std::unordered_map<domain_id_t, ArrivReqTime> ×) { + auto do_reset = [&](dict<domain_id_t, ArrivReqTime> ×) { for (auto &t : times) { t.second.value = init_delay; t.second.path_length = 0; @@ -426,7 +425,7 @@ void TimingAnalyser::walk_backward() void TimingAnalyser::print_fmax() { // Temporary testing code for comparison only - std::unordered_map<int, double> domain_fmax; + dict<int, double> domain_fmax; for (auto p : topological_order) { auto &pd = ports.at(p); for (auto &req : pd.required) { @@ -591,6 +590,7 @@ struct ClockEvent ClockEdge edge; bool operator==(const ClockEvent &other) const { return clock == other.clock && edge == other.edge; } + unsigned int hash() const { return mkhash(clock.hash(), int(edge)); } }; struct ClockPair @@ -598,37 +598,10 @@ struct ClockPair ClockEvent start, end; bool operator==(const ClockPair &other) const { return start == other.start && end == other.end; } + unsigned int hash() const { return mkhash(start.hash(), end.hash()); } }; } // namespace -NEXTPNR_NAMESPACE_END -namespace std { - -template <> struct hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent> -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockEvent &obj) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX IdString>()(obj.clock)); - boost::hash_combine(seed, hash<int>()(int(obj.edge))); - return seed; - } -}; - -template <> struct hash<NEXTPNR_NAMESPACE_PREFIX ClockPair> -{ - std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX ClockPair &obj) const noexcept - { - std::size_t seed = 0; - boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent>()(obj.start)); - boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX ClockEvent>()(obj.start)); - return seed; - } -}; - -} // namespace std -NEXTPNR_NAMESPACE_BEGIN - typedef std::vector<const PortRef *> PortRefVector; typedef std::map<int, unsigned> DelayFrequency; @@ -639,7 +612,7 @@ struct CriticalPath delay_t path_period; }; -typedef std::unordered_map<ClockPair, CriticalPath> CriticalPathMap; +typedef dict<ClockPair, CriticalPath> CriticalPathMap; struct Timing { @@ -660,7 +633,7 @@ struct Timing delay_t min_remaining_budget; bool false_startpoint = false; std::vector<delay_t> min_required; - std::unordered_map<ClockEvent, delay_t> arrival_time; + dict<ClockEvent, delay_t> arrival_time; }; Timing(Context *ctx, bool net_delays, bool update, CriticalPathMap *crit_path = nullptr, @@ -677,14 +650,14 @@ struct Timing // First, compute the topological order of nets to walk through the circuit, assuming it is a _acyclic_ graph // TODO(eddieh): Handle the case where it is cyclic, e.g. combinatorial loops std::vector<NetInfo *> topological_order; - std::unordered_map<const NetInfo *, std::unordered_map<ClockEvent, TimingData>> net_data; + dict<const NetInfo *, dict<ClockEvent, TimingData>, hash_ptr_ops> net_data; // In lieu of deleting edges from the graph, simply count the number of fanins to each output port - std::unordered_map<const PortInfo *, unsigned> port_fanin; + dict<const PortInfo *, unsigned, hash_ptr_ops> port_fanin; std::vector<IdString> input_ports; std::vector<const PortInfo *> output_ports; - std::unordered_set<IdString> ooc_port_nets; + pool<IdString> ooc_port_nets; // In out-of-context mode, top-level inputs look floating but aren't if (bool_or_default(ctx->settings, ctx->id("arch.ooc"))) { @@ -880,7 +853,7 @@ struct Timing } } - std::unordered_map<ClockPair, std::pair<delay_t, NetInfo *>> crit_nets; + dict<ClockPair, std::pair<delay_t, NetInfo *>> crit_nets; // Now go backwards topologically to determine the minimum path slack, and to distribute all path slack evenly // between all nets on the path diff --git a/common/timing.h b/common/timing.h index 133bd4eb..974bb26b 100644 --- a/common/timing.h +++ b/common/timing.h @@ -35,15 +35,7 @@ struct CellPortKey port = pr.port; } IdString cell, port; - struct Hash - { - inline std::size_t operator()(const CellPortKey &arg) const noexcept - { - std::size_t seed = std::hash<IdString>()(arg.cell); - seed ^= std::hash<IdString>()(arg.port) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; + unsigned int hash() const { return mkhash(cell.hash(), port.hash()); } inline bool operator==(const CellPortKey &other) const { return (cell == other.cell) && (port == other.port); } inline bool operator!=(const CellPortKey &other) const { return (cell != other.cell) || (port != other.port); } inline bool operator<(const CellPortKey &other) const @@ -69,15 +61,8 @@ struct NetPortKey return idx; } - struct Hash - { - std::size_t operator()(const NetPortKey &arg) const noexcept - { - std::size_t seed = std::hash<IdString>()(arg.net); - seed ^= std::hash<size_t>()(arg.idx) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; + unsigned int hash() const { return mkhash(net.hash(), idx); } + inline bool operator==(const NetPortKey &other) const { return (net == other.net) && (idx == other.idx); } }; @@ -89,15 +74,8 @@ struct ClockDomainKey // probably also need something here to deal with constraints inline bool is_async() const { return clock == IdString(); } - struct Hash - { - std::size_t operator()(const ClockDomainKey &arg) const noexcept - { - std::size_t seed = std::hash<IdString>()(arg.clock); - seed ^= std::hash<int>()(int(arg.edge)) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; + unsigned int hash() const { return mkhash(clock.hash(), int(edge)); } + inline bool operator==(const ClockDomainKey &other) const { return (clock == other.clock) && (edge == other.edge); } }; @@ -111,15 +89,7 @@ struct ClockDomainPairKey { return (launch == other.launch) && (capture == other.capture); } - struct Hash - { - std::size_t operator()(const ClockDomainPairKey &arg) const noexcept - { - std::size_t seed = std::hash<domain_id_t>()(arg.launch); - seed ^= std::hash<domain_id_t>()(arg.capture) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - return seed; - } - }; + unsigned int hash() const { return mkhash(launch, capture); } }; struct TimingAnalyser @@ -223,16 +193,17 @@ struct TimingAnalyser NetPortKey net_port; PortType type; // per domain timings - std::unordered_map<domain_id_t, ArrivReqTime> arrival; - std::unordered_map<domain_id_t, ArrivReqTime> required; - std::unordered_map<domain_id_t, PortDomainPairData> domain_pairs; + dict<domain_id_t, ArrivReqTime> arrival; + dict<domain_id_t, ArrivReqTime> required; + dict<domain_id_t, PortDomainPairData> domain_pairs; // cell timing arcs to (outputs)/from (inputs) from this port std::vector<CellArc> cell_arcs; // routing delay into this port (input ports only) - DelayPair route_delay; + DelayPair route_delay{0}; // worst criticality and slack across domain pairs - float worst_crit; - delay_t worst_setup_slack, worst_hold_slack; + float worst_crit = 0; + delay_t worst_setup_slack = std::numeric_limits<delay_t>::max(), + worst_hold_slack = std::numeric_limits<delay_t>::max(); }; struct PerDomain @@ -260,9 +231,9 @@ struct TimingAnalyser void copy_domains(const CellPortKey &from, const CellPortKey &to, bool backwards); - std::unordered_map<CellPortKey, PerPort, CellPortKey::Hash> ports; - std::unordered_map<ClockDomainKey, domain_id_t, ClockDomainKey::Hash> domain_to_id; - std::unordered_map<ClockDomainPairKey, domain_id_t, ClockDomainPairKey::Hash> pair_to_id; + dict<CellPortKey, PerPort> ports; + dict<ClockDomainKey, domain_id_t> domain_to_id; + dict<ClockDomainPairKey, domain_id_t> pair_to_id; std::vector<PerDomain> domains; std::vector<PerDomainPair> domain_pairs; diff --git a/common/timing_opt.cc b/common/timing_opt.cc index 854cbc5b..da4907b6 100644 --- a/common/timing_opt.cc +++ b/common/timing_opt.cc @@ -35,8 +35,6 @@ #include "timing.h" #include "util.h" -#include "hash_table.h" - NEXTPNR_NAMESPACE_BEGIN class TimingOptimiser @@ -68,8 +66,8 @@ class TimingOptimiser void setup_delay_limits() { max_net_delay.clear(); - for (auto net : sorted(ctx->nets)) { - NetInfo *ni = net.second; + for (auto &net : ctx->nets) { + NetInfo *ni = net.second.get(); if (ni->driver.cell == nullptr) continue; for (auto usr : ni->users) { @@ -167,7 +165,7 @@ class TimingOptimiser BelId curr = cell->bel; Loc curr_loc = ctx->getBelLocation(curr); int found_count = 0; - cell_neighbour_bels[cell->name] = std::unordered_set<BelId>{}; + cell_neighbour_bels[cell->name] = pool<BelId>{}; for (int dy = -d; dy <= d; dy++) { for (int dx = -d; dx <= d; dx++) { // Go through all the Bels at this location @@ -239,7 +237,7 @@ class TimingOptimiser std::vector<std::pair<NetInfo *, int>> crit_nets; std::vector<IdString> netnames; std::transform(ctx->nets.begin(), ctx->nets.end(), std::back_inserter(netnames), - [](const std::pair<const IdString, std::unique_ptr<NetInfo>> &kv) { return kv.first; }); + [](const std::pair<IdString, std::unique_ptr<NetInfo>> &kv) { return kv.first; }); ctx->sorted_shuffle(netnames); for (auto net : netnames) { if (crit_nets.size() >= max_count) @@ -267,7 +265,7 @@ class TimingOptimiser } NPNR_ASSERT_FALSE("port user not found on net"); }; - std::unordered_set<PortRef *> used_ports; + pool<PortRef *, hash_ptr_ops> used_ports; for (auto crit_net : crit_nets) { @@ -439,10 +437,10 @@ 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>, PairHash> backtrace; + dict<IdString, dict<BelId, delay_t>> cumul_costs; + dict<std::pair<IdString, BelId>, std::pair<IdString, BelId>> backtrace; std::queue<std::pair<int, BelId>> visit; - std::unordered_set<std::pair<int, BelId>, PairHash> to_visit; + pool<std::pair<int, BelId>> to_visit; for (auto startbel : cell_neighbour_bels[path_cells.front()]) { // Swap for legality check @@ -568,10 +566,10 @@ class TimingOptimiser // Current candidate Bels for cells (linked in both direction> std::vector<IdString> path_cells; - std::unordered_map<IdString, std::unordered_set<BelId>> cell_neighbour_bels; - std::unordered_map<BelId, std::unordered_set<IdString>> bel_candidate_cells; + dict<IdString, pool<BelId>> cell_neighbour_bels; + dict<BelId, pool<IdString>> bel_candidate_cells; // Map cell ports to net delay limit - std::unordered_map<std::pair<IdString, IdString>, delay_t, PairHash> max_net_delay; + dict<std::pair<IdString, IdString>, delay_t> max_net_delay; Context *ctx; TimingOptCfg cfg; TimingAnalyser tmg; diff --git a/common/timing_opt.h b/common/timing_opt.h index 775d9596..46bf3500 100644 --- a/common/timing_opt.h +++ b/common/timing_opt.h @@ -29,7 +29,7 @@ struct TimingOptCfg // The timing optimiser will *only* optimise cells of these types // Normally these would only be logic cells (or tiles if applicable), the algorithm makes little sense // for other cell types - std::unordered_set<IdString> cellTypes; + pool<IdString> cellTypes; }; extern bool timing_opt(Context *ctx, TimingOptCfg cfg); diff --git a/common/util.h b/common/util.h index 540646c7..542bd395 100644 --- a/common/util.h +++ b/common/util.h @@ -55,7 +55,7 @@ std::string str_or_default(const Container &ct, const KeyType &key, std::string }; template <typename KeyType> -std::string str_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyType &key, std::string def = "") +std::string str_or_default(const dict<KeyType, Property> &ct, const KeyType &key, std::string def = "") { auto found = ct.find(key); if (found == ct.end()) @@ -78,8 +78,7 @@ template <typename Container, typename KeyType> int int_or_default(const Contain return std::stoi(found->second); }; -template <typename KeyType> -int int_or_default(const std::unordered_map<KeyType, Property> &ct, const KeyType &key, int def = 0) +template <typename KeyType> int int_or_default(const dict<KeyType, Property> &ct, const KeyType &key, int def = 0) { auto found = ct.find(key); if (found == ct.end()) @@ -103,42 +102,6 @@ bool bool_or_default(const Container &ct, const KeyType &key, bool def = false) return bool(int_or_default(ct, key, int(def))); }; -// Wrap an unordered_map, and allow it to be iterated over sorted by key -template <typename K, typename V> std::map<K, V *> sorted(const std::unordered_map<K, std::unique_ptr<V>> &orig) -{ - std::map<K, V *> retVal; - for (auto &item : orig) - retVal.emplace(std::make_pair(item.first, item.second.get())); - return retVal; -}; - -// Wrap an unordered_map, and allow it to be iterated over sorted by key -template <typename K, typename V> std::map<K, V &> sorted_ref(std::unordered_map<K, V> &orig) -{ - std::map<K, V &> retVal; - for (auto &item : orig) - retVal.emplace(std::make_pair(item.first, std::ref(item.second))); - return retVal; -}; - -// Wrap an unordered_map, and allow it to be iterated over sorted by key -template <typename K, typename V> std::map<K, const V &> sorted_cref(const std::unordered_map<K, V> &orig) -{ - std::map<K, const V &> retVal; - for (auto &item : orig) - retVal.emplace(std::make_pair(item.first, std::ref(item.second))); - return retVal; -}; - -// Wrap an unordered_set, and allow it to be iterated over sorted by key -template <typename K> std::set<K> sorted(const std::unordered_set<K> &orig) -{ - std::set<K> retVal; - for (auto &item : orig) - retVal.insert(item); - return retVal; -}; - // Return a net if port exists, or nullptr inline const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port) { |