Skip to content

Commit a2e086e

Browse files
author
Daniel Kroening
committed
base 256 bitvector representation
Simultaneously leading zeros are dropped. This reduces the memory consumption of bit-vectors by 8x or more.
1 parent 396794c commit a2e086e

File tree

2 files changed

+39
-52
lines changed

2 files changed

+39
-52
lines changed

src/util/arith_tools.cpp

Lines changed: 37 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -289,36 +289,14 @@ bool get_bvrep_bit(
289289
{
290290
PRECONDITION(bit_index < width);
291291

292-
// The representation is hex, i.e., four bits per letter,
293-
// most significant nibble first, using uppercase letters.
294-
// No lowercase, no leading zeros (other than for 'zero'),
295-
// to ensure canonicity.
296-
const auto nibble_index = bit_index / 4;
292+
const auto byte_index = bit_index >> 3;
297293

298-
if(nibble_index >= src.size())
294+
if(byte_index >= src.size())
299295
return false;
300296

301-
const char nibble = src[src.size() - 1 - nibble_index];
297+
unsigned char byte = src[src.size() - 1 - byte_index];
302298

303-
DATA_INVARIANT(
304-
isdigit(nibble) || (nibble >= 'A' && nibble <= 'F'),
305-
"bvrep is hexadecimal, upper-case");
306-
307-
const unsigned char nibble_value =
308-
isdigit(nibble) ? nibble - '0' : nibble - 'A' + 10;
309-
310-
return ((nibble_value >> (bit_index % 4)) & 1) != 0;
311-
}
312-
313-
/// turn a value 0...15 into '0'-'9', 'A'-'Z'
314-
static char nibble2hex(unsigned char nibble)
315-
{
316-
PRECONDITION(nibble <= 0xf);
317-
318-
if(nibble >= 10)
319-
return 'A' + nibble - 10;
320-
else
321-
return '0' + nibble;
299+
return ((byte >> (bit_index & 7)) & 1) != 0;
322300
}
323301

324302
/// construct a bit-vector representation from a functor
@@ -329,38 +307,32 @@ irep_idt
329307
make_bvrep(const std::size_t width, const std::function<bool(std::size_t)> f)
330308
{
331309
std::string result;
332-
result.reserve((width + 3) / 4);
333-
unsigned char nibble = 0;
310+
result.reserve(width / 8 + 1);
311+
unsigned byte = 0;
334312

335313
for(std::size_t i = 0; i < width; i++)
336314
{
337-
const auto bit_in_nibble = i % 4;
315+
const auto bit_in_byte = i % 8;
338316

339-
nibble |= ((unsigned char)f(i)) << bit_in_nibble;
317+
byte |= ((unsigned)f(i)) << bit_in_byte;
340318

341-
if(bit_in_nibble == 3)
319+
if(bit_in_byte == 7)
342320
{
343-
result += nibble2hex(nibble);
344-
nibble = 0;
321+
result += (char)byte;
322+
byte = 0;
345323
}
346324
}
347325

348-
if(nibble != 0)
349-
result += nibble2hex(nibble);
326+
if(byte != 0)
327+
result += (char)byte;
350328

351329
// drop leading zeros
352-
const std::size_t pos = result.find_last_not_of('0');
353-
354-
if(pos == std::string::npos)
355-
return ID_0;
356-
else
357-
{
358-
result.resize(pos + 1);
330+
while(!result.empty() && result.back() == 0)
331+
result.resize(result.size() - 1);
359332

360-
std::reverse(result.begin(), result.end());
333+
std::reverse(result.begin(), result.end());
361334

362-
return result;
363-
}
335+
return result;
364336
}
365337

366338
/// perform a binary bit-wise operation, given as a functor,
@@ -397,6 +369,19 @@ irep_idt bvrep_bitwise_op(
397369
});
398370
}
399371

372+
std::string dump_integer(mp_integer src)
373+
{
374+
std::size_t d = src.digits(256) + 1;
375+
unsigned char *buf = new unsigned char[d], *p = buf;
376+
src.dump(buf, d);
377+
while(d > 0 && *p == 0)
378+
{
379+
d--;
380+
p++;
381+
}
382+
return std::string((char *)p, d);
383+
}
384+
400385
/// convert an integer to bit-vector representation with given width
401386
/// This uses two's complement for negative numbers.
402387
/// If the value is out of range, it is 'wrapped around'.
@@ -412,22 +397,24 @@ irep_idt integer2bvrep(const mp_integer &src, std::size_t width)
412397
tmp %= p;
413398
if(tmp != 0)
414399
tmp = p - tmp;
415-
return integer2string(tmp, 16);
400+
return dump_integer(tmp);
416401
}
417402
else
418403
{
419404
// we 'wrap around' if 'src' is too large
420-
return integer2string(src % p, 16);
405+
return dump_integer(src % p);
421406
}
422407
}
423408

424409
/// convert a bit-vector representation (possibly signed) to integer
425410
mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
426411
{
412+
mp_integer tmp;
413+
tmp.load((const unsigned char *)id2string(src).data(), src.size());
414+
427415
if(is_signed)
428416
{
429417
PRECONDITION(width >= 1);
430-
const auto tmp = string2integer(id2string(src), 16);
431418
const auto p = power(2, width - 1);
432419
if(tmp >= p)
433420
{
@@ -440,8 +427,7 @@ mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
440427
}
441428
else
442429
{
443-
const auto result = string2integer(id2string(src), 16);
444-
PRECONDITION(result < power(2, width));
445-
return result;
430+
PRECONDITION(tmp < power(2, width));
431+
return tmp;
446432
}
447433
}

src/util/expr.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ bool exprt::is_zero() const
149149
type_id == ID_unsignedbv || type_id == ID_signedbv ||
150150
type_id == ID_c_bool || type_id == ID_c_bit_field)
151151
{
152-
return constant.value_is_zero_string();
152+
// zero is the empty string
153+
return constant.get_value().empty();
153154
}
154155
else if(type_id==ID_fixedbv)
155156
{

0 commit comments

Comments
 (0)