diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 9b7434478..bc1233bbc 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -1733,31 +1733,15 @@ RTLIL::IdString AstModule::derive(RTLIL::Design *design, const dict= 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; } diff --git a/kernel/calc.cc b/kernel/calc.cc index 77d8d78c9..2c6502666 100644 --- a/kernel/calc.cc +++ b/kernel/calc.cc @@ -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) diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 5335e4198..358c41877 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -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; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 47cde8d3d..7d8509778 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -202,16 +202,18 @@ const pool &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 &bits) { flags = RTLIL::CONST_FLAG_NONE; - this->bits_.reserve(bits.size()); + backing = bitvectype(); + bitvectype& bv = assert_get_bits("Const::Const(std::vector)"); + 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(&backing, ctx); + return std::get(backing); +} + +[[nodiscard]] std::string& RTLIL::Const::assert_get_str(const char* ctx) const { + // return assert_get(&backing, ctx); + return std::get(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(&backing) != std::get_if(&other.backing)) return decode_string() < other.decode_string(); - if (flags & CONST_FLAG_STRING_COMPACT) - return str < other.str; + if (std::get_if(&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(&backing) != std::get_if(&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(&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::Const::bits() { - log_assert(!(flags & CONST_FLAG_STRING_COMPACT)); - return bits_; + bitvectorize(); + return assert_get_bits("Const::bits()"); } const std::vector& RTLIL::Const::bits() const { - log_assert(!(flags & CONST_FLAG_STRING_COMPACT)); - return bits_; + bitvectorize(); + return assert_get_bits("Const::bits()"); } std::vector RTLIL::Const::to_bits() const { - if (!(flags & CONST_FLAG_STRING_COMPACT)) { - return bits_; + if (auto bv = std::get_if(&backing)) { + return *bv; } - - std::vector 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::Const::to_bits() const return b; } +std::string RTLIL::Const::pretty_fmt() const { + if (std::get_if(&backing)) + return decode_string(); + else + return std::to_string(as_int()); +} + +std::string RTLIL::Const::pretty_fmt_undef() const { + if (std::get_if(&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(&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) { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index 02cc2c799..92e291430 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -22,6 +22,8 @@ #include "kernel/yosys_common.h" #include "kernel/yosys.h" +#include +#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 bits_; - std::string str; // active on CONST_FLAG_STRING_COMPACT + typedef std::vector bitvectype; + mutable std::variant backing; public: - int flags; + short flags; - Const() : flags(RTLIL::CONST_FLAG_NONE) {} + Const() : backing(std::vector()), 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 &bits) : bits_(bits) { flags = CONST_FLAG_NONE; } + Const(const std::vector &bits) : backing(bits) { flags = CONST_FLAG_NONE; } Const(const std::vector &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& bits() const; std::vector& 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 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(&backing)) + return 8 * str->size(); + else + return assert_get_bits("Const::size").size(); + } + + inline bool empty() const { + if (auto str = std::get_if(&backing)) + return str->empty(); + else + return assert_get_bits("Const::empty").empty(); + } + + void bitvectorize() const { + if (std::get_if(&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(&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; diff --git a/passes/opt/opt_merge.cc b/passes/opt/opt_merge.cc index 78566f9da..c5dc2057e 100644 --- a/passes/opt/opt_merge.cc +++ b/passes/opt/opt_merge.cc @@ -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); }