Skip to content

Commit 2c3d140

Browse files
authored
Merge pull request #3107 from diffblue/hex-bitvectors5
Bitvectors are now hexadecimal
2 parents 3a393e0 + c7c4110 commit 2c3d140

File tree

3 files changed

+104
-20
lines changed

3 files changed

+104
-20
lines changed

regression/invariants/invariant-irep-diagnostic/test.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ invariant-with-irep-diagnostics
55
^SIGNAL=0$
66
--- begin invariant violation report ---
77
Invariant check failed
8-
value: 00000000000000000000000000001000
9-
value: 00000000000000000000000000001101
8+
value: 8
9+
value: [dD]

src/solvers/flattening/boolbv_constant.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,6 @@ bvt boolbvt::convert_constant(const constant_exprt &expr)
8181
{
8282
const auto &value = expr.get_value();
8383

84-
if(value.size() != width)
85-
{
86-
error().source_location=expr.find_source_location();
87-
error() << "wrong value length in constant: "
88-
<< expr.pretty() << eom;
89-
throw 0;
90-
}
91-
9284
for(std::size_t i=0; i<width; i++)
9385
{
9486
const bool bit = get_bvrep_bit(value, width, i);

src/util/arith_tools.cpp

Lines changed: 102 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ Author: Daniel Kroening, [email protected]
1414
#include "std_types.h"
1515
#include "std_expr.h"
1616

17+
#include <algorithm>
18+
1719
bool to_integer(const exprt &expr, mp_integer &int_value)
1820
{
1921
if(!expr.is_constant())
@@ -285,11 +287,38 @@ bool get_bvrep_bit(
285287
std::size_t width,
286288
std::size_t bit_index)
287289
{
288-
// The representation is binary, using '0'/'1',
289-
// most significant bit first.
290290
PRECONDITION(bit_index < width);
291-
PRECONDITION(src.size() == width);
292-
return src[src.size() - 1 - bit_index] == '1';
291+
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;
297+
298+
if(nibble_index >= src.size())
299+
return false;
300+
301+
const char nibble = src[src.size() - 1 - nibble_index];
302+
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;
293322
}
294323

295324
/// construct a bit-vector representation from a functor
@@ -299,12 +328,39 @@ bool get_bvrep_bit(
299328
irep_idt
300329
make_bvrep(const std::size_t width, const std::function<bool(std::size_t)> f)
301330
{
302-
std::string result(width, ' ');
331+
std::string result;
332+
result.reserve((width + 3) / 4);
333+
unsigned char nibble = 0;
303334

304335
for(std::size_t i = 0; i < width; i++)
305-
result[width - 1 - i] = f(i) ? '1' : '0';
336+
{
337+
const auto bit_in_nibble = i % 4;
306338

307-
return result;
339+
nibble |= ((unsigned char)f(i)) << bit_in_nibble;
340+
341+
if(bit_in_nibble == 3)
342+
{
343+
result += nibble2hex(nibble);
344+
nibble = 0;
345+
}
346+
}
347+
348+
if(nibble != 0)
349+
result += nibble2hex(nibble);
350+
351+
// 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);
359+
360+
std::reverse(result.begin(), result.end());
361+
362+
return result;
363+
}
308364
}
309365

310366
/// perform a binary bit-wise operation, given as a functor,
@@ -342,14 +398,50 @@ irep_idt bvrep_bitwise_op(
342398
}
343399

344400
/// convert an integer to bit-vector representation with given width
401+
/// This uses two's complement for negative numbers.
402+
/// If the value is out of range, it is 'wrapped around'.
345403
irep_idt integer2bvrep(const mp_integer &src, std::size_t width)
346404
{
347-
return integer2binary(src, width);
405+
const mp_integer p = power(2, width);
406+
407+
if(src.is_negative())
408+
{
409+
// do two's complement encoding of negative numbers
410+
mp_integer tmp = src;
411+
tmp.negate();
412+
tmp %= p;
413+
if(tmp != 0)
414+
tmp = p - tmp;
415+
return integer2string(tmp, 16);
416+
}
417+
else
418+
{
419+
// we 'wrap around' if 'src' is too large
420+
return integer2string(src % p, 16);
421+
}
348422
}
349423

350424
/// convert a bit-vector representation (possibly signed) to integer
351425
mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
352426
{
353-
PRECONDITION(src.size() == width);
354-
return binary2integer(id2string(src), is_signed);
427+
if(is_signed)
428+
{
429+
PRECONDITION(width >= 1);
430+
const auto tmp = string2integer(id2string(src), 16);
431+
const auto p = power(2, width - 1);
432+
if(tmp >= p)
433+
{
434+
const auto result = tmp - 2 * p;
435+
PRECONDITION(result >= -p);
436+
return result;
437+
}
438+
else
439+
return tmp;
440+
}
441+
else
442+
{
443+
const auto result = string2integer(id2string(src), 16);
444+
PRECONDITION(result < power(2, width));
445+
return result;
446+
}
355447
}

0 commit comments

Comments
 (0)