3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-15 11:45:41 +00:00

Merge from upstream

This commit is contained in:
Akash Levy 2025-08-21 17:56:55 -07:00
commit e54fa487b8
29 changed files with 1314 additions and 793 deletions

View file

@ -27,10 +27,10 @@ YOSYS_NAMESPACE_BEGIN
struct FfInitVals
{
const SigMap *sigmap;
const SigMapView *sigmap;
dict<SigBit, std::pair<State,SigBit>> initbits;
void set(const SigMap *sigmap_, RTLIL::Module *module)
void set(const SigMapView *sigmap_, RTLIL::Module *module)
{
sigmap = sigmap_;
initbits.clear();
@ -126,7 +126,7 @@ struct FfInitVals
initbits.clear();
}
FfInitVals (const SigMap *sigmap, RTLIL::Module *module)
FfInitVals (const SigMapView *sigmap, RTLIL::Module *module)
{
set(sigmap, module);
}

View file

@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN
struct FfMergeHelper
{
const SigMap *sigmap;
const SigMapView *sigmap;
RTLIL::Module *module;
FfInitVals *initvals;

View file

@ -12,6 +12,7 @@
#ifndef HASHLIB_H
#define HASHLIB_H
#include <array>
#include <stdexcept>
#include <algorithm>
#include <set>
@ -101,7 +102,7 @@ private:
uint32_t hash = ((a << 5) + a) ^ b;
return hash;
}
public:
public:
void hash32(uint32_t i) {
state = djb2_xor(i, state);
state = mkhash_xorshift(fudge ^ state);
@ -128,6 +129,7 @@ private:
*this = hash_ops<T>::hash_into(t, *this);
}
[[deprecated]]
void commutative_eat(hash_t t) {
state ^= t;
}
@ -357,6 +359,29 @@ 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;
// Computes the hash value of an unordered set of elements.
// See https://www.preprints.org/manuscript/201710.0192/v1/download.
// This is the Sum(4) algorithm from that paper, which has good collision resistance,
// much better than Sum(1) or Xor(1) (and somewhat better than Xor(4)).
class commutative_hash {
public:
commutative_hash() {
buckets.fill(0);
}
void eat(Hasher h) {
Hasher::hash_t v = h.yield();
size_t index = v & (buckets.size() - 1);
buckets[index] += v;
}
[[nodiscard]] Hasher hash_into(Hasher h) const {
for (auto b : buckets)
h.eat(b);
return h;
}
private:
std::array<Hasher::hash_t, 4> buckets;
};
template<typename K, typename T, typename OPS>
class dict {
struct entry_t
@ -802,14 +827,14 @@ public:
}
[[nodiscard]] Hasher hash_into(Hasher h) const {
commutative_hash comm;
for (auto &it : entries) {
Hasher entry_hash;
entry_hash.eat(it.udata.first);
entry_hash.eat(it.udata.second);
h.commutative_eat(entry_hash.yield());
comm.eat(entry_hash);
}
h.eat(entries.size());
return h;
return comm.hash_into(h);
}
void reserve(size_t n) { entries.reserve(n); }
@ -1190,11 +1215,11 @@ public:
}
[[nodiscard]] Hasher hash_into(Hasher h) const {
commutative_hash comm;
for (auto &it : entries) {
h.commutative_eat(ops.hash(it.udata).yield());
comm.eat(ops.hash(it.udata));
}
h.eat(entries.size());
return h;
return comm.hash_into(h);
}
void reserve(size_t n) { entries.reserve(n); }
@ -1359,7 +1384,8 @@ public:
return p;
}
// Merge sets if the given indices belong to different sets
// Merge sets if the given indices belong to different sets.
// Makes ifind(j) the root of the merged set.
void imerge(int i, int j)
{
i = ifind(i);

View file

@ -412,6 +412,70 @@ static std::string string_view_stringf(std::string_view spec, ...)
return result;
}
static int spec_parameter_size(std::string_view spec)
{
// Every valid spec starts with '%' which means the code below
// won't look before the spec start.
switch (spec[spec.size() - 1]) {
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
switch (spec[spec.size() - 2]) {
case 'h':
if (spec[spec.size() - 3] == 'h')
return sizeof(char);
return sizeof(short);
case 'l':
if (spec[spec.size() - 3] == 'l')
return sizeof(long long);
return sizeof(long);
case 'L':
case 'q':
return sizeof(long long);
case 'j':
return sizeof(intmax_t);
case 'z':
case 'Z':
return sizeof(size_t);
case 't':
return sizeof(ptrdiff_t);
}
return sizeof(int);
case 'e':
case 'E':
case 'f':
case 'F':
case 'g':
case 'G':
case 'a':
case 'A':
if (spec[spec.size() - 2] == 'L')
return sizeof(long double);
if (spec[spec.size() - 2] == 'l' && spec[spec.size() - 3] == 'l')
return sizeof(long double);
return sizeof(double);
case 'c':
if (spec[spec.size() - 2] == 'l') {
return sizeof(wchar_t);
}
return sizeof(unsigned char);
case 'C':
return sizeof(wchar_t);
case 's':
case 'p':
case 'S':
case 'n':
return sizeof(void *);
case 'm':
return sizeof(int);
default:
return -1;
}
}
template <typename Arg>
static void format_emit_stringf(std::string &result, std::string_view spec, int *dynamic_ints,
DynamicIntCount num_dynamic_ints, Arg arg)
@ -439,7 +503,13 @@ void format_emit_long_long(std::string &result, std::string_view spec, int *dyna
result += std::to_string(static_cast<int>(arg));
return;
}
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
if (spec_parameter_size(spec) <= 4) {
// On some platforms (Wasm) we must ensure that the arg is properly aligned
// after the dynamic `int` parameters.
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (int)arg);
} else {
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
}
}
void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
@ -454,7 +524,13 @@ void format_emit_unsigned_long_long(std::string &result, std::string_view spec,
result += static_cast<char>(arg);
return;
}
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
if (spec_parameter_size(spec) <= 4) {
// On some platforms (Wasm) we must ensure that the arg is properly aligned
// after the dynamic `int` parameters.
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, (unsigned int)arg);
} else {
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
}
}
void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints,

View file

@ -237,6 +237,42 @@ using sort_by_name_id_guard = typename std::enable_if<std::is_same<T,RTLIL::Cell
template<typename T>
class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name_id<typename std::remove_pointer<T>::type>> {};
struct SigMapView
{
mfp<SigBit> database;
// Modify bit to its representative
void apply(RTLIL::SigBit &bit) const
{
bit = database.find(bit);
}
void apply(RTLIL::SigSpec &sig) const
{
for (auto &bit : sig)
apply(bit);
}
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
{
apply(bit);
return bit;
}
RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
{
apply(sig);
return sig;
}
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
{
SigSpec sig(wire);
apply(sig);
return sig;
}
};
/**
* SigMap wraps a union-find "database"
* to map SigBits of a module to canonical representative SigBits.
@ -244,10 +280,8 @@ class SigSet<T, sort_by_name_id_guard<T>> : public SigSet<T, RTLIL::sort_by_name
* If a SigBit has a const state (impl: bit.wire is nullptr),
* it's promoted to a representative.
*/
struct SigMap
struct SigMap final : public SigMapView
{
mfp<SigBit> database;
SigMap(RTLIL::Module *module = NULL)
{
if (module != NULL)
@ -320,37 +354,6 @@ struct SigMap
inline void add(Wire *wire) { return add(RTLIL::SigSpec(wire)); }
// Modify bit to its representative
void apply(RTLIL::SigBit &bit) const
{
bit = database.find(bit);
}
void apply(RTLIL::SigSpec &sig) const
{
for (auto &bit : sig)
apply(bit);
}
RTLIL::SigBit operator()(RTLIL::SigBit bit) const
{
apply(bit);
return bit;
}
RTLIL::SigSpec operator()(RTLIL::SigSpec sig) const
{
apply(sig);
return sig;
}
RTLIL::SigSpec operator()(RTLIL::Wire *wire) const
{
SigSpec sig(wire);
apply(sig);
return sig;
}
// All non-const bits
RTLIL::SigSpec allbits() const
{
@ -362,6 +365,107 @@ struct SigMap
}
};
/**
* SiValgMap wraps a union-find "database" to map SigBits of a module to
* canonical representative SigBits plus some optional Val value associated with the bits.
* Val has a commutative, associative, idempotent operator|=, a default constructor
* which constructs an identity element, and a copy constructor.
* SigBits that are connected share a set in the underlying database;
* the associated value is the "sum" of all the values associated with the contributing bits.
* If any of the SigBits in a set are a constant, the canonical SigBit is a constant.
*/
template <class Val>
struct SigValMap final : public SigMapView
{
dict<SigBit, Val> values;
void swap(SigValMap<Val> &other)
{
database.swap(other.database);
values.swap(other.values);
}
void clear()
{
database.clear();
values.clear();
}
// Rebuild SigMap for all connections in module
void set(RTLIL::Module *module)
{
int bitcount = 0;
for (auto &it : module->connections())
bitcount += it.first.size();
database.clear();
values.clear();
database.reserve(bitcount);
for (auto &it : module->connections())
add(it.first, it.second);
}
// Add connections from "from" to "to", bit-by-bit.
void add(const RTLIL::SigSpec& from, const RTLIL::SigSpec& to)
{
log_assert(GetSize(from) == GetSize(to));
for (int i = 0; i < GetSize(from); i++)
{
int bfi = database.lookup(from[i]);
int bti = database.lookup(to[i]);
if (bfi == bti) {
continue;
}
const RTLIL::SigBit &bf = database[bfi];
const RTLIL::SigBit &bt = database[bti];
if (bf.wire == nullptr) {
// bf is constant so make it the canonical representative.
database.imerge(bti, bfi);
merge_value(bt, bf);
} else {
// Make bt the canonical representative.
database.imerge(bfi, bti);
merge_value(bf, bt);
}
}
}
void addVal(const RTLIL::SigBit &bit, const Val &val)
{
values[database.find(bit)] |= val;
}
void addVal(const RTLIL::SigSpec &sig, const Val &val)
{
for (const auto &bit : sig)
addVal(bit, val);
}
Val apply_and_get_value(RTLIL::SigBit &bit) const
{
bit = database.find(bit);
auto it = values.find(bit);
return it == values.end() ? Val() : it->second;
}
private:
void merge_value(const RTLIL::SigBit &from, const RTLIL::SigBit &to)
{
auto it = values.find(from);
if (it == values.end()) {
return;
}
// values[to] could resize the underlying `entries` so
// finish using `it` first.
Val v = it->second;
values.erase(it);
values[to] |= v;
}
};
YOSYS_NAMESPACE_END
#endif /* SIGTOOLS_H */

View file

@ -20,6 +20,7 @@
#ifndef YOSYS_COMMON_H
#define YOSYS_COMMON_H
#include <array>
#include <map>
#include <set>
#include <tuple>