Skip to content

Commit cef957d

Browse files
committed
Fix simplification of bit counting for big endian architectures
We need to start searching from the least or most significant bit, the position of which depends on endianness.
1 parent 63b8b71 commit cef957d

File tree

4 files changed

+53
-20
lines changed

4 files changed

+53
-20
lines changed
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 --big-endian
4+
^\[main.bit_count.\d+\] line 61 count leading zeros is undefined for value zero in __builtin_clz\(0u\): FAILURE$
5+
^\*\* 1 of \d+ failed
6+
^VERIFICATION FAILED$
7+
^EXIT=10$
8+
^SIGNAL=0$
9+
--
10+
^warning: ignoring
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
main.c
3+
--bounds-check --big-endian
4+
^\[main.bit_count.\d+\] line 46 count trailing zeros is undefined for value zero in __builtin_ctz\(0u\): FAILURE$
5+
^\[main.assertion.2\] line 47 count trailing zeros of 0 is bit width: SUCCESS$
6+
^\*\* 1 of \d+ failed
7+
^VERIFICATION FAILED$
8+
^EXIT=10$
9+
^SIGNAL=0$
10+
--
11+
^warning: ignoring
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--pointer-check --bounds-check --big-endian
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^VERIFICATION SUCCESSFUL$
7+
--
8+
^warning: ignoring

src/util/simplify_expr.cpp

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -150,24 +150,24 @@ simplify_exprt::simplify_popcount(const popcount_exprt &expr)
150150
simplify_exprt::resultt<>
151151
simplify_exprt::simplify_clz(const count_leading_zeros_exprt &expr)
152152
{
153-
const auto const_bits_opt = expr2bits(
154-
expr.op(),
155-
config.ansi_c.endianness == configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN,
156-
ns);
153+
const bool is_little_endian =
154+
config.ansi_c.endianness == configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN;
155+
156+
const auto const_bits_opt = expr2bits(expr.op(), is_little_endian, ns);
157157

158158
if(!const_bits_opt.has_value())
159159
return unchanged(expr);
160160

161-
// expr2bits generates a bit string starting with the least-significant bit
162-
std::size_t n_leading_zeros = const_bits_opt->rfind('1');
161+
std::size_t n_leading_zeros =
162+
is_little_endian ? const_bits_opt->rfind('1') : const_bits_opt->find('1');
163163
if(n_leading_zeros == std::string::npos)
164164
{
165165
if(!expr.zero_permitted())
166166
return unchanged(expr);
167167

168168
n_leading_zeros = const_bits_opt->size();
169169
}
170-
else
170+
else if(is_little_endian)
171171
n_leading_zeros = const_bits_opt->size() - n_leading_zeros - 1;
172172

173173
return from_integer(n_leading_zeros, expr.type());
@@ -176,44 +176,48 @@ simplify_exprt::simplify_clz(const count_leading_zeros_exprt &expr)
176176
simplify_exprt::resultt<>
177177
simplify_exprt::simplify_ctz(const count_trailing_zeros_exprt &expr)
178178
{
179-
const auto const_bits_opt = expr2bits(
180-
expr.op(),
181-
config.ansi_c.endianness == configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN,
182-
ns);
179+
const bool is_little_endian =
180+
config.ansi_c.endianness == configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN;
181+
182+
const auto const_bits_opt = expr2bits(expr.op(), is_little_endian, ns);
183183

184184
if(!const_bits_opt.has_value())
185185
return unchanged(expr);
186186

187-
// expr2bits generates a bit string starting with the least-significant bit
188-
std::size_t n_trailing_zeros = const_bits_opt->find('1');
187+
std::size_t n_trailing_zeros =
188+
is_little_endian ? const_bits_opt->find('1') : const_bits_opt->rfind('1');
189189
if(n_trailing_zeros == std::string::npos)
190190
{
191191
if(!expr.zero_permitted())
192192
return unchanged(expr);
193193

194194
n_trailing_zeros = const_bits_opt->size();
195195
}
196+
else if(!is_little_endian)
197+
n_trailing_zeros = const_bits_opt->size() - n_trailing_zeros - 1;
196198

197199
return from_integer(n_trailing_zeros, expr.type());
198200
}
199201

200202
simplify_exprt::resultt<>
201203
simplify_exprt::simplify_ffs(const find_first_set_exprt &expr)
202204
{
203-
const auto const_bits_opt = expr2bits(
204-
expr.op(),
205-
config.ansi_c.endianness == configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN,
206-
ns);
205+
const bool is_little_endian =
206+
config.ansi_c.endianness == configt::ansi_ct::endiannesst::IS_LITTLE_ENDIAN;
207+
208+
const auto const_bits_opt = expr2bits(expr.op(), is_little_endian, ns);
207209

208210
if(!const_bits_opt.has_value())
209211
return unchanged(expr);
210212

211-
// expr2bits generates a bit string starting with the least-significant bit
212-
std::size_t first_one_bit = const_bits_opt->find('1');
213+
std::size_t first_one_bit =
214+
is_little_endian ? const_bits_opt->find('1') : const_bits_opt->rfind('1');
213215
if(first_one_bit == std::string::npos)
214216
first_one_bit = 0;
215-
else
217+
else if(is_little_endian)
216218
++first_one_bit;
219+
else
220+
first_one_bit = const_bits_opt->size() - first_one_bit;
217221

218222
return from_integer(first_one_bit, expr.type());
219223
}

0 commit comments

Comments
 (0)