3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-11 03:33:36 +00:00

const: string and bits in a variant

This commit is contained in:
Emil J. Tywoniak 2024-07-30 19:58:43 +02:00
parent 498e0498c5
commit 5f85eef3b4
6 changed files with 208 additions and 128 deletions

View file

@ -1733,31 +1733,15 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict<RTLIL::IdStr
static std::string serialize_param_value(const RTLIL::Const &val) {
std::string res;
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_STRING) {
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_STRING)
res.push_back('t');
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_STRING_COMPACT) {
res += stringf("%d", GetSize(val));
res.push_back('\'');
res.append(val.decode_string());
return res;
}
}
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_SIGNED)
res.push_back('s');
if (val.flags & RTLIL::ConstFlags::CONST_FLAG_REAL)
res.push_back('r');
res += stringf("%d", GetSize(val));
res.push_back('\'');
for (int i = GetSize(val) - 1; i >= 0; i--) {
switch (val.bits()[i]) {
case RTLIL::State::S0: res.push_back('0'); break;
case RTLIL::State::S1: res.push_back('1'); break;
case RTLIL::State::Sx: res.push_back('x'); break;
case RTLIL::State::Sz: res.push_back('z'); break;
case RTLIL::State::Sa: res.push_back('?'); break;
case RTLIL::State::Sm: res.push_back('m'); break;
}
}
res.append(val.as_string("?"));
return res;
}

View file

@ -72,7 +72,7 @@ static RTLIL::Const big2const(const BigInteger &val, int result_len, int undef_b
BigUnsigned mag = val.getMagnitude();
RTLIL::Const result(0, result_len);
log_debug("size %d\n", result.bits().size());
if (!mag.isZero())
{
if (val.getSign() < 0)

View file

@ -274,10 +274,7 @@ Aig::Aig(Cell *cell)
name = mkname_last + stringf(":%d%c", p.second.as_int(), mkname_is_signed ? 'S' : 'U');
} else {
mkname_last = name;
if (p.second.flags & RTLIL::CONST_FLAG_STRING_COMPACT)
name += ":" + p.second.decode_string();
else
name += stringf(":%d", p.second.as_int());
name += ":" + p.second.pretty_fmt();
}
mkname_a_signed = false;

View file

@ -202,16 +202,18 @@ const pool<IdString> &RTLIL::builtin_ff_cell_types() {
RTLIL::Const::Const(const std::string &str)
{
flags = RTLIL::CONST_FLAG_STRING | CONST_FLAG_STRING_COMPACT;
this->str = str;
flags = RTLIL::CONST_FLAG_STRING;
backing = str;
}
RTLIL::Const::Const(int val, int width)
{
flags = RTLIL::CONST_FLAG_NONE;
bits_.reserve(width);
backing = bitvectype();
bitvectype& bv = assert_get_bits("Const::Const(int, int)");
bv.reserve(width);
for (int i = 0; i < width; i++) {
bits_.push_back((val & 1) != 0 ? State::S1 : State::S0);
bv.push_back((val & 1) != 0 ? State::S1 : State::S0);
val = val >> 1;
}
}
@ -219,75 +221,91 @@ RTLIL::Const::Const(int val, int width)
RTLIL::Const::Const(RTLIL::State bit, int width)
{
flags = RTLIL::CONST_FLAG_NONE;
bits_.reserve(width);
backing = bitvectype();
bitvectype& bv = assert_get_bits("Const::Const(State, int)");
bv.reserve(width);
for (int i = 0; i < width; i++)
bits_.push_back(bit);
bv.push_back(bit);
}
RTLIL::Const::Const(const std::vector<bool> &bits)
{
flags = RTLIL::CONST_FLAG_NONE;
this->bits_.reserve(bits.size());
backing = bitvectype();
bitvectype& bv = assert_get_bits("Const::Const(std::vector<bool>)");
bv.reserve(bits.size());
for (const auto &b : bits)
this->bits_.emplace_back(b ? State::S1 : State::S0);
bv.emplace_back(b ? State::S1 : State::S0);
}
[[nodiscard]] RTLIL::Const::bitvectype& RTLIL::Const::assert_get_bits(const char* ctx) const {
// return assert_get<bitvectype, decltype(backing)>(&backing, ctx);
return std::get<bitvectype>(backing);
}
[[nodiscard]] std::string& RTLIL::Const::assert_get_str(const char* ctx) const {
// return assert_get<std::string, decltype(backing)>(&backing, ctx);
return std::get<std::string>(backing);
}
bool RTLIL::Const::operator <(const RTLIL::Const &other) const
{
if ((flags & CONST_FLAG_STRING_COMPACT) != (other.flags & CONST_FLAG_STRING_COMPACT))
const char* ctx = "operator<";
if (std::get_if<std::string>(&backing) != std::get_if<std::string>(&other.backing))
return decode_string() < other.decode_string();
if (flags & CONST_FLAG_STRING_COMPACT)
return str < other.str;
if (std::get_if<std::string>(&backing))
return assert_get_str(ctx) < other.assert_get_str(ctx);
if (bits_.size() != other.bits_.size())
return bits_.size() < other.bits_.size();
for (size_t i = 0; i < bits_.size(); i++)
if (bits_[i] != other.bits_[i])
return bits_[i] < other.bits_[i];
bitvectype& bv = assert_get_bits(ctx);
auto other_bv = other.assert_get_bits(ctx);
if (bv.size() != other_bv.size())
return bv.size() < other_bv.size();
for (size_t i = 0; i < bv.size(); i++)
if (bv[i] != other_bv[i])
return bv[i] < other_bv[i];
return false;
}
bool RTLIL::Const::operator ==(const RTLIL::Const &other) const
{
if ((flags & CONST_FLAG_STRING_COMPACT) != (other.flags & CONST_FLAG_STRING_COMPACT))
const char* ctx = "operator==";
if (std::get_if<std::string>(&backing) != std::get_if<std::string>(&other.backing))
return decode_string() == other.decode_string();
if (flags & CONST_FLAG_STRING_COMPACT)
return str == other.str;
return bits_ == other.bits_;
if (std::get_if<std::string>(&backing))
return assert_get_str(ctx) == other.assert_get_str(ctx);
return assert_get_bits(ctx) == other.assert_get_bits(ctx);
}
bool RTLIL::Const::operator !=(const RTLIL::Const &other) const
{
if ((flags & CONST_FLAG_STRING_COMPACT) != (other.flags & CONST_FLAG_STRING_COMPACT))
return decode_string() != other.decode_string();
if (flags & CONST_FLAG_STRING_COMPACT)
return str != other.str;
return bits_ != other.bits_;
return !(*this == other);
}
std::vector<RTLIL::State>& RTLIL::Const::bits()
{
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
return bits_;
bitvectorize();
return assert_get_bits("Const::bits()");
}
const std::vector<RTLIL::State>& RTLIL::Const::bits() const
{
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
return bits_;
bitvectorize();
return assert_get_bits("Const::bits()");
}
std::vector<RTLIL::State> RTLIL::Const::to_bits() const
{
if (!(flags & CONST_FLAG_STRING_COMPACT)) {
return bits_;
if (auto bv = std::get_if<bitvectype>(&backing)) {
return *bv;
}
std::vector<RTLIL::State> b;
auto str = assert_get_str("Const::to_bits");
bitvectype b;
b.reserve(str.size() * 8);
for (int i = str.size()-1; i >= 0; i--) {
unsigned char ch = str[i];
@ -299,40 +317,57 @@ std::vector<RTLIL::State> RTLIL::Const::to_bits() const
return b;
}
std::string RTLIL::Const::pretty_fmt() const {
if (std::get_if<std::string>(&backing))
return decode_string();
else
return std::to_string(as_int());
}
std::string RTLIL::Const::pretty_fmt_undef() const {
if (std::get_if<std::string>(&backing))
return decode_string();
else
return as_string();
}
bool RTLIL::Const::as_bool() const
{
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
for (size_t i = 0; i < bits_.size(); i++)
if (bits_[i] == State::S1)
bitvectorize();
bitvectype& bv = assert_get_bits("Const::as_bool");
for (size_t i = 0; i < bv.size(); i++)
if (bv[i] == State::S1)
return true;
return false;
}
int RTLIL::Const::as_int(bool is_signed) const
{
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
bitvectorize();
bitvectype& bv = assert_get_bits("Const::as_int");
int32_t ret = 0;
for (size_t i = 0; i < bits_.size() && i < 32; i++)
if (bits_[i] == State::S1)
for (size_t i = 0; i < bv.size() && i < 32; i++)
if (bv[i] == State::S1)
ret |= 1 << i;
if (is_signed && bits_.back() == State::S1)
for (size_t i = bits_.size(); i < 32; i++)
if (is_signed && bv.back() == State::S1)
for (size_t i = bv.size(); i < 32; i++)
ret |= 1 << i;
return ret;
}
std::string RTLIL::Const::as_string() const
std::string RTLIL::Const::as_string(std::string any) const
{
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
bitvectorize();
bitvectype& bv = assert_get_bits("Const::as_bool");
std::string ret;
ret.reserve(bits_.size());
for (size_t i = bits_.size(); i > 0; i--)
switch (bits_[i-1]) {
ret.reserve(bv.size());
for (size_t i = bv.size(); i > 0; i--)
switch (bv[i-1]) {
case S0: ret += "0"; break;
case S1: ret += "1"; break;
case Sx: ret += "x"; break;
case Sz: ret += "z"; break;
case Sa: ret += "-"; break;
case Sa: ret += any; break;
case Sm: ret += "m"; break;
}
return ret;
@ -341,25 +376,29 @@ std::string RTLIL::Const::as_string() const
RTLIL::Const RTLIL::Const::from_string(const std::string &str)
{
Const c;
c.bits_.reserve(str.size());
c.backing = bitvectype();
bitvectype& bv = c.assert_get_bits("Const::from_string");
bv.reserve(str.size());
for (auto it = str.rbegin(); it != str.rend(); it++)
switch (*it) {
case '0': c.bits_.push_back(State::S0); break;
case '1': c.bits_.push_back(State::S1); break;
case 'x': c.bits_.push_back(State::Sx); break;
case 'z': c.bits_.push_back(State::Sz); break;
case 'm': c.bits_.push_back(State::Sm); break;
default: c.bits_.push_back(State::Sa);
case '0': bv.push_back(State::S0); break;
case '1': bv.push_back(State::S1); break;
case 'x': bv.push_back(State::Sx); break;
case 'z': bv.push_back(State::Sz); break;
case 'm': bv.push_back(State::Sm); break;
default: bv.push_back(State::Sa);
}
return c;
}
std::string RTLIL::Const::decode_string() const
{
if (flags & CONST_FLAG_STRING_COMPACT)
return str;
if (auto str = std::get_if<std::string>(&backing))
return *str;
const int n = GetSize(bits_);
bitvectorize();
bitvectype& bv = assert_get_bits("Const::decode_string");
const int n = GetSize(bv);
const int n_over_8 = n / 8;
std::string s;
s.reserve(n_over_8);
@ -367,7 +406,7 @@ std::string RTLIL::Const::decode_string() const
if (i < n) {
char ch = 0;
for (int j = 0; j < (n - i); j++) {
if (bits_[i + j] == RTLIL::State::S1) {
if (bv[i + j] == RTLIL::State::S1) {
ch |= 1 << j;
}
}
@ -378,7 +417,7 @@ std::string RTLIL::Const::decode_string() const
for (; i >= 0; i -= 8) {
char ch = 0;
for (int j = 0; j < 8; j++) {
if (bits_[i + j] == RTLIL::State::S1) {
if (bv[i + j] == RTLIL::State::S1) {
ch |= 1 << j;
}
}
@ -390,10 +429,11 @@ std::string RTLIL::Const::decode_string() const
bool RTLIL::Const::is_fully_zero() const
{
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
bitvectorize();
bitvectype& bv = assert_get_bits("Const::decode_string");
cover("kernel.rtlil.const.is_fully_zero");
for (const auto &bit : bits_)
for (const auto &bit : bv)
if (bit != RTLIL::State::S0)
return false;
@ -402,10 +442,11 @@ bool RTLIL::Const::is_fully_zero() const
bool RTLIL::Const::is_fully_ones() const
{
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
bitvectorize();
bitvectype& bv = assert_get_bits("Const::decode_string");
cover("kernel.rtlil.const.is_fully_ones");
for (const auto &bit : bits_)
for (const auto &bit : bv)
if (bit != RTLIL::State::S1)
return false;
@ -416,10 +457,10 @@ bool RTLIL::Const::is_fully_def() const
{
cover("kernel.rtlil.const.is_fully_def");
if (flags & CONST_FLAG_STRING_COMPACT)
return true;
bitvectorize();
bitvectype& bv = assert_get_bits("Const::decode_string");
for (const auto &bit : bits_)
for (const auto &bit : bv)
if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
return false;
@ -430,10 +471,10 @@ bool RTLIL::Const::is_fully_undef() const
{
cover("kernel.rtlil.const.is_fully_undef");
if (flags & CONST_FLAG_STRING_COMPACT)
return false;
bitvectorize();
bitvectype& bv = assert_get_bits("Const::decode_string");
for (const auto &bit : bits_)
for (const auto &bit : bv)
if (bit != RTLIL::State::Sx && bit != RTLIL::State::Sz)
return false;
@ -444,10 +485,10 @@ bool RTLIL::Const::is_fully_undef_x_only() const
{
cover("kernel.rtlil.const.is_fully_undef_x_only");
if (flags & CONST_FLAG_STRING_COMPACT)
return false;
bitvectorize();
bitvectype& bv = assert_get_bits("Const::decode_string");
for (const auto &bit : bits_)
for (const auto &bit : bv)
if (bit != RTLIL::State::Sx)
return false;
@ -458,12 +499,12 @@ bool RTLIL::Const::is_onehot(int *pos) const
{
cover("kernel.rtlil.const.is_onehot");
if (flags & CONST_FLAG_STRING_COMPACT)
return false;
bitvectorize();
bitvectype& bv = assert_get_bits("Const::decode_string");
bool found = false;
for (int i = 0; i < GetSize(*this); i++) {
auto &bit = bits_[i];
auto &bit = bv[i];
if (bit != RTLIL::State::S0 && bit != RTLIL::State::S1)
return false;
if (bit == RTLIL::State::S1) {

View file

@ -22,6 +22,8 @@
#include "kernel/yosys_common.h"
#include "kernel/yosys.h"
#include <variant>
#include "kernel/utils.h"
YOSYS_NAMESPACE_BEGIN
@ -47,14 +49,21 @@ namespace RTLIL
STi = 7 // init
};
// Semantic metadata - how can this constant be interpreted?
// Values may be generally non-exclusive
enum ConstFlags : unsigned char {
CONST_FLAG_NONE = 0,
CONST_FLAG_STRING = 1,
CONST_FLAG_STRING_COMPACT = 2, // internally efficient string storage
CONST_FLAG_SIGNED = 4, // only used for parameters
CONST_FLAG_REAL = 8, // only used for parameters
CONST_FLAG_SIGNED = 2, // only used for parameters
CONST_FLAG_REAL = 4, // only used for parameters
};
// // Union discriminator. Values are exclusive
// enum ConstRepr : unsigned char {
// CONST_REPR_BITS = 1,
// CONST_REPR_STRING = 2,
// };
struct Const;
struct AttrObject;
struct Selection;
@ -660,16 +669,16 @@ struct RTLIL::Const
{
private:
// TODO unionize
std::vector<RTLIL::State> bits_;
std::string str; // active on CONST_FLAG_STRING_COMPACT
typedef std::vector<RTLIL::State> bitvectype;
mutable std::variant<bitvectype, std::string> backing;
public:
int flags;
short flags;
Const() : flags(RTLIL::CONST_FLAG_NONE) {}
Const() : backing(std::vector<RTLIL::State>()), flags(RTLIL::CONST_FLAG_NONE) {}
Const(const std::string &str);
Const(int val, int width = 32);
Const(RTLIL::State bit, int width = 1);
Const(const std::vector<RTLIL::State> &bits) : bits_(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<RTLIL::State> &bits) : backing(bits) { flags = CONST_FLAG_NONE; }
Const(const std::vector<bool> &bits);
Const(const RTLIL::Const &c) = default;
RTLIL::Const &operator =(const RTLIL::Const &other) = default;
@ -678,22 +687,68 @@ struct RTLIL::Const
bool operator ==(const RTLIL::Const &other) const;
bool operator !=(const RTLIL::Const &other) const;
bitvectype& assert_get_bits(const char* ctx) const;
std::string& assert_get_str(const char* ctx) const;
const std::vector<RTLIL::State>& bits() const;
std::vector<RTLIL::State>& bits();
bool as_bool() const;
int as_int(bool is_signed = false) const;
std::string as_string() const;
std::string as_string(std::string any = "-") const;
static Const from_string(const std::string &str);
std::vector<RTLIL::State> to_bits() const;
std::string pretty_fmt() const;
std::string pretty_fmt_undef() const;
std::string decode_string() const;
// (flags & CONST_FLAG_STRING_COMPACT) ? : ;
inline size_t size() const { return (flags & CONST_FLAG_STRING_COMPACT) ? 8 * str.size() : bits_.size(); }
inline bool empty() const { return (flags & CONST_FLAG_STRING_COMPACT) ? str.empty() : bits_.empty(); }
inline RTLIL::State &operator[](int index) { log_assert(!(flags & CONST_FLAG_STRING_COMPACT)); return bits_.at(index); }
inline const RTLIL::State &operator[](int index) const { log_assert(!(flags & CONST_FLAG_STRING_COMPACT)); return bits_.at(index); }
inline decltype(bits_)::iterator begin() { log_assert(!(flags & CONST_FLAG_STRING_COMPACT)); return bits_.begin(); }
inline decltype(bits_)::iterator end() { log_assert(!(flags & CONST_FLAG_STRING_COMPACT)); return bits_.end(); }
inline size_t size() const {
if (auto str = std::get_if<std::string>(&backing))
return 8 * str->size();
else
return assert_get_bits("Const::size").size();
}
inline bool empty() const {
if (auto str = std::get_if<std::string>(&backing))
return str->empty();
else
return assert_get_bits("Const::empty").empty();
}
void bitvectorize() const {
if (std::get_if<bitvectype>(&backing))
return;
std::string& str = assert_get_str("Const::bitvectorize");
bitvectype bits;
bits.reserve(str.size() * 8);
for (int i = str.size() - 1; i >= 0; i--) {
unsigned char ch = str[i];
for (int j = 0; j < 8; j++) {
bits.push_back((ch & 1) != 0 ? State::S1 : State::S0);
ch = ch >> 1;
}
}
backing = bits;
}
inline RTLIL::State &operator[](int index) {
bitvectorize();
return assert_get_bits("Const::operator[]").at(index);
}
inline const RTLIL::State &operator[](int index) const {
bitvectorize();
return assert_get_bits("const Const::operator[]").at(index);
}
inline bitvectype::iterator begin() {
bitvectorize();
return assert_get_bits("Const bit iterator begin()").begin();
}
inline bitvectype::iterator end() {
bitvectorize();
return assert_get_bits("Const bit iterator end()").end();
}
bool is_fully_zero() const;
bool is_fully_ones() const;
@ -703,32 +758,35 @@ struct RTLIL::Const
bool is_onehot(int *pos = nullptr) const;
inline RTLIL::Const extract(int offset, int len = 1, RTLIL::State padding = RTLIL::State::S0) const {
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
RTLIL::Const ret;
ret.bits_.reserve(len);
bitvectorize();
bitvectype& bv = assert_get_bits("Const::extract");
bitvectype ret_bv;
ret_bv.reserve(len);
for (int i = offset; i < offset + len; i++)
ret.bits_.push_back(i < GetSize(bits_) ? bits_[i] : padding);
return ret;
ret_bv.push_back(i < GetSize(bv) ? bv[i] : padding);
return RTLIL::Const(ret_bv);
}
void extu(int width) {
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
bits_.resize(width, RTLIL::State::S0);
bitvectorize();
assert_get_bits("Const::extu").resize(width, RTLIL::State::S0);
}
void exts(int width) {
log_assert(!(flags & CONST_FLAG_STRING_COMPACT));
bits_.resize(width, bits_.empty() ? RTLIL::State::Sx : bits_.back());
bitvectorize();
bitvectype& bv = assert_get_bits("Const::exts");
bv.resize(width, bv.empty() ? RTLIL::State::Sx : bv.back());
}
inline unsigned int hash() const {
unsigned int h = mkhash_init;
if(flags & CONST_FLAG_STRING_COMPACT) {
for (auto c : str)
if(auto str = std::get_if<std::string>(&backing)) {
for (auto c : *str)
h = mkhash(h, c);
} else {
for (auto b : bits_)
bitvectype& bv = assert_get_bits("Const::hash");
for (auto b : bv)
h = mkhash(h, b);
}
return h;

View file

@ -143,7 +143,7 @@ struct OptMergeWorker
for (auto &it : cell->parameters) {
Const c = it.second;
std::string s = "P " + it.first.str() + "=";
s += (c.flags & RTLIL::CONST_FLAG_STRING_COMPACT) ? c.decode_string() : c.as_string();
s += c.pretty_fmt_undef();
s += "\n";
hash_conn_strings.push_back(s);
}