Skip to content

Commit 37861c8

Browse files
committed
Implement incremental SMT2 support for bswap_exprt
Implements byte swapping in the incremental SMT2 decision procedure and adds unit tests. Regression test `gcc_bswap1` now passes. Fixes: #8064
1 parent 4fe3ade commit 37861c8

File tree

3 files changed

+125
-4
lines changed

3 files changed

+125
-4
lines changed

regression/cbmc/gcc_bswap1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
CORE no-new-smt
1+
CORE
22
main.c
33

44
^EXIT=10$

src/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,9 +1432,60 @@ static smt_termt convert_expr_to_smt(
14321432
const bswap_exprt &byte_swap,
14331433
const sub_expression_mapt &converted)
14341434
{
1435-
UNIMPLEMENTED_FEATURE(
1436-
"Generation of SMT formula for byte swap expression: " +
1437-
byte_swap.pretty());
1435+
const auto operand_term = converted.at(byte_swap.op());
1436+
const auto &operand_type = byte_swap.op().type();
1437+
1438+
if(!can_cast_type<bitvector_typet>(operand_type))
1439+
{
1440+
UNIMPLEMENTED_FEATURE(
1441+
"Generation of SMT formula for byte swap of non-bitvector type: " +
1442+
byte_swap.pretty());
1443+
}
1444+
1445+
const auto &bv_type = to_bitvector_type(operand_type);
1446+
const std::size_t width = bv_type.get_width();
1447+
const std::size_t byte_bits = byte_swap.get_bits_per_byte();
1448+
1449+
// Width must be multiple of byte_bits
1450+
if(width % byte_bits != 0)
1451+
{
1452+
UNIMPLEMENTED_FEATURE(
1453+
"Generation of SMT formula for byte swap with width not multiple of byte "
1454+
"size: " +
1455+
byte_swap.pretty());
1456+
}
1457+
1458+
const std::size_t num_bytes = width / byte_bits;
1459+
1460+
// If only one byte, no swapping needed
1461+
if(num_bytes == 1)
1462+
return operand_term;
1463+
1464+
// Extract each byte from the operand
1465+
// byte_terms[i] will contain bits [(i+1)*byte_bits-1 : i*byte_bits]
1466+
std::vector<smt_termt> byte_terms;
1467+
byte_terms.reserve(num_bytes);
1468+
1469+
for(std::size_t byte_idx = 0; byte_idx < num_bytes; ++byte_idx)
1470+
{
1471+
const std::size_t high_bit = (byte_idx + 1) * byte_bits - 1;
1472+
const std::size_t low_bit = byte_idx * byte_bits;
1473+
1474+
byte_terms.push_back(
1475+
smt_bit_vector_theoryt::extract(high_bit, low_bit)(operand_term));
1476+
}
1477+
1478+
// Concatenate bytes in reverse order
1479+
// SMT concat(a, b) makes 'a' the most significant bits
1480+
// So to reverse bytes, we start with byte 0 (originally least significant)
1481+
// and make it most significant in the result
1482+
smt_termt result = byte_terms[0];
1483+
for(std::size_t i = 1; i < num_bytes; ++i)
1484+
{
1485+
result = smt_bit_vector_theoryt::concat(result, byte_terms[i]);
1486+
}
1487+
1488+
return result;
14381489
}
14391490

14401491
static smt_termt convert_expr_to_smt(

unit/solvers/smt2_incremental/convert_expr_to_smt.cpp

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1776,3 +1776,73 @@ TEST_CASE(
17761776
CHECK(test.convert(assignment) == expected);
17771777
}
17781778
}
1779+
1780+
TEST_CASE(
1781+
"expr to smt conversion for bswap_exprt expressions",
1782+
"[core][smt2_incremental]")
1783+
{
1784+
auto test =
1785+
expr_to_smt_conversion_test_environmentt::make(test_archt::x86_64);
1786+
SECTION("16-bit byte swap")
1787+
{
1788+
const symbol_exprt operand{"my_value", unsignedbv_typet{16}};
1789+
const bswap_exprt byte_swap{operand, 8, unsignedbv_typet{16}};
1790+
INFO("Expression being converted: " + byte_swap.pretty(2, 0));
1791+
const smt_identifier_termt operand_smt{"my_value", smt_bit_vector_sortt{16}};
1792+
// For 16-bit bswap, we extract [7:0] and [15:8], then concat in reverse order
1793+
// concat([7:0], [15:8]) puts [7:0] as most significant
1794+
const smt_termt expected = smt_bit_vector_theoryt::concat(
1795+
smt_bit_vector_theoryt::extract(7, 0)(operand_smt),
1796+
smt_bit_vector_theoryt::extract(15, 8)(operand_smt));
1797+
CHECK(test.convert(byte_swap) == expected);
1798+
}
1799+
SECTION("32-bit byte swap")
1800+
{
1801+
const symbol_exprt operand{"my_value", unsignedbv_typet{32}};
1802+
const bswap_exprt byte_swap{operand, 8, unsignedbv_typet{32}};
1803+
INFO("Expression being converted: " + byte_swap.pretty(2, 0));
1804+
const smt_identifier_termt operand_smt{"my_value", smt_bit_vector_sortt{32}};
1805+
// For 32-bit bswap, we extract 4 bytes and concat in reverse order
1806+
const smt_termt expected = smt_bit_vector_theoryt::concat(
1807+
smt_bit_vector_theoryt::concat(
1808+
smt_bit_vector_theoryt::concat(
1809+
smt_bit_vector_theoryt::extract(7, 0)(operand_smt),
1810+
smt_bit_vector_theoryt::extract(15, 8)(operand_smt)),
1811+
smt_bit_vector_theoryt::extract(23, 16)(operand_smt)),
1812+
smt_bit_vector_theoryt::extract(31, 24)(operand_smt));
1813+
CHECK(test.convert(byte_swap) == expected);
1814+
}
1815+
SECTION("64-bit byte swap")
1816+
{
1817+
const symbol_exprt operand{"my_value", unsignedbv_typet{64}};
1818+
const bswap_exprt byte_swap{operand, 8, unsignedbv_typet{64}};
1819+
INFO("Expression being converted: " + byte_swap.pretty(2, 0));
1820+
const smt_identifier_termt operand_smt{"my_value", smt_bit_vector_sortt{64}};
1821+
// For 64-bit bswap, we extract 8 bytes and concat in reverse order
1822+
const smt_termt expected = smt_bit_vector_theoryt::concat(
1823+
smt_bit_vector_theoryt::concat(
1824+
smt_bit_vector_theoryt::concat(
1825+
smt_bit_vector_theoryt::concat(
1826+
smt_bit_vector_theoryt::concat(
1827+
smt_bit_vector_theoryt::concat(
1828+
smt_bit_vector_theoryt::concat(
1829+
smt_bit_vector_theoryt::extract(7, 0)(operand_smt),
1830+
smt_bit_vector_theoryt::extract(15, 8)(operand_smt)),
1831+
smt_bit_vector_theoryt::extract(23, 16)(operand_smt)),
1832+
smt_bit_vector_theoryt::extract(31, 24)(operand_smt)),
1833+
smt_bit_vector_theoryt::extract(39, 32)(operand_smt)),
1834+
smt_bit_vector_theoryt::extract(47, 40)(operand_smt)),
1835+
smt_bit_vector_theoryt::extract(55, 48)(operand_smt)),
1836+
smt_bit_vector_theoryt::extract(63, 56)(operand_smt));
1837+
CHECK(test.convert(byte_swap) == expected);
1838+
}
1839+
SECTION("Single byte (no swap needed)")
1840+
{
1841+
const symbol_exprt operand{"my_value", unsignedbv_typet{8}};
1842+
const bswap_exprt byte_swap{operand, 8, unsignedbv_typet{8}};
1843+
INFO("Expression being converted: " + byte_swap.pretty(2, 0));
1844+
const smt_identifier_termt operand_smt{"my_value", smt_bit_vector_sortt{8}};
1845+
// Single byte should return operand unchanged
1846+
CHECK(test.convert(byte_swap) == operand_smt);
1847+
}
1848+
}

0 commit comments

Comments
 (0)