Skip to content

Commit ac1e4dd

Browse files
authored
Merge pull request #5879 from tautschnig/clz-expression
New expression: count_leading_zeros_exprt
2 parents b0b86a2 + 7409997 commit ac1e4dd

File tree

24 files changed

+308
-218
lines changed

24 files changed

+308
-218
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
int main()
2+
{
3+
#ifdef __GNUC__
4+
_Static_assert(
5+
__builtin_clz(0xffU) == 8 * sizeof(unsigned) - 8,
6+
"GCC/Clang compile-time constant");
7+
#endif
8+
9+
return 0;
10+
}

regression/cbmc-library/__builtin_clz-02/main.c

Lines changed: 0 additions & 12 deletions
This file was deleted.

regression/cbmc-library/__builtin_clz-01/main.c renamed to regression/cbmc/__builtin_clz-01/main.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,9 @@ int main()
5656
__CPROVER_assume(u != 0);
5757
assert(nlz2a(u) == __builtin_clz(u));
5858

59+
#undef __builtin_clz
60+
// a failing assertion should be generated as __builtin_clz is undefined for 0
61+
__builtin_clz(0U);
62+
5963
return 0;
6064
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
CORE
2+
main.c
3+
--bounds-check
4+
^\[main.bit_count.\d+\] line 61 count leading zeros argument in __builtin_clz\(0u\): FAILURE$
5+
^\*\* 1 of \d+ failed
6+
^VERIFICATION FAILED$
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring

scripts/expected_doxygen_warnings.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,19 @@
2121
warning: Include graph for 'goto_instrument_parse_options.cpp' not generated, too many nodes (97), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
2222
warning: Included by graph for 'goto_functions.h' not generated, too many nodes (66), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
2323
warning: Included by graph for 'goto_model.h' not generated, too many nodes (110), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
24-
warning: Included by graph for 'arith_tools.h' not generated, too many nodes (182), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
24+
warning: Included by graph for 'arith_tools.h' not generated, too many nodes (181), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
2525
warning: Included by graph for 'c_types.h' not generated, too many nodes (110), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
2626
warning: Included by graph for 'config.h' not generated, too many nodes (87), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
2727
warning: Included by graph for 'exception_utils.h' not generated, too many nodes (61), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
2828
warning: Included by graph for 'expr.h' not generated, too many nodes (87), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
2929
warning: Included by graph for 'expr_util.h' not generated, too many nodes (61), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
30-
warning: Included by graph for 'invariant.h' not generated, too many nodes (187), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
30+
warning: Included by graph for 'invariant.h' not generated, too many nodes (186), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3131
warning: Included by graph for 'irep.h' not generated, too many nodes (62), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3232
warning: Included by graph for 'message.h' not generated, too many nodes (117), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3333
warning: Included by graph for 'namespace.h' not generated, too many nodes (109), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3434
warning: Included by graph for 'pointer_expr.h' not generated, too many nodes (117), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3535
warning: Included by graph for 'prefix.h' not generated, too many nodes (85), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
36-
warning: Included by graph for 'simplify_expr.h' not generated, too many nodes (77), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
36+
warning: Included by graph for 'simplify_expr.h' not generated, too many nodes (79), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3737
warning: Included by graph for 'std_code.h' not generated, too many nodes (78), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3838
warning: Included by graph for 'std_expr.h' not generated, too many nodes (241), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.
3939
warning: Included by graph for 'std_types.h' not generated, too many nodes (102), threshold is 60. Consider increasing DOT_GRAPH_MAX_NODES.

src/analyses/goto_check.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,9 @@ class goto_checkt
172172

173173
using conditionst = std::list<conditiont>;
174174

175-
void bounds_check(const index_exprt &, const guardt &);
175+
void bounds_check(const exprt &, const guardt &);
176+
void bounds_check_index(const index_exprt &, const guardt &);
177+
void bounds_check_clz(const count_leading_zeros_exprt &, const guardt &);
176178
void div_by_zero_check(const div_exprt &, const guardt &);
177179
void mod_by_zero_check(const mod_exprt &, const guardt &);
178180
void mod_overflow_check(const mod_exprt &, const guardt &);
@@ -1321,17 +1323,28 @@ std::string goto_checkt::array_name(const exprt &expr)
13211323
return ::array_name(ns, expr);
13221324
}
13231325

1324-
void goto_checkt::bounds_check(
1325-
const index_exprt &expr,
1326-
const guardt &guard)
1326+
void goto_checkt::bounds_check(const exprt &expr, const guardt &guard)
13271327
{
13281328
if(!enable_bounds_check)
13291329
return;
13301330

1331-
if(expr.find("bounds_check").is_not_nil() &&
1332-
!expr.get_bool("bounds_check"))
1331+
if(
1332+
expr.find(ID_C_bounds_check).is_not_nil() &&
1333+
!expr.get_bool(ID_C_bounds_check))
1334+
{
13331335
return;
1336+
}
13341337

1338+
if(expr.id() == ID_index)
1339+
bounds_check_index(to_index_expr(expr), guard);
1340+
else if(expr.id() == ID_count_leading_zeros)
1341+
bounds_check_clz(to_count_leading_zeros_expr(expr), guard);
1342+
}
1343+
1344+
void goto_checkt::bounds_check_index(
1345+
const index_exprt &expr,
1346+
const guardt &guard)
1347+
{
13351348
typet array_type = expr.array().type();
13361349

13371350
if(array_type.id()==ID_pointer)
@@ -1507,6 +1520,19 @@ void goto_checkt::bounds_check(
15071520
}
15081521
}
15091522

1523+
void goto_checkt::bounds_check_clz(
1524+
const count_leading_zeros_exprt &expr,
1525+
const guardt &guard)
1526+
{
1527+
add_guarded_property(
1528+
notequal_exprt{expr.op(), from_integer(0, expr.op().type())},
1529+
"count leading zeros argument",
1530+
"bit count",
1531+
expr.find_source_location(),
1532+
expr,
1533+
guard);
1534+
}
1535+
15101536
void goto_checkt::add_guarded_property(
15111537
const exprt &asserted_expr,
15121538
const std::string &comment,
@@ -1726,7 +1752,7 @@ void goto_checkt::check_rec(const exprt &expr, guardt &guard)
17261752

17271753
if(expr.id()==ID_index)
17281754
{
1729-
bounds_check(to_index_expr(expr), guard);
1755+
bounds_check(expr, guard);
17301756
}
17311757
else if(expr.id()==ID_div)
17321758
{
@@ -1763,6 +1789,10 @@ void goto_checkt::check_rec(const exprt &expr, guardt &guard)
17631789
{
17641790
pointer_primitive_check(expr, guard);
17651791
}
1792+
else if(expr.id() == ID_count_leading_zeros)
1793+
{
1794+
bounds_check(expr, guard);
1795+
}
17661796
}
17671797

17681798
void goto_checkt::check(const exprt &expr)

src/ansi-c/ansi_c_entry_point.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ bool generate_ansi_c_start_function(
407407
argv_symbol.symbol_expr(), argc_symbol.symbol_expr());
408408

409409
// disable bounds check on that one
410-
index_expr.set("bounds_check", false);
410+
index_expr.set(ID_C_bounds_check, false);
411411

412412
init_code.add(code_assignt(index_expr, null));
413413
}
@@ -423,7 +423,7 @@ bool generate_ansi_c_start_function(
423423
index_exprt index_expr(
424424
envp_symbol.symbol_expr(), envp_size_symbol.symbol_expr());
425425
// disable bounds check on that one
426-
index_expr.set("bounds_check", false);
426+
index_expr.set(ID_C_bounds_check, false);
427427

428428
equal_exprt is_null(std::move(index_expr), std::move(null));
429429

@@ -449,7 +449,7 @@ bool generate_ansi_c_start_function(
449449
argv_symbol.symbol_expr(), from_integer(0, index_type()));
450450

451451
// disable bounds check on that one
452-
index_expr.set("bounds_check", false);
452+
index_expr.set(ID_C_bounds_check, false);
453453

454454
const pointer_typet &pointer_type =
455455
to_pointer_type(parameters[1].type());

src/ansi-c/c_typecheck_expr.cpp

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2689,27 +2689,14 @@ exprt c_typecheck_baset::do_special_functions(
26892689
throw 0;
26902690
}
26912691

2692-
side_effect_expr_function_callt try_constant{expr};
2693-
typecheck_function_call_arguments(try_constant);
2694-
exprt argument = try_constant.arguments().front();
2695-
simplify(argument, *this);
2696-
const auto int_constant = numeric_cast<mp_integer>(argument);
2697-
2698-
if(
2699-
!int_constant.has_value() || *int_constant == 0 ||
2700-
argument.type().id() != ID_unsignedbv)
2701-
{
2702-
return nil_exprt{};
2703-
}
2692+
typecheck_function_call_arguments(expr);
27042693

2705-
const std::string binary_value = integer2binary(
2706-
*int_constant, to_unsignedbv_type(argument.type()).get_width());
2707-
std::size_t n_leading_zeros = binary_value.find('1');
2708-
CHECK_RETURN(n_leading_zeros != std::string::npos);
2694+
count_leading_zeros_exprt clz{expr.arguments().front(),
2695+
has_prefix(id2string(identifier), "__lzcnt"),
2696+
expr.type()};
2697+
clz.add_source_location() = source_location;
27092698

2710-
return from_integer(
2711-
n_leading_zeros,
2712-
to_code_type(try_constant.function().type()).return_type());
2699+
return std::move(clz);
27132700
}
27142701
else if(identifier==CPROVER_PREFIX "equal")
27152702
{

src/ansi-c/expr2c.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3896,6 +3896,9 @@ std::string expr2ct::convert_with_precedence(
38963896
else if(src.id()==ID_type)
38973897
return convert(src.type());
38983898

3899+
else if(src.id() == ID_count_leading_zeros)
3900+
return convert_function(src, "__builtin_clz");
3901+
38993902
// no C language expression for internal representation
39003903
return convert_norep(src, precedence);
39013904
}

src/ansi-c/library/gcc.c

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -33,64 +33,6 @@ inline void __sync_synchronize(void)
3333
#endif
3434
}
3535

36-
/* FUNCTION: __builtin_clz */
37-
38-
int __builtin_popcount(unsigned int);
39-
40-
inline int __builtin_clz(unsigned int x)
41-
{
42-
__CPROVER_precondition(x != 0, "__builtin_clz(0) is undefined");
43-
44-
x = x | (x >> 1);
45-
x = x | (x >> 2);
46-
x = x | (x >> 4);
47-
x = x | (x >> 8);
48-
if(sizeof(x) >= 4)
49-
x = x | (x >> 16);
50-
51-
return __builtin_popcount(~x);
52-
}
53-
54-
/* FUNCTION: __builtin_clzl */
55-
56-
int __builtin_popcountl(unsigned long int);
57-
58-
inline int __builtin_clzl(unsigned long int x)
59-
{
60-
__CPROVER_precondition(x != 0, "__builtin_clzl(0) is undefined");
61-
62-
x = x | (x >> 1);
63-
x = x | (x >> 2);
64-
x = x | (x >> 4);
65-
x = x | (x >> 8);
66-
if(sizeof(x) >= 4)
67-
x = x | (x >> 16);
68-
if(sizeof(x) >= 8)
69-
x = x | (x >> 32);
70-
71-
return __builtin_popcountl(~x);
72-
}
73-
74-
/* FUNCTION: __builtin_clzll */
75-
76-
int __builtin_popcountll(unsigned long long int);
77-
78-
inline int __builtin_clzll(unsigned long long int x)
79-
{
80-
__CPROVER_precondition(x != 0, "__builtin_clzll(0) is undefined");
81-
82-
x = x | (x >> 1);
83-
x = x | (x >> 2);
84-
x = x | (x >> 4);
85-
x = x | (x >> 8);
86-
if(sizeof(x) >= 4)
87-
x = x | (x >> 16);
88-
if(sizeof(x) >= 8)
89-
x = x | (x >> 32);
90-
91-
return __builtin_popcountll(~x);
92-
}
93-
9436
/* FUNCTION: __builtin_ffs */
9537

9638
int __builtin_clz(unsigned int x);

src/ansi-c/library/windows.c

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -51,46 +51,3 @@ inline HANDLE CreateThread(
5151
return handle;
5252
}
5353
#endif
54-
55-
/* FUNCTION: __lzcnt16 */
56-
57-
#ifdef _MSC_VER
58-
int __builtin_clz(unsigned int x);
59-
60-
unsigned short __lzcnt16(unsigned short value)
61-
{
62-
if(value == 0)
63-
return 16;
64-
65-
return __builtin_clz(value) -
66-
(sizeof(unsigned int) - sizeof(unsigned short)) * 8;
67-
}
68-
#endif
69-
70-
/* FUNCTION: __lzcnt */
71-
72-
#ifdef _MSC_VER
73-
int __builtin_clz(unsigned int x);
74-
75-
unsigned int __lzcnt(unsigned int value)
76-
{
77-
if(value == 0)
78-
return 32;
79-
80-
return __builtin_clz(value);
81-
}
82-
#endif
83-
84-
/* FUNCTION: __lzcnt64 */
85-
86-
#ifdef _MSC_VER
87-
int __builtin_clzll(unsigned long long x);
88-
89-
unsigned __int64 __lzcnt64(unsigned __int64 value)
90-
{
91-
if(value == 0)
92-
return 64;
93-
94-
return __builtin_clzll(value);
95-
}
96-
#endif

src/goto-programs/string_abstraction.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -570,7 +570,7 @@ void string_abstractiont::abstract_function_call(
570570

571571
index_exprt idx(str_args.back(), from_integer(0, index_type()));
572572
// disable bounds check on that one
573-
idx.set("bounds_check", false);
573+
idx.set(ID_C_bounds_check, false);
574574

575575
str_args.back()=address_of_exprt(idx);
576576
}

src/solvers/Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,6 @@ SRC = $(BOOLEFORCE_SRC) \
141141
floatbv/float_approximation.cpp \
142142
lowering/byte_operators.cpp \
143143
lowering/functions.cpp \
144-
lowering/popcount.cpp \
145144
bdd/miniBDD/miniBDD.cpp \
146145
prop/bdd_expr.cpp \
147146
prop/cover_goals.cpp \

src/solvers/flattening/boolbv.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Author: Daniel Kroening, kroening@kroening.com
1919
#include <util/magic.h>
2020
#include <util/mp_arith.h>
2121
#include <util/replace_expr.h>
22+
#include <util/simplify_expr.h>
2223
#include <util/std_expr.h>
2324
#include <util/std_types.h>
2425
#include <util/string2int.h>
@@ -227,7 +228,12 @@ bvt boolbvt::convert_bitvector(const exprt &expr)
227228
else if(expr.id()==ID_power)
228229
return convert_power(to_binary_expr(expr));
229230
else if(expr.id() == ID_popcount)
230-
return convert_bv(lower_popcount(to_popcount_expr(expr), ns));
231+
return convert_bv(simplify_expr(to_popcount_expr(expr).lower(), ns));
232+
else if(expr.id() == ID_count_leading_zeros)
233+
{
234+
return convert_bv(
235+
simplify_expr(to_count_leading_zeros_expr(expr).lower(), ns));
236+
}
231237

232238
return conversion_failed(expr);
233239
}

src/solvers/lowering/expr_lowering.h

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ Author: Michael Tautschnig
1414
class byte_extract_exprt;
1515
class byte_update_exprt;
1616
class namespacet;
17-
class popcount_exprt;
1817

1918
/// Rewrite a byte extract expression to more fundamental operations.
2019
/// \param src: Byte extract expression
@@ -44,10 +43,4 @@ exprt lower_byte_operators(const exprt &src, const namespacet &ns);
4443

4544
bool has_byte_operator(const exprt &src);
4645

47-
/// Lower a popcount_exprt to arithmetic and logic expressions
48-
/// \param expr: Input expression to be translated
49-
/// \param ns: Namespace for type lookups
50-
/// \return Semantically equivalent expression
51-
exprt lower_popcount(const popcount_exprt &expr, const namespacet &ns);
52-
5346
#endif /* CPROVER_SOLVERS_LOWERING_EXPR_LOWERING_H */

0 commit comments

Comments
 (0)