Introduce small object optimization to V3Number (#3034)

This commit is contained in:
Yutetsu TAKATSUKASA 2021-06-30 21:20:56 +09:00 committed by GitHub
parent 2cdf0aae72
commit 22e0f3edbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 169 additions and 120 deletions

View File

@ -101,10 +101,9 @@ V3Number::V3Number(VerilogStringLiteral, AstNode* nodep, const string& str) {
m_fromString = true;
for (unsigned pos = 0; pos < str.length(); ++pos) {
const int topos = str.length() - 1 - pos;
ValueAndX& v = m_value[topos / 4];
for (int bit = 0; bit < 8; ++bit) {
if (str[pos] & (1UL << bit)) {
m_value[topos / 4] |= (1UL << (bit + (topos % 4) * 8));
}
if (str[pos] & (1UL << bit)) { v.m_value |= (1UL << (bit + (topos % 4) * 8)); }
}
}
opCleanThis(true);
@ -159,7 +158,7 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl)
base = 'd';
}
for (int i = 0; i < words(); ++i) m_value[i] = m_valueX[i] = 0;
for (int i = 0; i < words(); ++i) m_value[i] = {0, 0};
// Special SystemVerilog unsized constructs
if (base == '0') {
@ -216,7 +215,7 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl)
if (olen <= 7) { // 10000000 fits in 32 bits, so ok
// Constants are common, so for speed avoid wide math until we need it
val = val * 10 + (*cp - '0');
m_value[0] = val;
m_value[0].m_value = val;
} else { // Wide; all previous digits are already in m_value[0]
// this = (this * 10)/*product*/ + (*cp-'0')/*addend*/
// Assumed rare; lots of optimizations are possible here
@ -373,31 +372,31 @@ int V3Number::log2b(uint32_t num) {
// Setters
V3Number& V3Number::setZero() {
for (int i = 0; i < words(); i++) m_value[i] = m_valueX[i] = 0;
for (int i = 0; i < words(); i++) m_value[i] = {0, 0};
return *this;
}
V3Number& V3Number::setQuad(vluint64_t value) {
for (int i = 0; i < words(); i++) m_value[i] = m_valueX[i] = 0;
m_value[0] = value & 0xffffffffULL;
m_value[1] = (value >> 32ULL) & 0xffffffffULL;
for (int i = 0; i < words(); i++) m_value[i] = {0, 0};
m_value[0].m_value = value & 0xffffffffULL;
if (width() > 32) m_value[1].m_value = (value >> 32ULL) & 0xffffffffULL;
opCleanThis();
return *this;
}
V3Number& V3Number::setLong(uint32_t value) {
for (int i = 0; i < words(); i++) m_value[i] = m_valueX[i] = 0;
m_value[0] = value;
for (int i = 0; i < words(); i++) m_value[i] = {0, 0};
m_value[0].m_value = value;
opCleanThis();
return *this;
}
V3Number& V3Number::setLongS(vlsint32_t value) {
for (int i = 0; i < words(); i++) m_value[i] = m_valueX[i] = 0;
for (int i = 0; i < words(); i++) m_value[i] = {0, 0};
union {
uint32_t u;
vlsint32_t s;
} u;
u.s = value;
if (u.s) {}
m_value[0] = u.u;
m_value[0].m_value = u.u;
opCleanThis();
return *this;
}
@ -410,41 +409,35 @@ V3Number& V3Number::setDouble(double value) {
} u;
u.d = value;
if (u.d != 0.0) {}
for (int i = 2; i < words(); i++) m_value[i] = m_valueX[i] = 0;
m_value[0] = u.u[0];
m_value[1] = u.u[1];
for (int i = 2; i < words(); i++) m_value[i] = {0, 0};
m_value[0].m_value = u.u[0];
m_value[1].m_value = u.u[1];
return *this;
}
V3Number& V3Number::setSingleBits(char value) {
for (int i = 1 /*upper*/; i < words(); i++) m_value[i] = m_valueX[i] = 0;
m_value[0] = (value == '1' || value == 'x' || value == 1 || value == 3);
m_valueX[0] = (value == 'z' || value == 'x' || value == 2 || value == 3);
for (int i = 1 /*upper*/; i < words(); i++) m_value[i] = {0, 0};
m_value[0] = {(value == '1' || value == 'x' || value == 1 || value == 3),
(value == 'z' || value == 'x' || value == 2 || value == 3)};
return *this;
}
V3Number& V3Number::setAllBits0() {
for (int i = 0; i < words(); i++) { m_value[i] = m_valueX[i] = 0; }
for (int i = 0; i < words(); i++) { m_value[i] = {0, 0}; }
return *this;
}
V3Number& V3Number::setAllBits1() {
for (int i = 0; i < words(); i++) {
m_value[i] = ~0;
m_valueX[i] = 0;
}
for (int i = 0; i < words(); i++) { m_value[i] = {~0u, 0}; }
opCleanThis();
return *this;
}
V3Number& V3Number::setAllBitsX() {
// Use setAllBitsXRemoved if calling this based on a non-X/Z input value such as divide by zero
for (int i = 0; i < words(); i++) { m_value[i] = m_valueX[i] = ~0; }
for (int i = 0; i < words(); i++) { m_value[i] = {~0u, ~0u}; }
opCleanThis();
return *this;
}
V3Number& V3Number::setAllBitsZ() {
for (int i = 0; i < words(); i++) {
m_value[i] = 0;
m_valueX[i] = ~0;
}
for (int i = 0; i < words(); i++) { m_value[i] = {0, ~0u}; }
opCleanThis();
return *this;
}
@ -485,7 +478,8 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
} else if (isString()) {
return '"' + toString() + '"';
} else {
if (VL_UNCOVERABLE((m_value[words() - 1] | m_valueX[words() - 1]) & ~hiWordMask())) {
if (VL_UNCOVERABLE((m_value[words() - 1].m_value | m_value[words() - 1].m_valueX)
& ~hiWordMask())) {
out << "%E-hidden-bits"; // LCOV_EXCL_LINE
}
}
@ -704,23 +698,25 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const {
// 'p' // Packed - converted to another code by V3Width
case 'u': { // Packed 2-state
for (int i = 0; i < words(); i++) {
str += static_cast<char>((m_value[i] >> 0) & 0xff);
str += static_cast<char>((m_value[i] >> 8) & 0xff);
str += static_cast<char>((m_value[i] >> 16) & 0xff);
str += static_cast<char>((m_value[i] >> 24) & 0xff);
const uint32_t v = m_value[i].m_value;
str += static_cast<char>((v >> 0) & 0xff);
str += static_cast<char>((v >> 8) & 0xff);
str += static_cast<char>((v >> 16) & 0xff);
str += static_cast<char>((v >> 24) & 0xff);
}
return str;
}
case 'z': { // Packed 4-state
for (int i = 0; i < words(); i++) {
str += static_cast<char>((m_value[i] >> 0) & 0xff);
str += static_cast<char>((m_value[i] >> 8) & 0xff);
str += static_cast<char>((m_value[i] >> 16) & 0xff);
str += static_cast<char>((m_value[i] >> 24) & 0xff);
str += static_cast<char>((m_valueX[i] >> 0) & 0xff);
str += static_cast<char>((m_valueX[i] >> 8) & 0xff);
str += static_cast<char>((m_valueX[i] >> 16) & 0xff);
str += static_cast<char>((m_valueX[i] >> 24) & 0xff);
const ValueAndX v = m_value[i];
str += static_cast<char>((v.m_value >> 0) & 0xff);
str += static_cast<char>((v.m_value >> 8) & 0xff);
str += static_cast<char>((v.m_value >> 16) & 0xff);
str += static_cast<char>((v.m_value >> 24) & 0xff);
str += static_cast<char>((v.m_valueX >> 0) & 0xff);
str += static_cast<char>((v.m_valueX >> 8) & 0xff);
str += static_cast<char>((v.m_valueX >> 16) & 0xff);
str += static_cast<char>((v.m_valueX >> 24) & 0xff);
}
return str;
}
@ -809,12 +805,12 @@ uint32_t V3Number::toUInt() const {
UASSERT(!isFourState(), "toUInt with 4-state " << *this);
// We allow wide numbers that represent values <= 32 bits
for (int i = 1; i < words(); ++i) {
if (m_value[i]) {
if (m_value[i].m_value) {
v3error("Value too wide for 32-bits expected in this context " << *this);
break;
}
}
return m_value[0];
return m_value[0].m_value;
}
double V3Number::toDouble() const {
@ -825,8 +821,8 @@ double V3Number::toDouble() const {
double d;
uint32_t u[2];
} u;
u.u[0] = m_value[0];
u.u[1] = m_value[1];
u.u[0] = m_value[0].m_value;
u.u[1] = m_value[1].m_value;
return u.d;
}
@ -848,14 +844,14 @@ vluint64_t V3Number::toUQuad() const {
// We allow wide numbers that represent values <= 64 bits
if (isDouble()) return static_cast<vluint64_t>(toDouble());
for (int i = 2; i < words(); ++i) {
if (m_value[i]) {
if (m_value[i].m_value) {
v3error("Value too wide for 64-bits expected in this context " << *this);
break;
}
}
if (width() <= 32) return (static_cast<vluint64_t>(toUInt()));
return ((static_cast<vluint64_t>(m_value[1]) << 32ULL)
| (static_cast<vluint64_t>(m_value[0])));
return ((static_cast<vluint64_t>(m_value[1].m_value) << 32ULL)
| (static_cast<vluint64_t>(m_value[0].m_value)));
}
vlsint64_t V3Number::toSQuad() const {
@ -886,13 +882,13 @@ string V3Number::toString() const {
V3Hash V3Number::toHash() const {
V3Hash hash(m_width);
for (int i = 0; i < words(); ++i) { hash += m_value[i]; }
for (int i = 0; i < words(); ++i) { hash += m_value[i].m_value; }
return hash;
}
uint32_t V3Number::edataWord(int eword) const {
UASSERT(!isFourState(), "edataWord with 4-state " << *this);
return m_value[eword];
return m_value[eword].m_value;
}
uint8_t V3Number::dataByte(int byte) const {
@ -901,13 +897,15 @@ uint8_t V3Number::dataByte(int byte) const {
bool V3Number::isEqZero() const {
for (int i = 0; i < words(); i++) {
if (m_value[i] || m_valueX[i]) return false;
const ValueAndX v = m_value[i];
if (v.m_value || v.m_valueX) return false;
}
return true;
}
bool V3Number::isNeqZero() const {
for (int i = 0; i < words(); i++) {
if (m_value[i] & ~m_valueX[i]) return true;
const ValueAndX v = m_value[i];
if (v.m_value & ~v.m_valueX) return true;
}
return false;
}
@ -918,9 +916,10 @@ bool V3Number::isBitsZero(int msb, int lsb) const {
return true;
}
bool V3Number::isEqOne() const {
if (m_value[0] != 1 || m_valueX[0]) return false;
if (m_value[0].m_value != 1 || m_value[0].m_valueX) return false;
for (int i = 1; i < words(); i++) {
if (m_value[i] || m_valueX[i]) return false;
const ValueAndX v = m_value[i];
if (v.m_value || v.m_valueX) return false;
}
return true;
}
@ -934,7 +933,7 @@ bool V3Number::isEqAllOnes(int optwidth) const {
bool V3Number::isFourState() const {
if (isDouble() || isString()) return false;
for (int i = 0; i < words(); ++i) {
if (m_valueX[i]) return true;
if (m_value[i].m_valueX) return true;
}
return false;
}
@ -1129,7 +1128,7 @@ V3Number& V3Number::opCountBits(const V3Number& expr, const V3Number& ctrl1, con
NUM_ASSERT_OP_ARGS4(expr, ctrl1, ctrl2, ctrl3);
NUM_ASSERT_LOGIC_ARGS4(expr, ctrl1, ctrl2, ctrl3);
setZero();
m_value[0] = expr.countBits(ctrl1, ctrl2, ctrl3);
m_value[0].m_value = expr.countBits(ctrl1, ctrl2, ctrl3);
opCleanThis();
return *this;
}
@ -1138,7 +1137,7 @@ V3Number& V3Number::opCountOnes(const V3Number& lhs) {
NUM_ASSERT_LOGIC_ARGS1(lhs);
if (lhs.isFourState()) return setAllBitsX();
setZero();
m_value[0] = lhs.countOnes();
m_value[0].m_value = lhs.countOnes();
opCleanThis();
return *this;
}
@ -1531,8 +1530,10 @@ bool V3Number::isCaseEq(const V3Number& rhs) const {
if (isString()) return toString() == rhs.toString();
if (isDouble()) return toDouble() == rhs.toDouble();
if (this->width() != rhs.width()) return false;
if (m_value != rhs.m_value) return false;
return m_valueX == rhs.m_valueX;
for (int i = 0; i < words(); ++i) {
if (!(m_value[i] == rhs.m_value[i])) return false;
}
return true;
}
V3Number& V3Number::opCaseEq(const V3Number& lhs, const V3Number& rhs) {
@ -1761,15 +1762,15 @@ V3Number& V3Number::opMul(const V3Number& lhs, const V3Number& rhs) {
opCleanThis(); // Mult produces extra bits in result
} else {
for (int lword = 0; lword < lhs.words(); lword++) {
const vluint64_t lwordval = static_cast<vluint64_t>(lhs.m_value[lword]);
const vluint64_t lwordval = static_cast<vluint64_t>(lhs.m_value[lword].m_value);
if (lwordval == 0) continue;
for (int rword = 0; rword < rhs.words(); rword++) {
const vluint64_t rwordval = static_cast<vluint64_t>(rhs.m_value[rword]);
const vluint64_t rwordval = static_cast<vluint64_t>(rhs.m_value[rword].m_value);
if (rwordval == 0) continue;
vluint64_t mul = lwordval * rwordval;
for (int qword = lword + rword; qword < this->words(); qword++) {
mul += static_cast<vluint64_t>(m_value[qword]);
m_value[qword] = (mul & 0xffffffffULL);
mul += static_cast<vluint64_t>(m_value[qword].m_value);
m_value[qword].m_value = (mul & 0xffffffffULL);
mul = (mul >> 32ULL) & 0xffffffffULL;
if (mul == 0) break;
}
@ -1886,16 +1887,17 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw - 1; j >= 0; j--) {
vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lhs.m_value[j]));
m_value[j] = unw64 / static_cast<vluint64_t>(rhs.m_value[0]);
vluint64_t unw64 = ((k << 32ULL) + static_cast<vluint64_t>(lhs.m_value[j].m_value));
m_value[j].m_value = unw64 / static_cast<vluint64_t>(rhs.m_value[0].m_value);
k = unw64
- (static_cast<vluint64_t>(m_value[j]) * static_cast<vluint64_t>(rhs.m_value[0]));
- (static_cast<vluint64_t>(m_value[j].m_value)
* static_cast<vluint64_t>(rhs.m_value[0].m_value));
}
UINFO(9, " opmoddiv-1w " << lhs << " " << rhs << " q=" << *this << " rem=0x" << std::hex
<< k << std::dec << endl);
if (is_modulus) {
setZero();
m_value[0] = k;
m_value[0].m_value = k;
}
opCleanThis();
return *this;
@ -1906,7 +1908,7 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
uint32_t vn[VL_MULS_MAX_WORDS + 1]; // v normalized
// Zero for ease of debugging and to save having to zero for shifts
for (int i = 0; i < words; i++) { m_value[i] = 0; }
for (int i = 0; i < words; i++) { m_value[i].m_value = 0; }
for (int i = 0; i < words + 1; i++) { un[i] = vn[i] = 0; } // +1 as vn may get extra word
// Algorithm requires divisor MSB to be set
@ -1914,20 +1916,22 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
int s = 31 - ((vmsbp1 - 1) & 31); // shift amount (0...31)
uint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value
for (int i = vw - 1; i > 0; i--) {
vn[i] = (rhs.m_value[i] << s) | (shift_mask & (rhs.m_value[i - 1] >> (32 - s)));
vn[i] = (rhs.m_value[i].m_value << s)
| (shift_mask & (rhs.m_value[i - 1].m_value >> (32 - s)));
}
vn[0] = rhs.m_value[0] << s;
vn[0] = rhs.m_value[0].m_value << s;
// Copy and shift dividend by same amount; may set new upper word
if (s) {
un[uw] = lhs.m_value[uw - 1] >> (32 - s);
un[uw] = lhs.m_value[uw - 1].m_value >> (32 - s);
} else {
un[uw] = 0;
}
for (int i = uw - 1; i > 0; i--) {
un[i] = (lhs.m_value[i] << s) | (shift_mask & (lhs.m_value[i - 1] >> (32 - s)));
un[i] = (lhs.m_value[i].m_value << s)
| (shift_mask & (lhs.m_value[i - 1].m_value >> (32 - s)));
}
un[0] = lhs.m_value[0] << s;
un[0] = lhs.m_value[0].m_value << s;
// printf(" un="); for (int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n");
// printf(" vn="); for (int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n");
@ -1958,11 +1962,11 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
}
t = un[j + vw] - k;
un[j + vw] = t;
this->m_value[j] = qhat; // Save quotient digit
this->m_value[j].m_value = qhat; // Save quotient digit
if (t < 0) {
// Over subtracted; correct by adding back
this->m_value[j]--;
this->m_value[j].m_value--;
k = 0;
for (int i = 0; i < vw; i++) {
t = static_cast<vluint64_t>(un[i + j]) + static_cast<vluint64_t>(vn[i]) + k;
@ -1980,9 +1984,9 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
if (is_modulus) { // modulus
// Need to reverse normalization on copy to output
for (int i = 0; i < vw; i++) {
m_value[i] = (un[i] >> s) | (shift_mask & (un[i + 1] << (32 - s)));
m_value[i].m_value = (un[i] >> s) | (shift_mask & (un[i + 1] << (32 - s)));
}
for (int i = vw; i < words; i++) m_value[i] = 0;
for (int i = vw; i < words; i++) m_value[i].m_value = 0;
opCleanThis();
UINFO(9, " opmoddiv-mod " << lhs << " " << rhs << " now=" << *this << endl);
return *this;
@ -2016,7 +2020,7 @@ V3Number& V3Number::opPow(const V3Number& lhs, const V3Number& rhs, bool lsign,
}
if (lhs.isEqZero()) return setZero();
setZero();
m_value[0] = 1;
m_value[0].m_value = 1;
V3Number power(&lhs, width());
power.opAssign(lhs);
for (int bit = 0; bit < rhs.width(); bit++) {
@ -2104,15 +2108,14 @@ V3Number& V3Number::opClean(const V3Number& lhs, uint32_t bits) { return opSel(l
void V3Number::opCleanThis(bool warnOnTruncation) {
// Clean MSB of number
NUM_ASSERT_LOGIC_ARGS1(*this);
uint32_t newValueMsb = m_value[words() - 1] & hiWordMask();
uint32_t newValueXMsb = m_valueX[words() - 1] & hiWordMask();
if (warnOnTruncation
&& (newValueMsb != m_value[words() - 1] || newValueXMsb != m_valueX[words() - 1])) {
const ValueAndX v = m_value[words() - 1];
uint32_t newValueMsb = v.m_value & hiWordMask();
uint32_t newValueXMsb = v.m_valueX & hiWordMask();
if (warnOnTruncation && (newValueMsb != v.m_value || newValueXMsb != v.m_valueX)) {
// Displaying in decimal avoids hiWordMask truncation
v3warn(WIDTH, "Value too large for " << width() << " bit number: " << displayed("%d"));
}
m_value[words() - 1] = newValueMsb;
m_valueX[words() - 1] = newValueXMsb;
m_value[words() - 1] = {newValueMsb, newValueXMsb};
}
V3Number& V3Number::opSel(const V3Number& lhs, const V3Number& msb, const V3Number& lsb) {

View File

@ -38,8 +38,52 @@ inline bool v3EpsilonEqual(double a, double b) {
//============================================================================
class AstNode;
class FileLine;
// Holds a few entries of ValueAndX to avoid dynamic allocation in std::vector for less width of
// constants
class V3NumberData final {
public:
// TYPES
struct ValueAndX final {
// Value, with bit 0 in bit 0 of this vector (unless X/Z)
uint32_t m_value;
// Each bit is true if it's X or Z, 10=z, 11=x
uint32_t m_valueX;
bool operator==(const ValueAndX& other) const {
return m_value == other.m_value && m_valueX == other.m_valueX;
}
};
private:
// MEMBERS
static constexpr size_t m_inlinedSize = 2; // Can hold 64 bit without dynamic allocation
ValueAndX m_inlined[m_inlinedSize]; // Holds the beginning m_inlinedSize words
std::vector<ValueAndX> m_data; // Holds m_inlinedSize-th word and later
public:
// CONSTRUCTORS
V3NumberData() {
for (size_t i = 0; i < m_inlinedSize; ++i) m_inlined[i] = {0, 0};
}
// METHODS
void ensureSizeAtLeast(size_t s) {
if (VL_UNLIKELY(s > m_data.size() + m_inlinedSize)) m_data.resize(s - m_inlinedSize);
}
ValueAndX& operator[](size_t idx) {
UDEBUGONLY(UASSERT(idx < m_data.size() + m_inlinedSize,
"idx:" << idx << " size:" << m_data.size()
<< " inlinedSize:" << m_inlinedSize););
return idx >= m_inlinedSize ? m_data[idx - m_inlinedSize] : m_inlined[idx];
}
const ValueAndX& operator[](size_t idx) const { return const_cast<V3NumberData&>(*this)[idx]; }
};
class V3Number final {
// TYPES
using ValueAndX = V3NumberData::ValueAndX;
// Large 4-state number handling
int m_width; // Width as specified/calculated.
bool m_sized : 1; // True if the user specified the width, else we track it.
@ -51,8 +95,7 @@ class V3Number final {
bool m_autoExtend : 1; // True if SystemVerilog extend-to-any-width
FileLine* m_fileline;
AstNode* m_nodep; // Parent node
std::vector<uint32_t> m_value; // Value, with bit 0 in bit 0 of this vector (unless X/Z)
std::vector<uint32_t> m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x
V3NumberData m_value; // Value and X/Z information
string m_stringVal; // If isString, the value of the string
// METHODS
V3Number& setSingleBits(char value);
@ -74,18 +117,19 @@ public:
void setBit(int bit, char value) { // Note must be pre-zeroed!
if (bit >= m_width) return;
uint32_t mask = (1UL << (bit & 31));
ValueAndX& v = m_value[bit / 32];
if (value == '0' || value == 0) {
m_value[bit / 32] &= ~mask;
m_valueX[bit / 32] &= ~mask;
v.m_value &= ~mask;
v.m_valueX &= ~mask;
} else if (value == '1' || value == 1) {
m_value[bit / 32] |= mask;
m_valueX[bit / 32] &= ~mask;
v.m_value |= mask;
v.m_valueX &= ~mask;
} else if (value == 'z' || value == 2) {
m_value[bit / 32] &= ~mask;
m_valueX[bit / 32] |= mask;
v.m_value &= ~mask;
v.m_valueX |= mask;
} else { // X
m_value[bit / 32] |= mask;
m_valueX[bit / 32] |= mask;
v.m_value |= mask;
v.m_valueX |= mask;
}
}
@ -95,8 +139,9 @@ private:
// We never sign extend
return '0';
}
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
const ValueAndX v = m_value[bit / 32];
return ("01zx"[(((v.m_value & (1UL << (bit & 31))) ? 1 : 0)
| ((v.m_valueX & (1UL << (bit & 31))) ? 2 : 0))]);
}
char bitIsExtend(int bit, int lbits) const {
// lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less
@ -104,49 +149,52 @@ private:
UASSERT(lbits <= m_width, "Extend of wrong size");
if (bit >= lbits) {
bit = lbits ? lbits - 1 : 0;
const ValueAndX v = m_value[bit / 32];
// We do sign extend
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
return ("01zx"[(((v.m_value & (1UL << (bit & 31))) ? 1 : 0)
| ((v.m_valueX & (1UL << (bit & 31))) ? 2 : 0))]);
}
return ("01zx"[(((m_value[bit / 32] & (1UL << (bit & 31))) ? 1 : 0)
| ((m_valueX[bit / 32] & (1UL << (bit & 31))) ? 2 : 0))]);
const ValueAndX v = m_value[bit / 32];
return ("01zx"[(((v.m_value & (1UL << (bit & 31))) ? 1 : 0)
| ((v.m_valueX & (1UL << (bit & 31))) ? 2 : 0))]);
}
public:
bool bitIs0(int bit) const {
if (bit < 0) return false;
if (bit >= m_width) return !bitIsXZ(m_width - 1);
return ((m_value[bit / 32] & (1UL << (bit & 31))) == 0
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
const ValueAndX v = m_value[bit / 32];
return ((v.m_value & (1UL << (bit & 31))) == 0 && !(v.m_valueX & (1UL << (bit & 31))));
}
bool bitIs1(int bit) const {
if (bit < 0) return false;
if (bit >= m_width) return false;
return ((m_value[bit / 32] & (1UL << (bit & 31)))
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
const ValueAndX v = m_value[bit / 32];
return ((v.m_value & (1UL << (bit & 31))) && !(v.m_valueX & (1UL << (bit & 31))));
}
bool bitIs1Extend(int bit) const {
if (bit < 0) return false;
if (bit >= m_width) return bitIs1Extend(m_width - 1);
return ((m_value[bit / 32] & (1UL << (bit & 31)))
&& !(m_valueX[bit / 32] & (1UL << (bit & 31))));
const ValueAndX v = m_value[bit / 32];
return ((v.m_value & (1UL << (bit & 31))) && !(v.m_valueX & (1UL << (bit & 31))));
}
bool bitIsX(int bit) const {
if (bit < 0) return false;
if (bit >= m_width) return bitIsZ(m_width - 1);
return ((m_value[bit / 32] & (1UL << (bit & 31)))
&& (m_valueX[bit / 32] & (1UL << (bit & 31))));
const ValueAndX v = m_value[bit / 32];
return ((v.m_value & (1UL << (bit & 31))) && (v.m_valueX & (1UL << (bit & 31))));
}
bool bitIsXZ(int bit) const {
if (bit < 0) return false;
if (bit >= m_width) return bitIsXZ(m_width - 1);
return ((m_valueX[bit / 32] & (1UL << (bit & 31))));
const ValueAndX v = m_value[bit / 32];
return ((v.m_valueX & (1UL << (bit & 31))));
}
bool bitIsZ(int bit) const {
if (bit < 0) return false;
if (bit >= m_width) return bitIsZ(m_width - 1);
return ((~m_value[bit / 32] & (1UL << (bit & 31)))
&& (m_valueX[bit / 32] & (1UL << (bit & 31))));
const ValueAndX v = m_value[bit / 32];
return ((~v.m_value & (1UL << (bit & 31))) && (v.m_valueX & (1UL << (bit & 31))));
}
private:
@ -167,7 +215,7 @@ public:
V3Number(AstNode* nodep, int width) { init(nodep, width); } // 0=unsized
V3Number(AstNode* nodep, int width, uint32_t value, bool sized = true) {
init(nodep, width, sized);
m_value[0] = value;
m_value[0].m_value = value;
opCleanThis();
}
// Create from a verilog 32'hxxxx number.
@ -195,7 +243,7 @@ public:
}
V3Number(const V3Number* nump, int width, uint32_t value) {
init(nullptr, width);
m_value[0] = value;
m_value[0].m_value = value;
opCleanThis();
m_fileline = nump->fileline();
}
@ -212,7 +260,7 @@ private:
m_autoExtend = false;
m_fromString = false;
width(swidth, sized);
for (int i = 0; i < words(); ++i) m_value[i] = m_valueX[i] = 0;
for (int i = 0; i < words(); ++i) m_value[i] = {0, 0};
}
void setNames(AstNode* nodep);
static string displayPad(size_t fmtsize, char pad, bool left, const string& in);
@ -231,10 +279,7 @@ public:
m_sized = false;
m_width = 1;
}
if (VL_UNLIKELY(m_value.size() < (unsigned)(words() + 1))) {
m_value.resize(words() + 1);
m_valueX.resize(words() + 1);
}
m_value.ensureSizeAtLeast(words());
}
// SETTERS
@ -269,7 +314,8 @@ public:
bool isFourState() const;
bool hasZ() const {
for (int i = 0; i < words(); i++) {
if ((~m_value[i]) & m_valueX[i]) return true;
const ValueAndX v = m_value[i];
if ((~v.m_value) & v.m_valueX) return true;
}
return false;
}