Skip to content

Commit 3799e5d

Browse files
Try all rounding modes when domain is unknown
For rounding modes in constant propagator domain
1 parent 1e295ae commit 3799e5d

File tree

3 files changed

+83
-0
lines changed

3 files changed

+83
-0
lines changed
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+
}
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

+43
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ Author: Peter Schrammel
2222

2323
#include <langapi/language_util.h>
2424
#include <goto-programs/adjust_float_expressions.h>
25+
#include <util/ieee_float.h>
26+
27+
#include <algorithm>
28+
#include <array>
2529

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

0 commit comments

Comments
 (0)