Skip to content

Commit 9cc6aae

Browse files
Merge pull request diffblue#2081 from hannes-steffenhagen-diffblue/floating_point_simplificiation
Floating point simplification for goto-analyzer constants domain
2 parents 06d8bea + a055454 commit 9cc6aae

File tree

19 files changed

+188
-35
lines changed

19 files changed

+188
-35
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <assert.h>
2+
3+
#define ROUND_F(x) ((int)((x) + 0.5f))
4+
int eight = ROUND_F(100.0f / 12.0f);
5+
6+
int main()
7+
{
8+
assert(eight == 8);
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
main.c
3+
--constants --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.assertion.1\] file main.c line 8 function main, assertion eight == 8: Success$
7+
--
8+
^warning: ignoring
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
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <assert.h>
2+
3+
int main(void)
4+
{
5+
__CPROVER_rounding_mode = 0;
6+
float rounded_up = 1.0f / 10.0f;
7+
__CPROVER_rounding_mode = 1;
8+
float rounded_down = 1.0f / 10.0f;
9+
assert(rounded_up - 0.1f >= 0);
10+
assert(rounded_down - 0.1f < 0);
11+
return 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CORE
2+
main.c
3+
--constants --verify
4+
^EXIT=0$
5+
^SIGNAL=0$
6+
^\[main.assertion.1\] file main.c line 9 function main, assertion rounded_up - 0.1f >= 0: Success
7+
^\[main.assertion.2\] file main.c line 10 function main, assertion rounded_down - 0.1f < 0: Success
8+
--
9+
^warning: ignoring

src/analyses/constant_propagator.cpp

+86-22
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ 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>
2526

27+
#include <algorithm>
28+
#include <array>
29+
2630
void constant_propagator_domaint::assign_rec(
2731
valuest &values,
2832
const exprt &lhs,
@@ -35,8 +39,7 @@ void constant_propagator_domaint::assign_rec(
3539
const symbol_exprt &s=to_symbol_expr(lhs);
3640

3741
exprt tmp=rhs;
38-
values.replace_const(tmp);
39-
simplify(tmp, ns);
42+
partial_evaluate(tmp, ns);
4043

4144
if(tmp.is_constant())
4245
values.set_to(s, tmp);
@@ -99,10 +102,10 @@ void constant_propagator_domaint::transform(
99102
// Comparing iterators is safe as the target must be within the same list
100103
// of instructions because this is a GOTO.
101104
if(from->get_target()==to)
102-
g=simplify_expr(from->guard, ns);
105+
g = from->guard;
103106
else
104-
g=simplify_expr(not_exprt(from->guard), ns);
105-
107+
g = not_exprt(from->guard);
108+
partial_evaluate(g, ns);
106109
if(g.is_false())
107110
values.set_to_bottom();
108111
else
@@ -269,10 +272,7 @@ bool constant_propagator_domaint::ai_simplify(
269272
exprt &condition,
270273
const namespacet &ns) const
271274
{
272-
bool b=values.replace_const.replace(condition);
273-
b&=simplify(condition, ns);
274-
275-
return b;
275+
return partial_evaluate(condition, ns);
276276
}
277277

278278

@@ -504,6 +504,74 @@ bool constant_propagator_domaint::merge(
504504
return values.merge(other.values);
505505
}
506506

507+
/// Attempt to evaluate expression using domain knowledge
508+
/// This function changes the expression that is passed into it.
509+
/// \param expr The expression to evaluate
510+
/// \param ns The namespace for symbols in the expression
511+
/// \return True if the expression is unchanged, false otherwise
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(
567+
exprt &expr,
568+
const namespacet &ns) const
569+
{
570+
bool did_not_change_anything = values.replace_const.replace(expr);
571+
did_not_change_anything &= simplify(expr, ns);
572+
return did_not_change_anything;
573+
}
574+
507575
void constant_propagator_ait::replace(
508576
goto_functionst &goto_functions,
509577
const namespacet &ns)
@@ -529,38 +597,34 @@ void constant_propagator_ait::replace(
529597

530598
if(it->is_goto() || it->is_assume() || it->is_assert())
531599
{
532-
s_it->second.values.replace_const(it->guard);
533-
simplify(it->guard, ns);
600+
s_it->second.partial_evaluate(it->guard, ns);
534601
}
535602
else if(it->is_assign())
536603
{
537604
exprt &rhs=to_code_assign(it->code).rhs();
538-
s_it->second.values.replace_const(rhs);
539-
simplify(rhs, ns);
605+
s_it->second.partial_evaluate(rhs, ns);
540606
if(rhs.id()==ID_constant)
541607
rhs.add_source_location()=it->code.op0().source_location();
542608
}
543609
else if(it->is_function_call())
544610
{
545-
s_it->second.values.replace_const(
546-
to_code_function_call(it->code).function());
547-
548-
simplify(to_code_function_call(it->code).function(), ns);
611+
exprt &function = to_code_function_call(it->code).function();
612+
s_it->second.partial_evaluate(function, ns);
549613

550614
exprt::operandst &args=
551615
to_code_function_call(it->code).arguments();
552616

553-
for(exprt::operandst::iterator o_it=args.begin();
554-
o_it!=args.end(); ++o_it)
617+
for(auto &arg : args)
555618
{
556-
s_it->second.values.replace_const(*o_it);
557-
simplify(*o_it, ns);
619+
s_it->second.partial_evaluate(arg, ns);
558620
}
559621
}
560622
else if(it->is_other())
561623
{
562624
if(it->code.get_statement()==ID_expression)
563-
s_it->second.values.replace_const(it->code);
625+
{
626+
s_it->second.partial_evaluate(it->code, ns);
627+
}
564628
}
565629
}
566630
}

src/analyses/constant_propagator.h

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

139139
valuest values;
140140

141+
bool partial_evaluate(exprt &expr, const namespacet &ns) const;
142+
141143
protected:
142144
void assign_rec(
143145
valuest &values,
@@ -147,6 +149,12 @@ class constant_propagator_domaint:public ai_domain_baset
147149
bool two_way_propagate_rec(
148150
const exprt &expr,
149151
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;
150158
};
151159

152160
class constant_propagator_ait:public ait<constant_propagator_domaint>

src/cbmc/cbmc_parse_options.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Author: Daniel Kroening, [email protected]
2626

2727
#include <ansi-c/c_preprocess.h>
2828

29+
#include <goto-programs/adjust_float_expressions.h>
2930
#include <goto-programs/initialize_goto_model.h>
3031
#include <goto-programs/instrument_preconditions.h>
3132
#include <goto-programs/goto_convert_functions.h>
@@ -49,7 +50,6 @@ Author: Daniel Kroening, [email protected]
4950
#include <goto-programs/string_instrumentation.h>
5051

5152
#include <goto-symex/rewrite_union.h>
52-
#include <goto-symex/adjust_float_expressions.h>
5353

5454
#include <goto-instrument/reachability_slicer.h>
5555
#include <goto-instrument/full_slicer.h>

src/clobber/Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ OBJ += ../ansi-c/ansi-c$(LIBEXT) \
1313
../assembler/assembler$(LIBEXT) \
1414
../solvers/solvers$(LIBEXT) \
1515
../util/util$(LIBEXT) \
16-
../goto-symex/adjust_float_expressions$(OBJEXT) \
1716
../goto-symex/rewrite_union$(OBJEXT) \
1817
../pointer-analysis/dereference$(OBJEXT) \
1918
../goto-instrument/dump_c$(OBJEXT) \

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/goto-diff/Makefile

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ OBJ += ../ansi-c/ansi-c$(LIBEXT) \
2525
../goto-instrument/cover_instrument_mcdc$(OBJEXT) \
2626
../goto-instrument/cover_instrument_other$(OBJEXT) \
2727
../goto-instrument/cover_util$(OBJEXT) \
28-
../goto-symex/adjust_float_expressions$(OBJEXT) \
2928
../goto-symex/rewrite_union$(OBJEXT) \
3029
../analyses/analyses$(LIBEXT) \
3130
../langapi/langapi$(LIBEXT) \

src/goto-diff/goto_diff_parse_options.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ Author: Peter Schrammel
2424

2525
#include <langapi/language.h>
2626

27+
#include <goto-programs/adjust_float_expressions.h>
2728
#include <goto-programs/goto_convert_functions.h>
2829
#include <goto-programs/instrument_preconditions.h>
2930
#include <goto-programs/mm_io.h>
@@ -45,7 +46,6 @@ Author: Peter Schrammel
4546
#include <goto-programs/link_to_library.h>
4647

4748
#include <goto-symex/rewrite_union.h>
48-
#include <goto-symex/adjust_float_expressions.h>
4949

5050
#include <goto-instrument/cover.h>
5151

src/goto-programs/Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
SRC = basic_blocks.cpp \
1+
SRC = adjust_float_expressions.cpp \
2+
basic_blocks.cpp \
23
builtin_functions.cpp \
34
class_hierarchy.cpp \
45
class_identifier.cpp \

src/goto-symex/adjust_float_expressions.cpp renamed to src/goto-programs/adjust_float_expressions.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Author: Daniel Kroening, [email protected]
1818
#include <util/ieee_float.h>
1919
#include <util/arith_tools.h>
2020

21-
#include <goto-programs/goto_model.h>
21+
#include "goto_model.h"
2222

2323
static bool have_to_adjust_float_expressions(
2424
const exprt &expr,

src/goto-symex/adjust_float_expressions.h renamed to src/goto-programs/adjust_float_expressions.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ Author: Daniel Kroening, [email protected]
99
/// \file
1010
/// Symbolic Execution
1111

12-
#ifndef CPROVER_GOTO_SYMEX_ADJUST_FLOAT_EXPRESSIONS_H
13-
#define CPROVER_GOTO_SYMEX_ADJUST_FLOAT_EXPRESSIONS_H
12+
#ifndef CPROVER_GOTO_PROGRAMS_ADJUST_FLOAT_EXPRESSIONS_H
13+
#define CPROVER_GOTO_PROGRAMS_ADJUST_FLOAT_EXPRESSIONS_H
1414

1515
#include <goto-programs/goto_functions.h>
1616

@@ -31,4 +31,4 @@ void adjust_float_expressions(
3131
const namespacet &ns);
3232
void adjust_float_expressions(goto_modelt &goto_model);
3333

34-
#endif // CPROVER_GOTO_SYMEX_ADJUST_FLOAT_EXPRESSIONS_H
34+
#endif // CPROVER_GOTO_PROGRAMS_ADJUST_FLOAT_EXPRESSIONS_H

src/goto-symex/Makefile

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
SRC = adjust_float_expressions.cpp \
2-
auto_objects.cpp \
1+
SRC = auto_objects.cpp \
32
build_goto_trace.cpp \
43
goto_symex.cpp \
54
goto_symex_state.cpp \

0 commit comments

Comments
 (0)