mirror of
https://github.com/YosysHQ/yosys
synced 2026-07-15 11:45:41 +00:00
Merge from upstream
This commit is contained in:
commit
e54fa487b8
29 changed files with 1314 additions and 793 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ YOSYS_NAMESPACE_BEGIN
|
|||
|
||||
struct FfMergeHelper
|
||||
{
|
||||
const SigMap *sigmap;
|
||||
const SigMapView *sigmap;
|
||||
RTLIL::Module *module;
|
||||
FfInitVals *initvals;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
80
kernel/io.cc
80
kernel/io.cc
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#ifndef YOSYS_COMMON_H
|
||||
#define YOSYS_COMMON_H
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <tuple>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue