Skip to content

Commit 0ec87c8

Browse files
authored
Merge pull request diffblue#2271 from diffblue/letification
SMT2: Efficient Letification
2 parents 7985716 + 022846a commit 0ec87c8

File tree

6 files changed

+156
-26
lines changed

6 files changed

+156
-26
lines changed

regression/cbmc/Float-smt2-1/main.c

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#include <assert.h>
2+
3+
int main (void) {
4+
float f;
5+
6+
assert(f * f > 28);
7+
8+
return 0;
9+
}
10+
+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE smt-backend
2+
main.c
3+
--smt2
4+
^EXIT=10$
5+
^SIGNAL=0$
6+
--
7+
Tests a floating-point operation encoding for SMT2 without --fpa.
8+
Owing to heavy use of sharing, this requires sharing-aware hashing.

src/solvers/smt2/smt2_conv.cpp

+13-13
Original file line numberDiff line numberDiff line change
@@ -287,24 +287,24 @@ constant_exprt smt2_convt::parse_literal(
287287
src.get_sub()[0].id()=="_" &&
288288
src.get_sub()[1].id()=="+oo") // (_ +oo e s)
289289
{
290-
unsigned e=unsafe_string2unsigned(src.get_sub()[2].id_string());
291-
unsigned s=unsafe_string2unsigned(src.get_sub()[3].id_string());
290+
std::size_t e = unsafe_string2size_t(src.get_sub()[2].id_string());
291+
std::size_t s = unsafe_string2size_t(src.get_sub()[3].id_string());
292292
return ieee_floatt::plus_infinity(ieee_float_spect(s, e)).to_expr();
293293
}
294294
else if(src.get_sub().size()==4 &&
295295
src.get_sub()[0].id()=="_" &&
296296
src.get_sub()[1].id()=="-oo") // (_ -oo e s)
297297
{
298-
unsigned e=unsafe_string2unsigned(src.get_sub()[2].id_string());
299-
unsigned s=unsafe_string2unsigned(src.get_sub()[3].id_string());
298+
std::size_t e = unsafe_string2size_t(src.get_sub()[2].id_string());
299+
std::size_t s = unsafe_string2size_t(src.get_sub()[3].id_string());
300300
return ieee_floatt::minus_infinity(ieee_float_spect(s, e)).to_expr();
301301
}
302302
else if(src.get_sub().size()==4 &&
303303
src.get_sub()[0].id()=="_" &&
304304
src.get_sub()[1].id()=="NaN") // (_ NaN e s)
305305
{
306-
unsigned e=unsafe_string2unsigned(src.get_sub()[2].id_string());
307-
unsigned s=unsafe_string2unsigned(src.get_sub()[3].id_string());
306+
std::size_t e = unsafe_string2size_t(src.get_sub()[2].id_string());
307+
std::size_t s = unsafe_string2size_t(src.get_sub()[3].id_string());
308308
return ieee_floatt::NaN(ieee_float_spect(s, e)).to_expr();
309309
}
310310

@@ -4333,7 +4333,7 @@ void smt2_convt::find_symbols(const exprt &expr)
43334333
<< " -> " << type2id(expr.type()) << "\n"
43344334
<< "(define-fun " << function << " (";
43354335

4336-
for(unsigned i=0; i<expr.operands().size(); i++)
4336+
for(std::size_t i = 0; i < expr.operands().size(); i++)
43374337
{
43384338
if(i!=0)
43394339
out << " ";
@@ -4347,7 +4347,7 @@ void smt2_convt::find_symbols(const exprt &expr)
43474347
out << ' ';
43484348

43494349
exprt tmp1=expr;
4350-
for(unsigned i=0; i<tmp1.operands().size(); i++)
4350+
for(std::size_t i = 0; i < tmp1.operands().size(); i++)
43514351
tmp1.operands()[i]=
43524352
smt2_symbolt("op"+std::to_string(i), tmp1.operands()[i].type());
43534353

@@ -4751,20 +4751,20 @@ exprt smt2_convt::letify_rec(
47514751
exprt &expr,
47524752
std::vector<exprt> &let_order,
47534753
const seen_expressionst &map,
4754-
unsigned i)
4754+
std::size_t i)
47554755
{
47564756
if(i>=let_order.size())
47574757
return substitute_let(expr, map);
47584758

47594759
exprt current=let_order[i];
47604760
assert(map.find(current)!=map.end());
47614761

4762-
if(map.find(current)->second.first<LET_COUNT)
4762+
if(map.find(current)->second.count < LET_COUNT)
47634763
return letify_rec(expr, let_order, map, i+1);
47644764

47654765
let_exprt let;
47664766

4767-
let.symbol() = map.find(current)->second.second;
4767+
let.symbol() = map.find(current)->second.let_symbol;
47684768
let.value() = substitute_let(current, map);
47694769
let.where() = letify_rec(expr, let_order, map, i+1);
47704770

@@ -4781,7 +4781,7 @@ void smt2_convt::collect_bindings(
47814781
if(it!=map.end())
47824782
{
47834783
let_count_idt &count_id=it->second;
4784-
++(count_id.first);
4784+
++(count_id.count);
47854785
return;
47864786
}
47874787

@@ -4797,7 +4797,7 @@ void smt2_convt::collect_bindings(
47974797
symbol_exprt let=
47984798
symbol_exprt("_let_"+std::to_string(++let_id_count), expr.type());
47994799

4800-
map.insert(std::make_pair(expr, std::make_pair(1, let)));
4800+
map.insert(std::make_pair(expr, let_count_idt(1, let)));
48014801

48024802
let_order.push_back(expr);
48034803
}

src/solvers/smt2/smt2_conv.h

+26-8
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ Author: Daniel Kroening, [email protected]
1616
#include <util/std_expr.h>
1717
#include <util/byte_operators.h>
1818

19+
#ifndef HASH_CODE
20+
#include <util/irep_hash_container.h>
21+
#endif
22+
1923
#include <solvers/prop/prop_conv.h>
2024
#include <solvers/flattening/boolbv_width.h>
2125
#include <solvers/flattening/pointer_logic.h>
@@ -170,10 +174,25 @@ class smt2_convt:public prop_convt
170174
void find_symbols_rec(const typet &type, std::set<irep_idt> &recstack);
171175

172176
// letification
173-
typedef std::pair<unsigned, symbol_exprt> let_count_idt;
177+
struct let_count_idt
178+
{
179+
let_count_idt(std::size_t _count, const symbol_exprt &_let_symbol)
180+
: count(_count), let_symbol(_let_symbol)
181+
{
182+
}
183+
184+
std::size_t count;
185+
symbol_exprt let_symbol;
186+
};
187+
188+
#ifdef HASH_CODE
174189
typedef std::unordered_map<exprt, let_count_idt, irep_hash> seen_expressionst;
175-
unsigned let_id_count;
176-
static const unsigned LET_COUNT=2;
190+
#else
191+
typedef irep_hash_mapt<exprt, let_count_idt> seen_expressionst;
192+
#endif
193+
194+
std::size_t let_id_count;
195+
static const std::size_t LET_COUNT = 2;
177196

178197
class let_visitort:public expr_visitort
179198
{
@@ -185,10 +204,9 @@ class smt2_convt:public prop_convt
185204
void operator()(exprt &expr)
186205
{
187206
seen_expressionst::const_iterator it=let_map.find(expr);
188-
if(it!=let_map.end() &&
189-
it->second.first>=LET_COUNT)
207+
if(it != let_map.end() && it->second.count >= LET_COUNT)
190208
{
191-
symbol_exprt symb=it->second.second;
209+
const symbol_exprt &symb = it->second.let_symbol;
192210
expr=symb;
193211
}
194212
}
@@ -199,7 +217,7 @@ class smt2_convt:public prop_convt
199217
exprt &expr,
200218
std::vector<exprt> &let_order,
201219
const seen_expressionst &map,
202-
unsigned i);
220+
std::size_t i);
203221

204222
void collect_bindings(
205223
exprt &expr,
@@ -294,7 +312,7 @@ class smt2_convt:public prop_convt
294312
smt2_identifierst smt2_identifiers;
295313

296314
// Boolean part
297-
unsigned no_boolean_variables;
315+
std::size_t no_boolean_variables;
298316
std::vector<bool> boolean_assignment;
299317
};
300318

src/util/irep_hash_container.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ size_t irep_hash_container_baset::number(const irept &irep)
2121
ptr_hasht::const_iterator it=ptr_hash.find(&irep.read());
2222

2323
if(it!=ptr_hash.end())
24-
return it->second;
24+
return it->second.number;
2525

2626
packedt packed;
2727
pack(irep, packed);
2828
size_t id=numbering.number(packed);
2929

30-
ptr_hash[&irep.read()]=id;
30+
auto &irep_entry = ptr_hash[&irep.read()];
31+
irep_entry.number = id;
32+
irep_entry.irep = irep;
3133

3234
return id;
3335
}

src/util/irep_hash_container.h

+95-3
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ Author: Daniel Kroening, [email protected]
1414

1515
#include <vector>
1616

17+
#include "irep.h"
1718
#include "numbering.h"
1819

19-
class irept;
20-
2120
class irep_hash_container_baset
2221
{
2322
public:
@@ -46,7 +45,13 @@ class irep_hash_container_baset
4645
}
4746
};
4847

49-
typedef std::unordered_map<const void *, std::size_t, pointer_hasht>
48+
struct irep_entryt
49+
{
50+
std::size_t number;
51+
irept irep; // copy to keep addresses stable
52+
};
53+
54+
typedef std::unordered_map<const void *, irep_entryt, pointer_hasht>
5055
ptr_hasht;
5156
ptr_hasht ptr_hash;
5257

@@ -87,4 +92,91 @@ class irep_full_hash_containert:
8792
}
8893
};
8994

95+
template <typename Key, typename T>
96+
class irep_hash_mapt
97+
{
98+
protected:
99+
using mapt = std::map<std::size_t, T>;
100+
101+
public:
102+
using key_type = Key;
103+
using mapped_type = T;
104+
using value_type = std::pair<const Key, T>;
105+
using const_iterator = typename mapt::const_iterator;
106+
using iterator = typename mapt::iterator;
107+
108+
const_iterator find(const Key &key) const
109+
{
110+
return map.find(hash_container.number(key));
111+
}
112+
113+
iterator find(const Key &key)
114+
{
115+
return map.find(hash_container.number(key));
116+
}
117+
118+
const_iterator begin() const
119+
{
120+
return map.begin();
121+
}
122+
123+
iterator begin()
124+
{
125+
return map.begin();
126+
}
127+
128+
const_iterator end() const
129+
{
130+
return map.end();
131+
}
132+
133+
iterator end()
134+
{
135+
return map.end();
136+
}
137+
138+
void clear()
139+
{
140+
hash_container.clear();
141+
map.clear();
142+
}
143+
144+
std::size_t size() const
145+
{
146+
return map.size();
147+
}
148+
149+
bool empty() const
150+
{
151+
return map.empty();
152+
}
153+
154+
T &operator[](const Key &key)
155+
{
156+
const std::size_t i = hash_container.number(key);
157+
return map[i];
158+
}
159+
160+
std::pair<iterator, bool> insert(const value_type &value)
161+
{
162+
const std::size_t i = hash_container.number(value.first);
163+
return map.emplace(i, value.second);
164+
}
165+
166+
void erase(iterator it)
167+
{
168+
map.erase(it);
169+
}
170+
171+
void swap(irep_hash_mapt<Key, T> &other)
172+
{
173+
std::swap(hash_container, other.hash_container);
174+
std::swap(map, other.map);
175+
}
176+
177+
protected:
178+
mutable irep_hash_containert hash_container;
179+
mapt map;
180+
};
181+
90182
#endif // CPROVER_UTIL_IREP_HASH_CONTAINER_H

0 commit comments

Comments
 (0)