Skip to content

Commit 45e1186

Browse files
authored
Merge pull request #4416 from antlechner/antonia/nondet-int-refactor
De-duplicate "generate a nondet int in a given range" logic
2 parents 72e54f3 + 63d9f50 commit 45e1186

File tree

3 files changed

+102
-122
lines changed

3 files changed

+102
-122
lines changed

jbmc/src/java_bytecode/java_object_factory.cpp

Lines changed: 10 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -156,13 +156,6 @@ class java_object_factoryt
156156
size_t depth,
157157
const source_locationt &location);
158158

159-
const symbol_exprt gen_nondet_int_init(
160-
code_blockt &assignments,
161-
const std::string &basename_prefix,
162-
const exprt &min_length_expr,
163-
const exprt &max_length_expr,
164-
const source_locationt &location);
165-
166159
void gen_method_call_if_present(
167160
code_blockt &assignments,
168161
const exprt &instance_expr,
@@ -1089,53 +1082,6 @@ void java_object_factoryt::declare_created_symbols(code_blockt &init_code)
10891082
allocate_objects.declare_created_symbols(init_code);
10901083
}
10911084

1092-
/// Nondeterministically initializes an int i in the range min <= i <= max,
1093-
/// where min is the integer represented by `min_value_expr` and max is the
1094-
/// integer represented by `max_value_expr`.
1095-
/// \param [out] assignments: A code block that the initializing assignments
1096-
/// will be appended to.
1097-
/// \param basename_prefix: Used for naming the newly created symbol.
1098-
/// \param min_value_expr: Represents the minimum value for the integer.
1099-
/// \param max_value_expr: Represents the maximum value for the integer.
1100-
/// \param location: Source location associated with nondet-initialization.
1101-
/// \return A symbol expression for the resulting integer.
1102-
const symbol_exprt java_object_factoryt::gen_nondet_int_init(
1103-
code_blockt &assignments,
1104-
const std::string &basename_prefix,
1105-
const exprt &min_value_expr,
1106-
const exprt &max_value_expr,
1107-
const source_locationt &location)
1108-
{
1109-
PRECONDITION(min_value_expr.type() == max_value_expr.type());
1110-
1111-
const symbol_exprt &int_symbol_expr =
1112-
allocate_objects.allocate_automatic_local_object(
1113-
min_value_expr.type(), basename_prefix);
1114-
1115-
// Nondet-initialize it
1116-
gen_nondet_init(
1117-
assignments,
1118-
int_symbol_expr,
1119-
false, // is_sub
1120-
irep_idt(),
1121-
false, // skip_classid
1122-
lifetimet::AUTOMATIC_LOCAL, // immaterial, type is primitive
1123-
{}, // no override type
1124-
0, // depth is immaterial, always non-null
1125-
update_in_placet::NO_UPDATE_IN_PLACE,
1126-
location);
1127-
1128-
// Insert assumptions to bound its value
1129-
const auto min_assume_expr =
1130-
binary_relation_exprt(int_symbol_expr, ID_ge, min_value_expr);
1131-
const auto max_assume_expr =
1132-
binary_relation_exprt(int_symbol_expr, ID_le, max_value_expr);
1133-
assignments.add(code_assumet(min_assume_expr));
1134-
assignments.add(code_assumet(max_assume_expr));
1135-
1136-
return int_symbol_expr;
1137-
}
1138-
11391085
/// Allocates a fresh array and emits an assignment writing to \p lhs the
11401086
/// address of the new array. Single-use at the moment, but useful to keep as a
11411087
/// separate function for downstream branches.
@@ -1158,12 +1104,13 @@ void java_object_factoryt::allocate_nondet_length_array(
11581104
const typet &element_type,
11591105
const source_locationt &location)
11601106
{
1161-
const auto &length_sym_expr = gen_nondet_int_init(
1162-
assignments,
1163-
"nondet_array_length",
1107+
const auto &length_sym_expr = generate_nondet_int(
11641108
from_integer(0, java_int_type()),
11651109
max_length_expr,
1166-
location);
1110+
"nondet_array_length",
1111+
location,
1112+
allocate_objects,
1113+
assignments);
11671114

11681115
side_effect_exprt java_new_array(ID_java_new_array, lhs.type(), loc);
11691116
java_new_array.copy_to_operands(length_sym_expr);
@@ -1462,12 +1409,13 @@ bool java_object_factoryt::gen_nondet_enum_init(
14621409
const member_exprt enum_array_expr =
14631410
member_exprt(deref_expr, "data", comps[2].type());
14641411

1465-
const symbol_exprt &index_expr = gen_nondet_int_init(
1466-
assignments,
1467-
"enum_index_init",
1412+
const symbol_exprt &index_expr = generate_nondet_int(
14681413
from_integer(0, java_int_type()),
14691414
minus_exprt(length_expr, from_integer(1, java_int_type())),
1470-
location);
1415+
"enum_index_init",
1416+
location,
1417+
allocate_objects,
1418+
assignments);
14711419

14721420
// Generate statement using pointer arithmetic to access array element:
14731421
// expr = (expr.type())*(enum_array_expr + index_expr);

src/util/nondet.cpp

Lines changed: 39 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,48 +8,26 @@ Author: Diffblue Ltd.
88

99
#include "nondet.h"
1010

11-
#include <util/arith_tools.h>
12-
#include <util/c_types.h>
13-
#include <util/fresh_symbol.h>
14-
#include <util/symbol.h>
15-
16-
/// Gets a fresh nondet choice in range (min_value, max_value). GOTO generated
17-
/// resembles:
18-
/// ```
19-
/// int_type name_prefix::nondet_int = NONDET(int_type)
20-
/// ASSUME(name_prefix::nondet_int >= min_value)
21-
/// ASSUME(name_prefix::nondet_int <= max_value)
22-
/// ```
23-
/// \param min_value: Minimum value (inclusive) of returned int.
24-
/// \param max_value: Maximum value (inclusive) of returned int.
25-
/// \param name_prefix: Prefix for the fresh symbol name generated (should be
26-
/// function id)
27-
/// \param int_type: The type of the int used to non-deterministically choose
28-
/// one of the switch cases.
29-
/// \param mode: Mode (language) of the symbol to be generated.
30-
/// \param source_location: The location to mark the generated int with.
31-
/// \param symbol_table: The global symbol table.
32-
/// \param [out] instructions: Output instructions are written to
33-
/// 'instructions'. These declare, nondet-initialise and range-constrain (with
34-
/// assume statements) a fresh integer.
35-
/// \return Returns a symbol expression for the resulting integer.
11+
#include "allocate_objects.h"
12+
#include "arith_tools.h"
13+
#include "c_types.h"
14+
#include "fresh_symbol.h"
15+
#include "symbol.h"
16+
3617
symbol_exprt generate_nondet_int(
37-
const mp_integer &min_value,
38-
const mp_integer &max_value,
39-
const std::string &name_prefix,
40-
const typet &int_type,
41-
const irep_idt &mode,
18+
const exprt &min_value_expr,
19+
const exprt &max_value_expr,
20+
const std::string &basename_prefix,
4221
const source_locationt &source_location,
43-
symbol_table_baset &symbol_table,
22+
allocate_objectst &allocate_objects,
4423
code_blockt &instructions)
4524
{
46-
PRECONDITION(min_value < max_value);
25+
PRECONDITION(min_value_expr.type() == max_value_expr.type());
26+
const typet &int_type = min_value_expr.type();
4727

4828
// Declare a symbol for the non deterministic integer.
4929
const symbol_exprt &nondet_symbol =
50-
get_fresh_aux_symbol(
51-
int_type, name_prefix, "nondet_int", source_location, mode, symbol_table)
52-
.symbol_expr();
30+
allocate_objects.allocate_automatic_local_object(int_type, basename_prefix);
5331
instructions.add(code_declt(nondet_symbol));
5432

5533
// Assign the symbol any non deterministic integer value.
@@ -60,30 +38,35 @@ symbol_exprt generate_nondet_int(
6038
// Constrain the non deterministic integer with a lower bound of `min_value`.
6139
// ASSUME(name_prefix::nondet_int >= min_value)
6240
instructions.add(
63-
code_assumet(
64-
binary_predicate_exprt(
65-
nondet_symbol, ID_ge, from_integer(min_value, int_type))));
41+
code_assumet(binary_predicate_exprt(nondet_symbol, ID_ge, min_value_expr)));
6642

6743
// Constrain the non deterministic integer with an upper bound of `max_value`.
6844
// ASSUME(name_prefix::nondet_int <= max_value)
6945
instructions.add(
70-
code_assumet(
71-
binary_predicate_exprt(
72-
nondet_symbol, ID_le, from_integer(max_value, int_type))));
46+
code_assumet(binary_predicate_exprt(nondet_symbol, ID_le, max_value_expr)));
7347

7448
return nondet_symbol;
7549
}
7650

77-
/// Pick nondeterministically between imperative actions 'switch_cases'.
78-
/// \param name_prefix: Name prefix for fresh symbols (should be function id)
79-
/// \param switch_cases: List of codet objects to execute in each switch case.
80-
/// \param int_type: The type of the int used to non-deterministically choose
81-
/// one of the switch cases.
82-
/// \param mode: Mode (language) of the symbol to be generated.
83-
/// \param source_location: The location to mark the generated int with.
84-
/// \param symbol_table: The global symbol table.
85-
/// \return Returns a nondet-switch choosing between switch_cases. The resulting
86-
/// switch block has no default case.
51+
symbol_exprt generate_nondet_int(
52+
const mp_integer &min_value,
53+
const mp_integer &max_value,
54+
const std::string &basename_prefix,
55+
const typet &int_type,
56+
const source_locationt &source_location,
57+
allocate_objectst &allocate_objects,
58+
code_blockt &instructions)
59+
{
60+
PRECONDITION(min_value <= max_value);
61+
return generate_nondet_int(
62+
from_integer(min_value, int_type),
63+
from_integer(max_value, int_type),
64+
basename_prefix,
65+
source_location,
66+
allocate_objects,
67+
instructions);
68+
}
69+
8770
code_blockt generate_nondet_switch(
8871
const irep_idt &name_prefix,
8972
const alternate_casest &switch_cases,
@@ -99,14 +82,16 @@ code_blockt generate_nondet_switch(
9982

10083
code_blockt result_block;
10184

85+
allocate_objectst allocate_objects{
86+
mode, source_location, name_prefix, symbol_table};
87+
10288
const symbol_exprt &switch_value = generate_nondet_int(
10389
0,
10490
switch_cases.size() - 1,
105-
id2string(name_prefix),
91+
"nondet_int",
10692
int_type,
107-
mode,
10893
source_location,
109-
symbol_table,
94+
allocate_objects,
11095
result_block);
11196

11297
code_blockt switch_block;

src/util/nondet.h

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,69 @@ Author: Diffblue Ltd.
99
#ifndef CPROVER_JAVA_BYTECODE_NONDET_H
1010
#define CPROVER_JAVA_BYTECODE_NONDET_H
1111

12-
#include <util/std_code.h>
13-
#include <util/std_expr.h>
14-
#include <util/symbol_table.h>
12+
#include "std_code.h"
13+
#include "std_expr.h"
1514

15+
class allocate_objectst;
16+
class symbol_table_baset;
17+
18+
/// Same as \ref generate_nondet_int(
19+
/// const mp_integer &min_value,
20+
/// const mp_integer &max_value,
21+
/// const std::string &name_prefix,
22+
/// const typet &int_type,
23+
/// const irep_idt &mode,
24+
/// const source_locationt &source_location,
25+
/// symbol_table_baset &symbol_table,
26+
/// code_blockt &instructions)
27+
/// except the minimum and maximum values are represented as exprts.
28+
symbol_exprt generate_nondet_int(
29+
const exprt &min_value_expr,
30+
const exprt &max_value_expr,
31+
const std::string &basename_prefix,
32+
const source_locationt &source_location,
33+
allocate_objectst &allocate_objects,
34+
code_blockt &instructions);
35+
36+
/// Gets a fresh nondet choice in range (min_value, max_value). GOTO generated
37+
/// resembles:
38+
/// ```
39+
/// int_type name_prefix::nondet_int = NONDET(int_type)
40+
/// ASSUME(name_prefix::nondet_int >= min_value)
41+
/// ASSUME(name_prefix::nondet_int <= max_value)
42+
/// ```
43+
/// \param min_value: Minimum value (inclusive) of returned int.
44+
/// \param max_value: Maximum value (inclusive) of returned int.
45+
/// \param basename_prefix: Basename prefix for the fresh symbol name generated.
46+
/// \param int_type: The type of the int used to non-deterministically choose
47+
/// one of the switch cases.
48+
/// \param allocate_objects: Handles allocation of new objects.
49+
/// \param source_location: The location to mark the generated int with.
50+
/// \param [out] instructions: Output instructions are written to
51+
/// 'instructions'. These declare, nondet-initialise and range-constrain (with
52+
/// assume statements) a fresh integer.
53+
/// \return Returns a symbol expression for the resulting integer.
1654
symbol_exprt generate_nondet_int(
1755
const mp_integer &min_value,
1856
const mp_integer &max_value,
19-
const std::string &name_prefix,
57+
const std::string &basename_prefix,
2058
const typet &int_type,
21-
const irep_idt &mode,
2259
const source_locationt &source_location,
23-
symbol_table_baset &symbol_table,
60+
allocate_objectst &allocate_objects,
2461
code_blockt &instructions);
2562

2663
typedef std::vector<codet> alternate_casest;
2764

65+
/// Pick nondeterministically between imperative actions 'switch_cases'.
66+
/// \param name_prefix: Name prefix for fresh symbols (should be function id)
67+
/// \param switch_cases: List of codet objects to execute in each switch case.
68+
/// \param int_type: The type of the int used to non-deterministically choose
69+
/// one of the switch cases.
70+
/// \param mode: Mode (language) of the symbol to be generated.
71+
/// \param source_location: The location to mark the generated int with.
72+
/// \param symbol_table: The global symbol table.
73+
/// \return Returns a nondet-switch choosing between switch_cases. The resulting
74+
/// switch block has no default case.
2875
code_blockt generate_nondet_switch(
2976
const irep_idt &name_prefix,
3077
const alternate_casest &switch_cases,

0 commit comments

Comments
 (0)