Skip to content

Commit aaf1662

Browse files
Try all rounding modes when domain is unknown
For rounding modes in constant propagator domain
1 parent b926719 commit aaf1662

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <fenv.h>
2+
#include <stdio.h>
3+
#include <assert.h>
4+
5+
int nondet_rounding_mode(void);
6+
7+
int main(void)
8+
{
9+
// slightly bigger than 0.1
10+
float f = 1.0f / 10.0f;
11+
12+
// now we don't know what rounding mode we're in
13+
__CPROVER_rounding_mode = nondet_rounding_mode();
14+
// depending on rounding mode 1.0f/10.0f could
15+
// be greater or smaller than 0.1
16+
17+
// definitely not smaller than -0.1
18+
assert((1.0f / 10.0f) - f < -0.1f);
19+
// might be smaller than 0
20+
assert((1.0f / 10.0f) - f < 0.0f);
21+
// definitely smaller or equal to 0
22+
assert((1.0f / 10.0f) - f <= 0.0f);
23+
// might be greater or equal to 0
24+
assert((1.0f / 10.0f) - f >= 0.0f);
25+
// definitely not greater than 0
26+
assert((1.0f / 10.0f) - f > 0.0f);
27+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
main.c
3+
--constants --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
\[main.assertion.1\] file main.c line 18 function main, assertion \(1.0f / 10.0f\) - f < -0.1f: Failure \(if reachable\)
7+
\[main.assertion.2\] file main.c line 20 function main, assertion \(1.0f / 10.0f\) - f < 0.0f: Unknown
8+
\[main.assertion.3\] file main.c line 22 function main, assertion \(1.0f / 10.0f\) - f <= 0.0f: Success
9+
\[main.assertion.4\] file main.c line 24 function main, assertion \(1.0f / 10.0f\) - f >= 0.0f: Unknown
10+
\[main.assertion.5\] file main.c line 26 function main, assertion \(1.0f / 10.0f\) - f > 0.0f: Failure \(if reachable\)
11+
12+
--
13+
^warning: ignoring

src/analyses/constant_propagator.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ Author: Peter Schrammel
2323

2424
#include <langapi/language_util.h>
2525
#include <goto-programs/adjust_float_expressions.h>
26+
#include <util/ieee_float.h>
27+
28+
#include <algorithm>
29+
#include <array>
2630

2731
void constant_propagator_domaint::assign_rec(
2832
valuest &values,
@@ -510,7 +514,46 @@ bool constant_propagator_domaint::try_evaluate(
510514
exprt &expr,
511515
const namespacet &ns) const
512516
{
517+
const irep_idt ID_rounding_mode = CPROVER_PREFIX "rounding_mode";
513518
adjust_float_expressions(expr, ns);
519+
520+
// if the current rounding mode is top we can
521+
// still get a non-top result by trying all rounding
522+
// modes and checking if the results are all the same
523+
if(!values.is_constant(symbol_exprt(ID_rounding_mode)))
524+
{
525+
// NOLINTNEXTLINE (whitespace/braces)
526+
auto rounding_modes = std::array<ieee_floatt::rounding_modet, 4>{
527+
// NOLINTNEXTLINE (whitespace/braces)
528+
{ieee_floatt::ROUND_TO_EVEN,
529+
ieee_floatt::ROUND_TO_ZERO,
530+
ieee_floatt::ROUND_TO_MINUS_INF,
531+
// NOLINTNEXTLINE (whitespace/braces)
532+
ieee_floatt::ROUND_TO_PLUS_INF}};
533+
// instead of 4, we could write rounding_modes.size() here
534+
// if we dropped Visual Studio 2013 support (no constexpr)
535+
std::array<exprt, 4> possible_results;
536+
for(std::size_t i = 0; i < possible_results.size(); ++i)
537+
{
538+
constant_propagator_domaint child(*this);
539+
child.values.set_to(
540+
ID_rounding_mode, from_integer(rounding_modes[i], integer_typet()));
541+
possible_results[i] = expr;
542+
if(child.try_evaluate(possible_results[i], ns))
543+
{
544+
return true;
545+
}
546+
}
547+
for(auto const &possible_result : possible_results)
548+
{
549+
if(possible_result != possible_results.front())
550+
{
551+
return true;
552+
}
553+
}
554+
expr = possible_results.front();
555+
return false;
556+
}
514557
bool did_not_change_anything = values.replace_const.replace(expr);
515558
did_not_change_anything &= simplify(expr, ns);
516559
return did_not_change_anything;

0 commit comments

Comments
 (0)