Skip to content

Commit 28fb701

Browse files
Merge pull request #689 from romainbrenguier/interpreter-sparse-memory
Interpreter sparse memory
2 parents fd96acc + 1b97f3d commit 28fb701

File tree

4 files changed

+297
-69
lines changed

4 files changed

+297
-69
lines changed

src/goto-programs/interpreter.cpp

Lines changed: 84 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -597,16 +597,25 @@ exprt interpretert::get_value(
597597
exprt result=array_exprt(to_array_type(real_type));
598598
const exprt &size_expr=static_cast<const exprt &>(type.find(ID_size));
599599
size_t subtype_size=get_size(type.subtype());
600-
mp_integer mp_count;
601-
to_integer(size_expr, mp_count);
602-
unsigned count=integer2unsigned(mp_count);
600+
std::size_t count;
601+
if(size_expr.id()!=ID_constant)
602+
{
603+
count=base_address_to_actual_size(offset)/subtype_size;
604+
}
605+
else
606+
{
607+
mp_integer mp_count;
608+
to_integer(size_expr, mp_count);
609+
count=integer2size_t(mp_count);
610+
}
603611

604612
// Retrieve the value for each member in the array
605613
result.reserve_operands(count);
606614
for(unsigned i=0; i<count; i++)
607615
{
608-
const exprt operand=get_value(type.subtype(),
609-
offset+i*subtype_size);
616+
const exprt operand=get_value(
617+
type.subtype(),
618+
offset+i*subtype_size);
610619
result.copy_to_operands(operand);
611620
}
612621
return result;
@@ -663,9 +672,17 @@ exprt interpretert::get_value(
663672

664673
// Get size of array
665674
size_t subtype_size=get_size(type.subtype());
666-
mp_integer mp_count;
667-
to_integer(size_expr, mp_count);
668-
unsigned count=integer2unsigned(mp_count);
675+
unsigned count;
676+
if(unbounded_size(type))
677+
{
678+
count=base_address_to_actual_size(offset)/subtype_size;
679+
}
680+
else
681+
{
682+
mp_integer mp_count;
683+
to_integer(size_expr, mp_count);
684+
count=integer2unsigned(mp_count);
685+
}
669686

670687
// Retrieve the value for each member in the array
671688
result.reserve_operands(count);
@@ -712,22 +729,24 @@ exprt interpretert::get_value(
712729
if(rhs[offset]<memory.size())
713730
{
714731
// We want the symbol pointed to
715-
memory_cellt &cell=memory[integer2unsigned(rhs[offset])];
716-
const typet type=get_type(cell.identifier);
732+
std::size_t address=integer2size_t(rhs[offset]);
733+
irep_idt identifier=address_to_identifier(address);
734+
size_t offset=address_to_offset(address);
735+
const typet type=get_type(identifier);
717736
exprt symbol_expr(ID_symbol, type);
718-
symbol_expr.set(ID_identifier, cell.identifier);
737+
symbol_expr.set(ID_identifier, identifier);
719738

720-
if(cell.offset==0)
739+
if(offset==0)
721740
return address_of_exprt(symbol_expr);
722741
if(ns.follow(type).id()==ID_struct)
723742
{
724-
irep_idt member_id=get_component_id(cell.identifier, cell.offset);
743+
irep_idt member_id=get_component_id(identifier, offset);
725744
member_exprt member_expr(symbol_expr, member_id);
726745
return address_of_exprt(member_expr);
727746
}
728747
index_exprt index_expr(
729748
symbol_expr,
730-
from_integer(cell.offset, integer_typet()));
749+
from_integer(offset, integer_typet()));
731750
return index_expr;
732751
}
733752

@@ -828,12 +847,13 @@ void interpretert::assign(
828847
{
829848
if((address+i)<memory.size())
830849
{
831-
memory_cellt &cell=memory[integer2unsigned(address+i)];
850+
std::size_t address_val=integer2size_t(address+i);
851+
memory_cellt &cell=memory[address_val];
832852
if(show)
833853
{
834854
status() << total_steps << " ** assigning "
835-
<< cell.identifier << "["
836-
<< cell.offset << "]:=" << rhs[i]
855+
<< address_to_identifier(address_val) << "["
856+
<< address_to_offset(address_val) << "]:=" << rhs[i]
837857
<< "\n" << eom;
838858
}
839859
cell.value=rhs[i];
@@ -913,8 +933,11 @@ void interpretert::execute_function_call()
913933
// Retrieve the empty last trace step struct we pushed for this step
914934
// of the interpreter run to fill it with the corresponding data
915935
goto_trace_stept &trace_step=steps.get_last_step();
916-
const memory_cellt &cell=memory[integer2size_t(a)];
917-
const irep_idt &identifier=cell.identifier;
936+
std::size_t address=integer2size_t(a);
937+
#if 0
938+
const memory_cellt &cell=memory[address];
939+
#endif
940+
const irep_idt &identifier=address_to_identifier(address);
918941
trace_step.identifier=identifier;
919942

920943
const goto_functionst::function_mapt::const_iterator f_it=
@@ -1020,9 +1043,7 @@ void interpretert::build_memory_map()
10201043
{
10211044
// put in a dummy for NULL
10221045
memory.resize(1);
1023-
memory[0].offset=0;
1024-
memory[0].identifier="NULL-OBJECT";
1025-
memory[0].initialized=0;
1046+
inverse_memory_map[0]="NULL-OBJECT";
10261047

10271048
num_dynamic_objects=0;
10281049
dynamic_types.clear();
@@ -1062,18 +1083,10 @@ void interpretert::build_memory_map(const symbolt &symbol)
10621083

10631084
if(size!=0)
10641085
{
1065-
unsigned address=memory.size();
1086+
std::size_t address=memory.size();
10661087
memory.resize(address+size);
10671088
memory_map[symbol.name]=address;
1068-
1069-
for(size_t i=0; i<size; i++)
1070-
{
1071-
memory_cellt &cell=memory[address+i];
1072-
cell.identifier=symbol.name;
1073-
cell.offset=i;
1074-
cell.value=0;
1075-
cell.initialized=0;
1076-
}
1089+
inverse_memory_map[address]=symbol.name;
10771090
}
10781091
}
10791092

@@ -1119,7 +1132,7 @@ Function: interpretert::build_memory_map
11191132
11201133
Inputs:
11211134
1122-
Outputs: Updtaes the memory map to include variable id if it does
1135+
Outputs: Updates the memory map to include variable id if it does
11231136
not exist
11241137
11251138
Purpose: Populates dynamic entries of the memory map
@@ -1136,12 +1149,10 @@ mp_integer interpretert::build_memory_map(
11361149

11371150
if(it!=dynamic_types.end())
11381151
{
1139-
unsigned offset=1;
1140-
unsigned address=memory_map[id];
1141-
while(memory[address+offset].offset>0) offset++;
1142-
1152+
std::size_t address=memory_map[id];
1153+
std::size_t current_size=base_address_to_alloc_size(address);
11431154
// current size <= size already recorded
1144-
if(size<=offset)
1155+
if(size<=current_size)
11451156
return memory_map[id];
11461157
}
11471158

@@ -1151,36 +1162,54 @@ mp_integer interpretert::build_memory_map(
11511162
if(size==0)
11521163
size=1; // This is a hack to create existence
11531164

1154-
unsigned address=memory.size();
1165+
std::size_t address=memory.size();
11551166
memory.resize(address+size);
11561167
memory_map[id]=address;
1168+
inverse_memory_map[address]=id;
11571169
dynamic_types.insert(std::pair<const irep_idt, typet>(id, alloc_type));
11581170

1159-
for(size_t i=0; i<size; i++)
1171+
return address;
1172+
}
1173+
1174+
bool interpretert::unbounded_size(const typet &type)
1175+
{
1176+
if(type.id()==ID_array)
11601177
{
1161-
memory_cellt &cell=memory[address+i];
1162-
cell.identifier=id;
1163-
cell.offset=i;
1164-
cell.value=0;
1165-
cell.initialized=0;
1178+
const exprt &size=to_array_type(type).size();
1179+
if(size.id()==ID_infinity)
1180+
return true;
1181+
return unbounded_size(type.subtype());
11661182
}
1167-
return address;
1183+
else if(type.id()==ID_struct)
1184+
{
1185+
const auto &st=to_struct_type(type);
1186+
if(st.components().empty())
1187+
return false;
1188+
return unbounded_size(st.components().back().type());
1189+
}
1190+
return false;
11681191
}
11691192

11701193
/*******************************************************************\
11711194
11721195
Function: interpretert::get_size
11731196
11741197
Inputs:
1198+
type - a structured type
11751199
1176-
Outputs:
1200+
Outputs: Size of the given type
11771201
1178-
Purpose: Retrieves the actual size of the provided structured type
1202+
Purpose: Retrieves the actual size of the provided structured type.
1203+
Unbounded objects get allocated 2^32 address space each
1204+
(of a 2^64 sized space).
11791205
11801206
\*******************************************************************/
11811207

11821208
size_t interpretert::get_size(const typet &type)
11831209
{
1210+
if(unbounded_size(type))
1211+
return 2ULL << 32ULL;
1212+
11841213
if(type.id()==ID_struct)
11851214
{
11861215
const struct_typet::componentst &components=
@@ -1268,7 +1297,7 @@ exprt interpretert::get_value(const irep_idt &id)
12681297
symbol_exprt symbol_expr(id, get_type);
12691298
mp_integer whole_lhs_object_address=evaluate_address(symbol_expr);
12701299

1271-
return get_value(get_type, integer2unsigned(whole_lhs_object_address));
1300+
return get_value(get_type, integer2size_t(whole_lhs_object_address));
12721301
}
12731302

12741303
/*******************************************************************\
@@ -1310,10 +1339,13 @@ Function: interpretert::print_memory
13101339

13111340
void interpretert::print_memory(bool input_flags)
13121341
{
1313-
for(size_t i=0; i<memory.size(); i++)
1342+
for(const auto &cell_address : memory)
13141343
{
1315-
memory_cellt &cell=memory[i];
1316-
debug() << cell.identifier << "[" << cell.offset << "]"
1344+
std::size_t i=cell_address.first;
1345+
const memory_cellt &cell=cell_address.second;
1346+
const auto identifier=address_to_identifier(i);
1347+
const auto offset=address_to_offset(i);
1348+
debug() << identifier << "[" << offset << "]"
13171349
<< "=" << cell.value << eom;
13181350
if(input_flags)
13191351
debug() << "(" << static_cast<int>(cell.initialized) << ")"

src/goto-programs/interpreter_class.h

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Author: Daniel Kroening, [email protected]
1212
#include <stack>
1313

1414
#include <util/arith_tools.h>
15+
#include <util/sparse_vector.h>
1516

1617
#include "goto_functions.h"
1718
#include "goto_trace.h"
@@ -68,6 +69,9 @@ class interpretert:public messaget
6869
// List of dynamically allocated symbols that are not in the symbol table
6970
typedef std::map<irep_idt, typet> dynamic_typest;
7071

72+
typedef std::map<irep_idt, function_assignmentst> output_valuest;
73+
output_valuest output_values;
74+
7175
// An assignment list annotated with the calling context.
7276
struct function_assignments_contextt
7377
{
@@ -103,27 +107,78 @@ class interpretert:public messaget
103107

104108
const goto_functionst &goto_functions;
105109

106-
typedef std::unordered_map<irep_idt, unsigned, irep_id_hash> memory_mapt;
110+
typedef std::unordered_map<irep_idt, std::size_t, irep_id_hash> memory_mapt;
111+
typedef std::map<std::size_t, irep_idt> inverse_memory_mapt;
107112
memory_mapt memory_map;
113+
inverse_memory_mapt inverse_memory_map;
114+
115+
const inverse_memory_mapt::value_type &address_to_object_record(
116+
std::size_t address) const
117+
{
118+
auto lower_bound=inverse_memory_map.lower_bound(address);
119+
if(lower_bound->first!=address)
120+
{
121+
assert(lower_bound!=inverse_memory_map.begin());
122+
--lower_bound;
123+
}
124+
return *lower_bound;
125+
}
126+
127+
irep_idt address_to_identifier(std::size_t address) const
128+
{
129+
return address_to_object_record(address).second;
130+
}
131+
132+
std::size_t address_to_offset(std::size_t address) const
133+
{
134+
return address-(address_to_object_record(address).first);
135+
}
136+
137+
std::size_t base_address_to_alloc_size(std::size_t address) const
138+
{
139+
assert(address_to_offset(address)==0);
140+
auto upper_bound=inverse_memory_map.upper_bound(address);
141+
std::size_t next_alloc_address=
142+
upper_bound==inverse_memory_map.end() ?
143+
memory.size() :
144+
upper_bound->first;
145+
return next_alloc_address-address;
146+
}
147+
148+
std::size_t base_address_to_actual_size(std::size_t address) const
149+
{
150+
auto memory_iter=memory.find(address);
151+
if(memory_iter==memory.end())
152+
return 0;
153+
std::size_t ret=0;
154+
std::size_t alloc_size=base_address_to_alloc_size(address);
155+
while(memory_iter!=memory.end() && ret<alloc_size)
156+
{
157+
++ret;
158+
++memory_iter;
159+
}
160+
return ret;
161+
}
108162

109163
class memory_cellt
110164
{
111165
public:
112-
irep_idt identifier;
113-
unsigned offset;
166+
memory_cellt() :
167+
value(0),
168+
initialized(0)
169+
{}
114170
mp_integer value;
115171
// Initialized is annotated even during reads
116172
// Set to 1 when written-before-read, -1 when read-before-written
117173
mutable char initialized;
118174
};
119175

120-
typedef std::vector<memory_cellt> memoryt;
176+
typedef sparse_vectort<memory_cellt> memoryt;
121177
typedef std::map<std::string, const irep_idt &> parameter_sett;
122178
// mapping <structure, field> -> value
123179
typedef std::pair<const irep_idt, const irep_idt> struct_member_idt;
124180
typedef std::map<struct_member_idt, const exprt> struct_valuest;
125181

126-
127182
// The memory is being annotated/reshaped even during reads
128183
// (ie to find a read-before-write location) thus memory
129184
// properties need to be mutable to avoid making all calls nonconst
@@ -135,6 +190,7 @@ class interpretert:public messaget
135190
void build_memory_map(const symbolt &symbol);
136191
mp_integer build_memory_map(const irep_idt &id, const typet &type);
137192
typet concretize_type(const typet &type);
193+
bool unbounded_size(const typet &);
138194
size_t get_size(const typet &type);
139195

140196
irep_idt get_component_id(const irep_idt &object, unsigned offset);
@@ -169,6 +225,10 @@ class interpretert:public messaget
169225
mp_integer address,
170226
mp_vectort &dest) const;
171227

228+
void read_unbounded(
229+
mp_integer address,
230+
mp_vectort &dest) const;
231+
172232
virtual void command();
173233

174234
class stack_framet

0 commit comments

Comments
 (0)