Skip to content

Commit 6076dbc

Browse files
committed
bitreverse_exprt: Expression to reverse the order of bits
Clang has a __builtin_bitreverse (and at some point GCC might as well: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=50481).
1 parent 23306ee commit 6076dbc

19 files changed

+260
-0
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
unsigned char __builtin_bitreverse8(char, char);
2+
3+
int main()
4+
{
5+
return __builtin_bitreverse8(1, 2);
6+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
bitreverse-typeconflict.c
3+
file bitreverse-typeconflict.c line 5 function main: error: __builtin_bitreverse8 expects one operand
4+
^EXIT=6$
5+
^SIGNAL=0$
6+
--
7+
^warning: ignoring
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <assert.h>
2+
#include <stdint.h>
3+
4+
#define test_bit_reverse(W) \
5+
uint##W##_t test_bit_reverse##W(uint##W##_t v) \
6+
{ \
7+
uint##W##_t result = 0; \
8+
int i; \
9+
for(i = 0; i < W; i++) \
10+
{ \
11+
if(v & (1ULL << i)) \
12+
result |= 1ULL << (W - i - 1); \
13+
} \
14+
return result; \
15+
} \
16+
int dummy_for_semicolon##W
17+
18+
test_bit_reverse(8);
19+
test_bit_reverse(16);
20+
test_bit_reverse(32);
21+
test_bit_reverse(64);
22+
23+
#ifndef __clang__
24+
unsigned char __builtin_bitreverse8(unsigned char);
25+
unsigned short __builtin_bitreverse16(unsigned short);
26+
unsigned int __builtin_bitreverse32(unsigned int);
27+
unsigned long long __builtin_bitreverse64(unsigned long long);
28+
#endif
29+
30+
void check_8(void)
31+
{
32+
uint8_t op;
33+
assert(__builtin_bitreverse8(op) == test_bit_reverse8(op));
34+
assert(__builtin_bitreverse8(1) == 0x80);
35+
}
36+
37+
void check_16(void)
38+
{
39+
uint16_t op;
40+
assert(__builtin_bitreverse16(op) == test_bit_reverse16(op));
41+
assert(__builtin_bitreverse16(1) == 0x8000);
42+
}
43+
44+
void check_32(void)
45+
{
46+
uint32_t op;
47+
assert(__builtin_bitreverse32(op) == test_bit_reverse32(op));
48+
assert(__builtin_bitreverse32(1) == 0x80000000);
49+
}
50+
51+
void check_64(void)
52+
{
53+
uint64_t op;
54+
assert(__builtin_bitreverse64(op) == test_bit_reverse64(op));
55+
assert(__builtin_bitreverse64(1) == 0x8000000000000000ULL);
56+
}
57+
58+
int main(void)
59+
{
60+
check_8();
61+
check_16();
62+
check_32();
63+
check_64();
64+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE thorough-paths
2+
bitreverse.c
3+
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3204,6 +3204,28 @@ exprt c_typecheck_baset::do_special_functions(
32043204
{
32053205
return typecheck_builtin_overflow(expr, ID_mult);
32063206
}
3207+
else if(
3208+
identifier == "__builtin_bitreverse8" ||
3209+
identifier == "__builtin_bitreverse16" ||
3210+
identifier == "__builtin_bitreverse32" ||
3211+
identifier == "__builtin_bitreverse64")
3212+
{
3213+
// clang only
3214+
if(expr.arguments().size() != 1)
3215+
{
3216+
std::ostringstream error_message;
3217+
error_message << expr.source_location().as_string()
3218+
<< ": error: " << identifier << " expects one operand";
3219+
throw invalid_source_file_exceptiont{error_message.str()};
3220+
}
3221+
3222+
typecheck_function_call_arguments(expr);
3223+
3224+
bitreverse_exprt bitreverse{expr.arguments()[0]};
3225+
bitreverse.add_source_location() = source_location;
3226+
3227+
return std::move(bitreverse);
3228+
}
32073229
else
32083230
return nil_exprt();
32093231
// NOLINTNEXTLINE(readability/fn_size)

src/ansi-c/clang_builtin_headers.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ void __builtin_nontemporal_load();
5454

5555
int __builtin_flt_rounds(void);
5656

57+
unsigned char __builtin_bitreverse8(unsigned char);
58+
unsigned short __builtin_bitreverse16(unsigned short);
59+
unsigned int __builtin_bitreverse32(unsigned int);
60+
unsigned long long __builtin_bitreverse64(unsigned long long);
61+
5762
unsigned char __builtin_rotateleft8(unsigned char, unsigned char);
5863
unsigned short __builtin_rotateleft16(unsigned short, unsigned short);
5964
unsigned int __builtin_rotateleft32(unsigned int, unsigned int);

src/ansi-c/expr2c.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3496,6 +3496,22 @@ std::string expr2ct::convert_conditional_target_group(const exprt &src)
34963496
return dest;
34973497
}
34983498

3499+
std::string expr2ct::convert_bitreverse(const bitreverse_exprt &src)
3500+
{
3501+
if(auto type_ptr = type_try_dynamic_cast<unsignedbv_typet>(src.type()))
3502+
{
3503+
const std::size_t width = type_ptr->get_width();
3504+
if(width == 8 || width == 16 || width == 32 || width == 64)
3505+
{
3506+
return convert_function(
3507+
src, "__builtin_bitreverse" + std::to_string(width));
3508+
}
3509+
}
3510+
3511+
unsigned precedence;
3512+
return convert_norep(src, precedence);
3513+
}
3514+
34993515
std::string expr2ct::convert_with_precedence(
35003516
const exprt &src,
35013517
unsigned &precedence)
@@ -3904,6 +3920,9 @@ std::string expr2ct::convert_with_precedence(
39043920
return convert_conditional_target_group(src);
39053921
}
39063922

3923+
else if(src.id() == ID_bitreverse)
3924+
return convert_bitreverse(to_bitreverse_expr(src));
3925+
39073926
auto function_string_opt = convert_function(src);
39083927
if(function_string_opt.has_value())
39093928
return *function_string_opt;

src/ansi-c/expr2c_class.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ class expr2ct
277277
bool include_padding_components);
278278

279279
std::string convert_conditional_target_group(const exprt &src);
280+
std::string convert_bitreverse(const bitreverse_exprt &src);
280281
};
281282

282283
#endif // CPROVER_ANSI_C_EXPR2C_CLASS_H

src/solvers/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ SRC = $(BOOLEFORCE_SRC) \
8686
flattening/boolbv_add_sub.cpp \
8787
flattening/boolbv_array.cpp \
8888
flattening/boolbv_array_of.cpp \
89+
flattening/boolbv_bitreverse.cpp \
8990
flattening/boolbv_bitwise.cpp \
9091
flattening/boolbv_bswap.cpp \
9192
flattening/boolbv_bv_rel.cpp \

src/solvers/flattening/boolbv.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ bvt boolbvt::convert_bitvector(const exprt &expr)
227227
return convert_bv(
228228
simplify_expr(to_count_trailing_zeros_expr(expr).lower(), ns));
229229
}
230+
else if(expr.id() == ID_bitreverse)
231+
return convert_bitreverse(to_bitreverse_expr(expr));
230232

231233
return conversion_failed(expr);
232234
}

0 commit comments

Comments
 (0)