Skip to content

Commit 68507c3

Browse files
Enable sharing of irept's as long as no references are held to sub-parts
A PR by @reuk some time ago prevented sharing when references are held to sub-parts but didn't re-enable sharing in situations where it is actually safe to do so. This PR amends that. This should improve performance, particularly in memory usage.
1 parent abe290b commit 68507c3

File tree

5 files changed

+78
-88
lines changed

5 files changed

+78
-88
lines changed

Diff for: src/util/expr.cpp

+18-42
Original file line numberDiff line numberDiff line change
@@ -25,64 +25,40 @@ Author: Daniel Kroening, [email protected]
2525

2626
void exprt::move_to_operands(exprt &expr)
2727
{
28-
operandst &op=operands();
29-
op.push_back(static_cast<const exprt &>(get_nil_irep()));
30-
op.back().swap(expr);
28+
move_to_sub(expr);
3129
}
3230

3331
void exprt::move_to_operands(exprt &e1, exprt &e2)
3432
{
35-
operandst &op=operands();
36-
#ifndef USE_LIST
37-
op.reserve(op.size()+2);
38-
#endif
39-
op.push_back(static_cast<const exprt &>(get_nil_irep()));
40-
op.back().swap(e1);
41-
op.push_back(static_cast<const exprt &>(get_nil_irep()));
42-
op.back().swap(e2);
33+
reserve_operands(get_operands_size() + 2);
34+
move_to_sub(e1);
35+
move_to_sub(e2);
4336
}
4437

4538
void exprt::move_to_operands(exprt &e1, exprt &e2, exprt &e3)
4639
{
47-
operandst &op=operands();
48-
#ifndef USE_LIST
49-
op.reserve(op.size()+3);
50-
#endif
51-
op.push_back(static_cast<const exprt &>(get_nil_irep()));
52-
op.back().swap(e1);
53-
op.push_back(static_cast<const exprt &>(get_nil_irep()));
54-
op.back().swap(e2);
55-
op.push_back(static_cast<const exprt &>(get_nil_irep()));
56-
op.back().swap(e3);
40+
reserve_operands(get_operands_size() + 3);
41+
move_to_sub(e1);
42+
move_to_sub(e2);
43+
move_to_sub(e3);
5744
}
5845

59-
void exprt::copy_to_operands(const exprt &expr)
46+
void exprt::copy_to_operands(exprt expr)
6047
{
61-
operands().push_back(expr);
48+
// Move the copy created by passing the argument by value to the operands
49+
move_to_operands(expr);
6250
}
6351

64-
void exprt::copy_to_operands(const exprt &e1, const exprt &e2)
52+
void exprt::copy_to_operands(exprt e1, exprt e2)
6553
{
66-
operandst &op=operands();
67-
#ifndef USE_LIST
68-
op.reserve(op.size()+2);
69-
#endif
70-
op.push_back(e1);
71-
op.push_back(e2);
54+
// Move the copies created by passing the arguments by value to the operands
55+
move_to_operands(e1, e2);
7256
}
7357

74-
void exprt::copy_to_operands(
75-
const exprt &e1,
76-
const exprt &e2,
77-
const exprt &e3)
58+
void exprt::copy_to_operands(exprt e1, exprt e2, exprt e3)
7859
{
79-
operandst &op=operands();
80-
#ifndef USE_LIST
81-
op.reserve(op.size()+3);
82-
#endif
83-
op.push_back(e1);
84-
op.push_back(e2);
85-
op.push_back(e3);
60+
// Move the copies created by passing the arguments by value to the operands
61+
move_to_operands(e1, e2, e3);
8662
}
8763

8864
void exprt::make_typecast(const typet &_type)
@@ -112,7 +88,7 @@ void exprt::make_not()
11288

11389
if(id()==ID_not && operands().size()==1)
11490
{
115-
new_expr.swap(operands().front());
91+
new_expr.swap(op0());
11692
}
11793
else
11894
{

Diff for: src/util/expr.h

+10-4
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,23 @@ class exprt:public irept
9494
const exprt &op3() const
9595
{ return operands()[3]; }
9696

97+
operandst::size_type get_operands_size() const
98+
{
99+
return get_sub_size();
100+
}
97101
void reserve_operands(operandst::size_type n)
98-
{ operands().reserve(n) ; }
102+
{
103+
reserve_sub(n);
104+
}
99105

100106
// destroys expr, e1, e2, e3
101107
void move_to_operands(exprt &expr);
102108
void move_to_operands(exprt &e1, exprt &e2);
103109
void move_to_operands(exprt &e1, exprt &e2, exprt &e3);
104110
// does not destroy expr, e1, e2, e3
105-
void copy_to_operands(const exprt &expr);
106-
void copy_to_operands(const exprt &e1, const exprt &e2);
107-
void copy_to_operands(const exprt &e1, const exprt &e2, const exprt &e3);
111+
void copy_to_operands(exprt expr);
112+
void copy_to_operands(exprt e1, exprt e2);
113+
void copy_to_operands(exprt e1, exprt e2, exprt e3);
108114

109115
// the following are deprecated -- use constructors instead
110116
void make_typecast(const typet &_type);

Diff for: src/util/irep.cpp

+14-38
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,14 @@ const irept &get_nil_irep()
5757

5858
void irept::move_to_named_sub(const irep_namet &name, irept &irep)
5959
{
60-
add(name).swap(irep);
60+
add(name, std::move(irep));
6161
irep.clear();
6262
}
6363

6464
void irept::move_to_sub(irept &irep)
6565
{
66-
get_sub().push_back(get_nil_irep());
67-
get_sub().back().swap(irep);
66+
write(true).sub.push_back(std::move(irep));
67+
irep.clear();
6868
}
6969

7070
const irep_idt &irept::get(const irep_namet &name) const
@@ -121,13 +121,13 @@ long long irept::get_long_long(const irep_namet &name) const
121121

122122
void irept::set(const irep_namet &name, const long long value)
123123
{
124-
add(name).id(std::to_string(value));
124+
set(name, std::to_string(value));
125125
}
126126

127127
void irept::remove(const irep_namet &name)
128128
{
129-
named_subt &s=
130-
is_comment(name)?get_comments():get_named_sub();
129+
named_subt &s =
130+
is_comment(name) ? write(true).comments : write(true).named_sub;
131131

132132
#ifdef SUB_IS_LIST
133133
named_subt::iterator it=named_subt_lower_bound(s, name);
@@ -160,47 +160,23 @@ const irept &irept::find(const irep_namet &name) const
160160
return it->second;
161161
}
162162

163-
irept &irept::add(const irep_namet &name)
163+
irept &irept::add(const irep_namet &name, bool mark_sharable)
164164
{
165-
named_subt &s=
166-
is_comment(name)?get_comments():get_named_sub();
165+
named_subt &s =
166+
is_comment(name)
167+
? write(mark_sharable).comments : write(mark_sharable).named_sub;
167168

168169
#ifdef SUB_IS_LIST
169-
named_subt::iterator it=named_subt_lower_bound(s, name);
170-
171-
if(it==s.end() ||
172-
it->first!=name)
173-
it=s.insert(it, std::make_pair(name, irept()));
174170

175-
return it->second;
176-
#else
177-
return s[name];
178-
#endif
179-
}
180-
181-
irept &irept::add(const irep_namet &name, const irept &irep)
182-
{
183-
named_subt &s=
184-
is_comment(name)?get_comments():get_named_sub();
185-
186-
#ifdef SUB_IS_LIST
187171
named_subt::iterator it=named_subt_lower_bound(s, name);
188-
189-
if(it==s.end() ||
190-
it->first!=name)
191-
it=s.insert(it, std::make_pair(name, irep));
192-
else
193-
it->second=irep;
194-
172+
if(it == s.end() || it->first != name)
173+
it = s.emplace(it, name, irept());
195174
return it->second;
175+
196176
#else
197-
std::pair<named_subt::iterator, bool> entry=
198-
s.insert(std::make_pair(name, irep));
199177

200-
if(!entry.second)
201-
entry.first->second=irep;
178+
return s[name];
202179

203-
return entry.first->second;
204180
#endif
205181
}
206182

Diff for: src/util/irep.h

+35-3
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,14 @@ class irept
125125
}
126126

127127
const irept &find(const irep_namet &name) const;
128-
irept &add(const irep_namet &name);
129-
irept &add(const irep_namet &name, const irept &irep);
128+
irept &add(const irep_namet &name)
129+
{
130+
return add(name, false);
131+
}
132+
void add(const irep_namet &name, irept irep)
133+
{
134+
add(name, true) = std::move(irep);
135+
}
130136

131137
const std::string &get_string(const irep_namet &name) const
132138
{
@@ -141,7 +147,9 @@ class irept
141147
long long get_long_long(const irep_namet &name) const;
142148

143149
void set(const irep_namet &name, const irep_idt &value)
144-
{ add(name).id(value); }
150+
{
151+
add(name, true).id(value);
152+
}
145153
void set(const irep_namet &name, const irept &irep)
146154
{ add(name, irep); }
147155
void set(const irep_namet &name, const long long value);
@@ -176,6 +184,16 @@ class irept
176184
return write(false).sub;
177185
}
178186
const subt &get_sub() const { return read().sub; }
187+
subt::size_type get_sub_size() const
188+
{
189+
return read().sub.size();
190+
}
191+
void reserve_sub(subt::size_type n)
192+
{
193+
#ifndef USE_LIST
194+
write(true).sub.reserve(n);
195+
#endif
196+
}
179197
named_subt &get_named_sub()
180198
{
181199
return write(false).named_sub;
@@ -199,6 +217,20 @@ class irept
199217
{ return !name.empty() && name[0]=='#'; }
200218

201219
private:
220+
/// Adds a new irept to the comments or named_sub collection with the given
221+
/// name or retrieves the existing irept with the matching name
222+
/// \remarks
223+
/// If name starts with a hash symbol ('#') then the comments collection is
224+
/// used, otherwise the named_sub collection is used
225+
/// If the reference returned by this call is potentially held long enough
226+
/// that a copy of this irept could be made before it is disposed of then you
227+
/// must pass false for mark_sharable to ensure safe behaviour.
228+
/// \param name: The name of the irept to add/retrieve
229+
/// \param mark_sharable: If false then future copies of this irept will
230+
/// not use sharing
231+
/// \returns The added or retrieved irept
232+
irept &add(const irep_namet &name, bool mark_sharable);
233+
202234
class dt
203235
#ifdef SHARING
204236
: public copy_on_write_pointeet<unsigned>

Diff for: unit/util/irep_sharing.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
#include <testing-utils/catch.hpp>
66
#include <util/expr.h>
77

8-
SCENARIO("irept_sharing", "[!mayfail][core][utils][irept]")
8+
SCENARIO("irept_sharing", "[core][utils][irept]")
99
{
1010
GIVEN("A sample expression created with move_to_operands and a copy")
1111
{

0 commit comments

Comments
 (0)