Update linfstwriter from upstream (#7193 prep) (#8181)

This commit is contained in:
Wilson Snyder
2026-08-21 16:35:15 +02:00
committed by GitHub
parent e656b11cd1
commit 99c26d3994
3 changed files with 161 additions and 61 deletions
+1 -1
View File
@@ -90,7 +90,7 @@ static inline constexpr unsigned bitPerEncodedBit(EncodingType type) {
[[maybe_unused]]
static const char* kEncodedBitToCharTable = (
"01" // Binary
"xzhu" // Verilog
"zxhu" // Verilog
"wl-? " // Vhdl (padded with ' ')
);
+124 -53
View File
@@ -423,18 +423,26 @@ public:
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
for (unsigned i = 0; i < bitPerEncodedBit(encoding); ++i) {
// C++17: replace this with if constexpr
if (sizeof(T) == 8) {
// C++17: replace this with if constexpr
if (sizeof(T) == 8) {
if (encoding == EncodingType::VERILOG) {
uint64_t v = val[2]; // high bits
v <<= 32;
v |= val[0]; // low bits
wh.template write<uint64_t>(v);
v = val[3]; // high bits
v <<= 32;
v |= val[1]; // low bits
wh.template write<uint64_t>(v);
} else {
uint64_t v = val[1]; // high bits
v <<= 32;
v |= val[0]; // low bits
wh.template write<uint64_t>(v);
val += 2;
} else {
wh.template write<T>(val[0]);
val += 1;
}
} else {
wh.template write<T>(val[0]);
if (encoding == EncodingType::VERILOG) wh.template write<T>(val[1]);
}
}
@@ -517,7 +525,7 @@ public:
} else {
unsigned val = 0;
for (unsigned i = 0; i < num_element; ++i) {
val |= rh.peek<T>(i);
val |= rh.peek<T>(i) << i;
}
uint64_t delta_time_index = time_index - prev_time_index;
prev_time_index = time_index;
@@ -525,8 +533,8 @@ public:
// clang-format off
case 0: delta_time_index = (delta_time_index<<2) | (0<<1) | 0; break; // '0'
case 1: delta_time_index = (delta_time_index<<2) | (1<<1) | 0; break; // '1'
case 2: delta_time_index = (delta_time_index<<4) | (0<<1) | 1; break; // 'X'
case 3: delta_time_index = (delta_time_index<<4) | (1<<1) | 1; break; // 'Z'
case 2: delta_time_index = (delta_time_index<<4) | (1<<1) | 1; break; // 'Z'
case 3: delta_time_index = (delta_time_index<<4) | (0<<1) | 1; break; // 'X'
// Not supporting VHDL now
// LCOV_EXCL_START
case 4: delta_time_index = (delta_time_index<<4) | (2<<1) | 1; break; // 'H'
@@ -556,13 +564,29 @@ public:
if (first) {
first = false;
} else {
FST_CHECK(enc == EncodingType::BINARY); // TODO
const bool has_non_binary = enc != EncodingType::BINARY;
const uint64_t delta_time_index = time_index - prev_time_index;
prev_time_index = time_index;
h //
.writeLEB128((delta_time_index << 1) | has_non_binary)
.writeUIntPartialForValueChange(rh.peek<T>(), bitwidth);
switch (enc) {
case EncodingType::BINARY: {
h //
.writeLEB128(delta_time_index << 1)
.writeUIntPartialForValueChange(rh.peek<T>(), bitwidth);
} break;
case EncodingType::VERILOG: {
h.writeLEB128((delta_time_index << 1) | 1);
const T val = rh.peek<T>();
const T xz = rh.peek<T>(1);
for (int j = bitwidth; j > 0;) {
--j;
h.writeUIntBE(
kEncodedBitToCharTable[(((xz >> j) << 1) & 2) | ((val >> j) & 1)]
);
}
} break;
[[unlikely]] case EncodingType::VHDL: {
FST_FAIL_STRING("VHDL format is unsupported with wide values");
} break;
}
}
rh.skip(num_byte);
}
@@ -573,16 +597,26 @@ public:
class VariableInfoLongInt {
VariableInfo &info;
unsigned num_words() const { return (info.bitwidth() + 63) / 64; }
unsigned num_words32() const { return (info.bitwidth() + 31) / 32; }
public:
VariableInfoLongInt(VariableInfo &info_) : info(info_) {}
public:
size_t computeBytesNeededNoHeader(EncodingType encoding) const {
switch (encoding) {
case EncodingType::BINARY:
return num_words() * sizeof(uint64_t);
case EncodingType::VERILOG:
return num_words32() * sizeof(uint32_t) * 2;
[[unlikely]] case EncodingType::VHDL:
FST_FAIL_STRING("VHDL format is unsupported with wide values");
}
FST_UNREACHABLE;
}
size_t computeBytesNeeded(EncodingType encoding) const {
return (
kEmitTimeIndexAndEncodingSize +
num_words() * sizeof(uint64_t) * bitPerEncodedBit(encoding)
);
return kEmitTimeIndexAndEncodingSize + computeBytesNeededNoHeader(encoding);
}
EmitWriterHelper emitValueChangeCommonPart(uint64_t current_time_index, EncodingType encoding) {
@@ -600,13 +634,12 @@ public:
public:
void construct() {
const size_t nw = num_words();
const size_t nw = num_words32();
info.resize(computeBytesNeeded(EncodingType::VERILOG));
EmitWriterHelper wh(info.data_ptr());
wh //
.writeTimeIndexAndEncoding(0, EncodingType::VERILOG)
.fill(uint64_t(0), nw)
.fill(uint64_t(-1), nw);
.fill(static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) << 32, nw);
}
void emitValueChange(uint64_t current_time_index, const uint64_t val) {
@@ -616,12 +649,12 @@ public:
}
void emitValueChange(uint64_t current_time_index, const uint32_t *val, EncodingType encoding) {
const unsigned nw32 = (info.bitwidth() + 31) / 32;
const unsigned bpb = bitPerEncodedBit(encoding);
const unsigned nw32 = num_words32();
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
for (unsigned i = 0; i < bpb; ++i) {
switch (encoding) {
case EncodingType::BINARY: {
for (unsigned j = 0; j < nw32 / 2; ++j) {
uint64_t v = val[1]; // high bits
v <<= 32;
@@ -634,13 +667,25 @@ public:
wh.write(v);
val += 1;
}
} break;
case EncodingType::VERILOG: {
for (unsigned j = 0; j < nw32; ++j) {
uint64_t v = val[1]; // high bits
v <<= 32;
v |= val[0]; // low bits
wh.write(v);
val += 2;
}
} break;
[[unlikely]] case EncodingType::VHDL:
FST_FAIL_STRING("VHDL format is unsupported with wide values");
}
}
void emitValueChange(uint64_t current_time_index, const uint64_t *val, EncodingType encoding) {
const unsigned nw_encoded = num_words() * bitPerEncodedBit(encoding);
auto wh = emitValueChangeCommonPart(current_time_index, encoding);
wh.write(val, nw_encoded);
FST_CHECK(encoding == EncodingType::BINARY);
wh.write(val, num_words());
}
void dumpInitialBits(std::vector<uint8_t> &buf) const {
@@ -663,15 +708,16 @@ public:
break;
}
case EncodingType::VERILOG: {
for (unsigned word_index = nw; word_index-- > 0;) {
const uint64_t v0 = rh.peek<uint64_t>(nw * 0 + word_index);
const uint64_t v1 = rh.peek<uint64_t>(nw * 1 + word_index);
for (unsigned word_index = num_words32(); word_index-- > 0;) {
const uint64_t val = rh.peek<uint64_t>(word_index);
const uint32_t aval = static_cast<uint32_t>(val);
const uint32_t bval = static_cast<uint32_t>(val >> 32);
const unsigned num_bit =
(word_index * 64 + 64 > info.bitwidth()) ? (info.bitwidth() % 64) : 64;
(word_index * 32 + 32 > info.bitwidth()) ? (info.bitwidth() % 32) : 32;
for (unsigned bit_index = num_bit; bit_index-- > 0;) {
const bool b0 = ((v0 >> bit_index) & uint64_t(1));
const bool b1 = ((v1 >> bit_index) & uint64_t(1));
const char c = kEncodedBitToCharTable[(b1 << 1) | b0];
const bool a = ((aval >> bit_index) & 1);
const bool b = ((bval >> bit_index) & 1);
const char c = kEncodedBitToCharTable[(b << 1) | a];
buf.push_back(c);
}
}
@@ -717,33 +763,58 @@ public:
FST_DCHECK_GT(tail, rh.ptr);
const auto time_index = rh.read<uint64_t>();
const auto enc = rh.read<EncodingType>();
const auto num_element = bitPerEncodedBit(enc);
const auto num_byte = num_element * nw * sizeof(uint64_t);
const auto num_byte = computeBytesNeededNoHeader(enc);
if (first) {
// Note: [0] is initial value, which is already dumped in dumpInitialBits()
first = false;
} else {
FST_CHECK(enc == EncodingType::BINARY); // TODO
const bool has_non_binary = enc != EncodingType::BINARY;
const uint64_t delta_time_index = time_index - prev_time_index;
prev_time_index = time_index;
h.writeLEB128((delta_time_index << 1) | has_non_binary);
if (bitwidth % 64 != 0) {
const unsigned remaining = bitwidth % 64;
uint64_t hi64 = rh.peek<uint64_t>(nw - 1);
// write from nw-1 to 1
for (unsigned j = nw - 1; j > 0; --j) {
uint64_t lo64 = rh.peek<uint64_t>(j - 1);
h.writeUIntBE((hi64 << (64 - remaining)) | (lo64 >> remaining));
hi64 = lo64;
switch (enc) {
case EncodingType::BINARY: {
h.writeLEB128((delta_time_index << 1));
if (bitwidth % 64 != 0) {
const unsigned remaining = bitwidth % 64;
uint64_t hi64 = rh.peek<uint64_t>(nw - 1);
// write from nw-1 to 1
for (unsigned j = nw - 1; j > 0; --j) {
uint64_t lo64 = rh.peek<uint64_t>(j - 1);
h.writeUIntBE((hi64 << (64 - remaining)) | (lo64 >> remaining));
hi64 = lo64;
}
// write 0
h.writeUIntPartialForValueChange(hi64, remaining);
} else {
// write from nw-1 to 0
for (unsigned j = nw; j-- > 0;) {
h.writeUIntBE(rh.peek<uint64_t>(j));
}
}
// write 0
h.writeUIntPartialForValueChange(hi64, remaining);
} else {
// write from nw-1 to 0
for (unsigned j = nw; j-- > 0;) {
h.writeUIntBE(rh.peek<uint64_t>(j));
} break;
case EncodingType::VERILOG: {
h.writeLEB128((delta_time_index << 1) | 1);
const int fullWords = (bitwidth / 32);
if (int j = bitwidth % 32) {
const uint64_t val = rh.peek<uint64_t>(fullWords);
while (j > 0) {
--j;
const uint64_t v = val >> j;
h.writeUIntBE(kEncodedBitToCharTable[((v >> 31) & 2) | (v & 1)]);
}
}
for (size_t i = fullWords; i > 0;) {
--i;
const uint64_t val = rh.peek<uint64_t>(i);
for (int j = 32; j > 0;) {
--j;
const uint64_t v = val >> j;
h.writeUIntBE(kEncodedBitToCharTable[((v >> 31) & 2) | (v & 1)]);
}
}
} break;
[[unlikely]] case EncodingType::VHDL: {
FST_FAIL_STRING("VHDL format is unsupported with wide values");
} break;
}
}
rh.skip(num_byte);
+36 -7
View File
@@ -268,26 +268,55 @@ void Writer::emitValueChange(Handle handle, const char *val) {
// For normal integer handles, const char* is "01xz..." (1B per bit)
const uint32_t bitwidth{var_info.bitwidth()};
const bool hasXZ = // Detects A-Z and a-z but not 0-9 and NOT `-` `?`
(std::accumulate(val, val + bitwidth, 0, [](int a, char b) { return a | b; }) & (1 << 6)) !=
0;
FST_DCHECK_NE(bitwidth, 0);
val += bitwidth;
const unsigned num_words{(bitwidth + 63) / 64};
m_packed_value_buffer_.assign(num_words, 0);
m_packed_value_buffer_.assign(num_words << (hasXZ ? 1 : 0), 0);
for (unsigned i = 0; i < num_words; ++i) {
const char *start{val - std::min((i + 1) * 64, bitwidth)};
const char *end{val - 64 * i};
m_packed_value_buffer_[i] = 0;
for (const char *p = start; p < end; ++p) {
// No checking for invalid characters, follow original C implementation
m_packed_value_buffer_[i] <<= 1;
m_packed_value_buffer_[i] |= static_cast<uint64_t>(*p - '0');
if (hasXZ) {
const size_t j = i << 1;
m_packed_value_buffer_[j] <<= 1;
m_packed_value_buffer_[j | 1] <<= 1;
switch (*p) {
case '0':
break;
case '1': {
m_packed_value_buffer_[i] |= 1;
} break;
case 'X':
case 'x': {
m_packed_value_buffer_[i] |= 1;
} // FALLTHROUGH
case 'Z':
case 'z': {
m_packed_value_buffer_[j | 1] |= 1;
} break;
[[unlikely]] default: { FST_FAIL_STRING("Unexpected char"); } break;
}
} else {
m_packed_value_buffer_[i] <<= 1;
m_packed_value_buffer_[i] |= static_cast<uint64_t>(*p - '0');
}
}
}
if (bitwidth <= 64) {
if (bitwidth <= 64 && !hasXZ) {
emitValueChange(handle, m_packed_value_buffer_.front());
} else {
emitValueChange(handle, m_packed_value_buffer_.data(), EncodingType::BINARY);
emitValueChange(
handle,
m_packed_value_buffer_.data(),
hasXZ ? EncodingType::VERILOG : EncodingType::BINARY
);
}
}
@@ -605,7 +634,7 @@ void detail::ValueChangeData::writeEncodedPositions(
}
// encode as signed (value << 1) | 1 and write as signed LEB128
h.writeLEB128Signed((value_to_encode << 1) | 1);
h.writeLEB128Signed((static_cast<uint64_t>(value_to_encode) << 1) | 1);
++i;
}
@@ -695,7 +724,7 @@ void Writer::flushValueChangeDataConstPart_(
(void)count;
return std::make_pair(positions, memory_usage);
}();
const std::vector<int64_t> positions{p_tmp2.first};
const std::vector<int64_t> positions{std::move(p_tmp2.first)};
const size_t memory_usage{p_tmp2.second};
// 4. Position Section