Skip to content

Commit 023fc8b

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 a0fe71a commit 023fc8b

17 files changed

+247
-4
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
@@ -3238,6 +3238,28 @@ exprt c_typecheck_baset::do_special_functions(
32383238
std::move(result),
32393239
expr.source_location()};
32403240
}
3241+
else if(
3242+
identifier == "__builtin_bitreverse8" ||
3243+
identifier == "__builtin_bitreverse16" ||
3244+
identifier == "__builtin_bitreverse32" ||
3245+
identifier == "__builtin_bitreverse64")
3246+
{
3247+
// clang only
3248+
if(expr.arguments().size() != 1)
3249+
{
3250+
std::ostringstream error_message;
3251+
error_message << expr.source_location().as_string()
3252+
<< ": error: " << identifier << " expects one operand";
3253+
throw invalid_source_file_exceptiont{error_message.str()};
3254+
}
3255+
3256+
typecheck_function_call_arguments(expr);
3257+
3258+
bitreverse_exprt bitreverse{expr.arguments()[0]};
3259+
bitreverse.add_source_location() = source_location;
3260+
3261+
return std::move(bitreverse);
3262+
}
32413263
else
32423264
return nil_exprt();
32433265
}

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/flattening/boolbv.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,14 @@ bvt boolbvt::convert_bitvector(const exprt &expr)
155155
return convert_replication(to_replication_expr(expr));
156156
else if(expr.id()==ID_extractbits)
157157
return convert_extractbits(to_extractbits_expr(expr));
158-
else if(expr.id()==ID_bitnot || expr.id()==ID_bitand ||
159-
expr.id()==ID_bitor || expr.id()==ID_bitxor ||
160-
expr.id()==ID_bitxnor || expr.id()==ID_bitnor ||
161-
expr.id()==ID_bitnand)
158+
else if(
159+
expr.id() == ID_bitnot || expr.id() == ID_bitand || expr.id() == ID_bitor ||
160+
expr.id() == ID_bitxor || expr.id() == ID_bitxnor ||
161+
expr.id() == ID_bitnor || expr.id() == ID_bitnand ||
162+
expr.id() == ID_bitreverse)
163+
{
162164
return convert_bitwise(expr);
165+
}
163166
else if(expr.id() == ID_unary_minus)
164167
return convert_unary_minus(to_unary_minus_expr(expr));
165168
else if(expr.id()==ID_unary_plus)

src/solvers/flattening/boolbv_bitwise.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ bvt boolbvt::convert_bitwise(const exprt &expr)
6060

6161
return bv;
6262
}
63+
else if(expr.id() == ID_bitreverse)
64+
{
65+
const exprt &op = to_bitreverse_expr(expr).op();
66+
bvt bv = convert_bv(op, width);
67+
68+
std::reverse(bv.begin(), bv.end());
69+
70+
return bv;
71+
}
6372

6473
UNIMPLEMENTED;
6574
}

0 commit comments

Comments
 (0)