Skip to content

Commit f5b6303

Browse files
author
Matthias Güdemann
committed
Add nondet.{h.cpp}
1 parent eb71a01 commit f5b6303

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

jbmc/src/java_bytecode/nondet.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/// Author: Diffblue Limited. All Rights Reserved.
2+
3+
#include "nondet.h"
4+
5+
#include <java_bytecode/java_types.h>
6+
#include <util/arith_tools.h>
7+
#include <util/c_types.h>
8+
#include <util/fresh_symbol.h>
9+
#include <util/symbol.h>
10+
11+
/// Gets a fresh nondet choice in range (min_value, max_value). GOTO generated
12+
/// resembles:
13+
/// ```
14+
/// int_type name_prefix::nondet_int = NONDET(int_type)
15+
/// ASSUME(name_prefix::nondet_int >= min_value)
16+
/// ASSUME(name_prefix::nondet_int <= max_value)
17+
/// ```
18+
/// \param min_value: Minimum value (inclusive) of returned int.
19+
/// \param max_value: Maximum value (inclusive) of returned int.
20+
/// \param name_prefix: Prefix for the fresh symbol name generated.
21+
/// \param source_location: The location to mark the generated int with.
22+
/// \param symbol_table: The global symbol table.
23+
/// \param instructions [out]: Output instructions are written to
24+
/// 'instructions'. These declare, nondet-initialise and range-constrain (with
25+
/// assume statements) a fresh integer.
26+
/// \return Returns a symbol expression for the resulting integer.
27+
symbol_exprt generate_nondet_int(
28+
const int64_t min_value,
29+
const int64_t max_value,
30+
const std::string &name_prefix,
31+
const typet &int_type,
32+
const source_locationt &source_location,
33+
symbol_table_baset &symbol_table,
34+
code_blockt &instructions)
35+
{
36+
PRECONDITION(min_value < max_value);
37+
38+
// Declare a symbol for the non deterministic integer.
39+
const symbol_exprt &nondet_symbol = get_fresh_aux_symbol(
40+
int_type,
41+
name_prefix + "::nondet_int",
42+
"nondet_int",
43+
source_location,
44+
ID_java,
45+
symbol_table)
46+
.symbol_expr();
47+
instructions.add(code_declt(nondet_symbol));
48+
49+
// Assign the symbol any non deterministic integer value.
50+
// int_type name_prefix::nondet_int = NONDET(int_type)
51+
instructions.add(
52+
code_assignt(nondet_symbol, side_effect_expr_nondett(int_type)));
53+
54+
// Constrain the non deterministic integer with a lower bound of `min_value`.
55+
// ASSUME(name_prefix::nondet_int >= min_value)
56+
instructions.add(
57+
code_assumet(
58+
binary_predicate_exprt(
59+
nondet_symbol, ID_ge, from_integer(min_value, int_type))));
60+
61+
// Constrain the non deterministic integer with an upper bound of `max_value`.
62+
// ASSUME(name_prefix::nondet_int <= max_value)
63+
instructions.add(
64+
code_assumet(
65+
binary_predicate_exprt(
66+
nondet_symbol, ID_le, from_integer(max_value, int_type))));
67+
68+
return nondet_symbol;
69+
}
70+
71+
/// Pick nondeterministically between imperative actions 'switch_cases'.
72+
/// \param name_prefix: Name prefix for fresh symbols
73+
/// \param switch_cases: List of codet objects to execute in each switch case.
74+
/// \param int_type: The type of the int used to non-deterministically choose
75+
/// one of the switch cases.
76+
/// \param source_location: The location to mark the generated int with.
77+
/// \param symbol_table: The global symbol table.
78+
/// \return Returns a nondet-switch choosing between switch_cases. The resulting
79+
/// switch block has no default case.
80+
code_blockt generate_nondet_switch(
81+
const irep_idt &name_prefix,
82+
const alternate_casest &switch_cases,
83+
const typet &int_type,
84+
const source_locationt &source_location,
85+
symbol_table_baset &symbol_table)
86+
{
87+
PRECONDITION(!switch_cases.empty());
88+
89+
if(switch_cases.size() == 1)
90+
return code_blockt({switch_cases[0]});
91+
92+
code_switcht result_switch;
93+
code_blockt result_block;
94+
95+
const symbol_exprt &switch_value = generate_nondet_int(
96+
0,
97+
switch_cases.size() - 1,
98+
id2string(name_prefix),
99+
int_type,
100+
source_location,
101+
symbol_table,
102+
result_block);
103+
104+
result_switch.value() = switch_value;
105+
106+
code_blockt switch_block;
107+
int64_t case_number = 0;
108+
for(const auto &switch_case : switch_cases)
109+
{
110+
code_blockt this_block;
111+
this_block.add(switch_case);
112+
this_block.add(code_breakt());
113+
code_switch_caset this_case;
114+
this_case.case_op() = from_integer(case_number, switch_value.type());
115+
this_case.code() = this_block;
116+
switch_block.move(this_case);
117+
++case_number;
118+
}
119+
120+
result_switch.body() = switch_block;
121+
result_block.move(result_switch);
122+
return result_block;
123+
}

jbmc/src/java_bytecode/nondet.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/// Author: DiffBlue Limited. All Rights Reserved.
2+
3+
#ifndef CPROVER_TEST_GEN_UTIL_NONDET_H
4+
#define CPROVER_TEST_GEN_UTIL_NONDET_H
5+
6+
#include <util/std_code.h>
7+
#include <util/std_expr.h>
8+
#include <util/symbol_table.h>
9+
10+
symbol_exprt generate_nondet_int(
11+
int64_t min_value,
12+
int64_t max_value,
13+
const std::string &name_prefix,
14+
const typet &int_type,
15+
const source_locationt &source_location,
16+
symbol_table_baset &symbol_table,
17+
code_blockt &instructions);
18+
19+
typedef std::vector<codet> alternate_casest;
20+
21+
code_blockt generate_nondet_switch(
22+
const irep_idt &name_prefix,
23+
const alternate_casest &switch_cases,
24+
const typet &int_type,
25+
const source_locationt &source_location,
26+
symbol_table_baset &symbol_table);
27+
28+
#endif // CPROVER_TEST_GEN_UTIL_NONDET_H

0 commit comments

Comments
 (0)