Skip to content

Commit a055454

Browse files
Try all rounding modes when domain is unknown
For rounding modes in constant propagator domain
1 parent 5f7bc15 commit a055454

File tree

8 files changed

+120
-14
lines changed

8 files changed

+120
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#include <assert.h>
2+
#include <fenv.h>
3+
#include <stdio.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

+67-11
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ Author: Peter Schrammel
1616
#include <util/format_expr.h>
1717
#endif
1818

19+
#include <util/ieee_float.h>
1920
#include <util/find_symbols.h>
2021
#include <util/arith_tools.h>
2122
#include <util/simplify_expr.h>
2223
#include <util/cprover_prefix.h>
2324

2425
#include <langapi/language_util.h>
25-
#include <goto-programs/adjust_float_expressions.h>
26+
27+
#include <algorithm>
28+
#include <array>
2629

2730
void constant_propagator_domaint::assign_rec(
2831
valuest &values,
@@ -36,7 +39,7 @@ void constant_propagator_domaint::assign_rec(
3639
const symbol_exprt &s=to_symbol_expr(lhs);
3740

3841
exprt tmp=rhs;
39-
try_evaluate(tmp, ns);
42+
partial_evaluate(tmp, ns);
4043

4144
if(tmp.is_constant())
4245
values.set_to(s, tmp);
@@ -102,7 +105,7 @@ void constant_propagator_domaint::transform(
102105
g = from->guard;
103106
else
104107
g = not_exprt(from->guard);
105-
try_evaluate(g, ns);
108+
partial_evaluate(g, ns);
106109
if(g.is_false())
107110
values.set_to_bottom();
108111
else
@@ -269,7 +272,7 @@ bool constant_propagator_domaint::ai_simplify(
269272
exprt &condition,
270273
const namespacet &ns) const
271274
{
272-
return try_evaluate(condition, ns);
275+
return partial_evaluate(condition, ns);
273276
}
274277

275278

@@ -506,11 +509,64 @@ bool constant_propagator_domaint::merge(
506509
/// \param expr The expression to evaluate
507510
/// \param ns The namespace for symbols in the expression
508511
/// \return True if the expression is unchanged, false otherwise
509-
bool constant_propagator_domaint::try_evaluate(
512+
bool constant_propagator_domaint::partial_evaluate(
513+
exprt &expr,
514+
const namespacet &ns) const
515+
{
516+
// if the current rounding mode is top we can
517+
// still get a non-top result by trying all rounding
518+
// modes and checking if the results are all the same
519+
if(!values.is_constant(symbol_exprt(ID_cprover_rounding_mode_str)))
520+
{
521+
return partial_evaluate_with_all_rounding_modes(expr, ns);
522+
}
523+
return replace_constants_and_simplify(expr, ns);
524+
}
525+
526+
/// Attempt to evaluate an expression in all rounding modes.
527+
///
528+
/// If the result is the same for all rounding modes, change
529+
/// expr to that result and return false. Otherwise, return true.
530+
bool constant_propagator_domaint::partial_evaluate_with_all_rounding_modes(
531+
exprt &expr,
532+
const namespacet &ns) const
533+
{ // NOLINTNEXTLINE (whitespace/braces)
534+
auto rounding_modes = std::array<ieee_floatt::rounding_modet, 4>{
535+
// NOLINTNEXTLINE (whitespace/braces)
536+
{ieee_floatt::ROUND_TO_EVEN,
537+
ieee_floatt::ROUND_TO_ZERO,
538+
ieee_floatt::ROUND_TO_MINUS_INF,
539+
// NOLINTNEXTLINE (whitespace/braces)
540+
ieee_floatt::ROUND_TO_PLUS_INF}};
541+
exprt first_result;
542+
for(std::size_t i = 0; i < rounding_modes.size(); ++i)
543+
{
544+
constant_propagator_domaint child(*this);
545+
child.values.set_to(
546+
ID_cprover_rounding_mode_str,
547+
from_integer(rounding_modes[i], integer_typet()));
548+
exprt result = expr;
549+
if(child.replace_constants_and_simplify(result, ns))
550+
{
551+
return true;
552+
}
553+
else if(i == 0)
554+
{
555+
first_result = result;
556+
}
557+
else if(result != first_result)
558+
{
559+
return true;
560+
}
561+
}
562+
expr = first_result;
563+
return false;
564+
}
565+
566+
bool constant_propagator_domaint::replace_constants_and_simplify(
510567
exprt &expr,
511568
const namespacet &ns) const
512569
{
513-
adjust_float_expressions(expr, ns);
514570
bool did_not_change_anything = values.replace_const.replace(expr);
515571
did_not_change_anything &= simplify(expr, ns);
516572
return did_not_change_anything;
@@ -541,33 +597,33 @@ void constant_propagator_ait::replace(
541597

542598
if(it->is_goto() || it->is_assume() || it->is_assert())
543599
{
544-
s_it->second.try_evaluate(it->guard, ns);
600+
s_it->second.partial_evaluate(it->guard, ns);
545601
}
546602
else if(it->is_assign())
547603
{
548604
exprt &rhs=to_code_assign(it->code).rhs();
549-
s_it->second.try_evaluate(rhs, ns);
605+
s_it->second.partial_evaluate(rhs, ns);
550606
if(rhs.id()==ID_constant)
551607
rhs.add_source_location()=it->code.op0().source_location();
552608
}
553609
else if(it->is_function_call())
554610
{
555611
exprt &function = to_code_function_call(it->code).function();
556-
s_it->second.try_evaluate(function, ns);
612+
s_it->second.partial_evaluate(function, ns);
557613

558614
exprt::operandst &args=
559615
to_code_function_call(it->code).arguments();
560616

561617
for(auto &arg : args)
562618
{
563-
s_it->second.try_evaluate(arg, ns);
619+
s_it->second.partial_evaluate(arg, ns);
564620
}
565621
}
566622
else if(it->is_other())
567623
{
568624
if(it->code.get_statement()==ID_expression)
569625
{
570-
s_it->second.try_evaluate(it->code, ns);
626+
s_it->second.partial_evaluate(it->code, ns);
571627
}
572628
}
573629
}

src/analyses/constant_propagator.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ class constant_propagator_domaint:public ai_domain_baset
138138

139139
valuest values;
140140

141-
bool try_evaluate(exprt &expr, const namespacet &ns) const;
141+
bool partial_evaluate(exprt &expr, const namespacet &ns) const;
142142

143143
protected:
144144
void assign_rec(
@@ -149,6 +149,12 @@ class constant_propagator_domaint:public ai_domain_baset
149149
bool two_way_propagate_rec(
150150
const exprt &expr,
151151
const namespacet &ns);
152+
153+
bool partial_evaluate_with_all_rounding_modes(
154+
exprt &expr,
155+
const namespacet &ns) const;
156+
157+
bool replace_constants_and_simplify(exprt &expr, const namespacet &ns) const;
152158
};
153159

154160
class constant_propagator_ait:public ait<constant_propagator_domaint>

src/cbmc/cbmc_parse_options.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ Author: Daniel Kroening, [email protected]
2727
#include <ansi-c/c_preprocess.h>
2828

2929
#include <goto-programs/adjust_float_expressions.h>
30-
#include <goto-programs/convert_nondet.h>
3130
#include <goto-programs/initialize_goto_model.h>
3231
#include <goto-programs/instrument_preconditions.h>
3332
#include <goto-programs/goto_convert_functions.h>

src/goto-analyzer/goto_analyzer_parse_options.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ Author: Daniel Kroening, [email protected]
5656
#include <util/exit_codes.h>
5757

5858
#include <cbmc/version.h>
59+
#include <goto-programs/adjust_float_expressions.h>
5960

6061
#include "taint_analysis.h"
6162
#include "unreachable_instructions.h"
@@ -477,6 +478,7 @@ int goto_analyzer_parse_optionst::doit()
477478
/// Depending on the command line mode, run one of the analysis tasks
478479
int goto_analyzer_parse_optionst::perform_analysis(const optionst &options)
479480
{
481+
adjust_float_expressions(goto_model);
480482
if(options.get_bool_option("taint"))
481483
{
482484
std::string taint_file=cmdline.get_value("taint");

src/jbmc/jbmc_parse_options.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ Author: Daniel Kroening, [email protected]
2727
#include <ansi-c/ansi_c_language.h>
2828

2929
#include <goto-programs/adjust_float_expressions.h>
30-
#include <goto-programs/convert_nondet.h>
3130
#include <goto-programs/lazy_goto_model.h>
3231
#include <goto-programs/instrument_preconditions.h>
3332
#include <goto-programs/goto_convert_functions.h>

src/util/ieee_float.h

+4
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,14 @@ Author: Daniel Kroening, [email protected]
1414

1515
#include "mp_arith.h"
1616
#include "format_spec.h"
17+
#include "irep.h"
18+
#include "cprover_prefix.h"
1719

1820
class constant_exprt;
1921
class floatbv_typet;
2022

23+
const char ID_cprover_rounding_mode_str[] = CPROVER_PREFIX "rounding_mode";
24+
2125
class ieee_float_spect
2226
{
2327
public:

0 commit comments

Comments
 (0)