Skip to content

Commit b1435ff

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

File tree

8 files changed

+121
-14
lines changed

8 files changed

+121
-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

+68-11
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Author: Peter Schrammel
1010
/// Constant Propagation
1111

1212
#include "constant_propagator.h"
13+
#include <util/ieee_float.h>
1314

1415
#ifdef DEBUG
1516
#include <iostream>
@@ -22,7 +23,10 @@ Author: Peter Schrammel
2223
#include <util/cprover_prefix.h>
2324

2425
#include <langapi/language_util.h>
25-
#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,
@@ -36,7 +40,7 @@ void constant_propagator_domaint::assign_rec(
3640
const symbol_exprt &s=to_symbol_expr(lhs);
3741

3842
exprt tmp=rhs;
39-
try_evaluate(tmp, ns);
43+
partial_evaluate(tmp, ns);
4044

4145
if(tmp.is_constant())
4246
values.set_to(s, tmp);
@@ -102,7 +106,7 @@ void constant_propagator_domaint::transform(
102106
g = from->guard;
103107
else
104108
g = not_exprt(from->guard);
105-
try_evaluate(g, ns);
109+
partial_evaluate(g, ns);
106110
if(g.is_false())
107111
values.set_to_bottom();
108112
else
@@ -269,7 +273,7 @@ bool constant_propagator_domaint::ai_simplify(
269273
exprt &condition,
270274
const namespacet &ns) const
271275
{
272-
return try_evaluate(condition, ns);
276+
return partial_evaluate(condition, ns);
273277
}
274278

275279

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

542599
if(it->is_goto() || it->is_assume() || it->is_assert())
543600
{
544-
s_it->second.try_evaluate(it->guard, ns);
601+
s_it->second.partial_evaluate(it->guard, ns);
545602
}
546603
else if(it->is_assign())
547604
{
548605
exprt &rhs=to_code_assign(it->code).rhs();
549-
s_it->second.try_evaluate(rhs, ns);
606+
s_it->second.partial_evaluate(rhs, ns);
550607
if(rhs.id()==ID_constant)
551608
rhs.add_source_location()=it->code.op0().source_location();
552609
}
553610
else if(it->is_function_call())
554611
{
555612
exprt &function = to_code_function_call(it->code).function();
556-
s_it->second.try_evaluate(function, ns);
613+
s_it->second.partial_evaluate(function, ns);
557614

558615
exprt::operandst &args=
559616
to_code_function_call(it->code).arguments();
560617

561618
for(auto &arg : args)
562619
{
563-
s_it->second.try_evaluate(arg, ns);
620+
s_it->second.partial_evaluate(arg, ns);
564621
}
565622
}
566623
else if(it->is_other())
567624
{
568625
if(it->code.get_statement()==ID_expression)
569626
{
570-
s_it->second.try_evaluate(it->code, ns);
627+
s_it->second.partial_evaluate(it->code, ns);
571628
}
572629
}
573630
}

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)