Skip to content

Commit 1926499

Browse files
committed
Move definition of can-be-constant-propagated to a central location
This is re-usable, for example for the constant-propagation data-flow analysis.
1 parent 50d1c79 commit 1926499

File tree

4 files changed

+120
-125
lines changed

4 files changed

+120
-125
lines changed

src/goto-symex/goto_symex_state.cpp

+37-120
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Author: Daniel Kroening, [email protected]
1616

1717
#include <util/invariant.h>
1818
#include <util/base_exceptions.h>
19+
#include <util/expr_util.h>
1920
#include <util/std_expr.h>
2021
#include <util/prefix.h>
2122

@@ -79,125 +80,6 @@ void goto_symex_statet::level1t::operator()(ssa_exprt &ssa_expr)
7980
ssa_expr.set_level_1(it->second.second);
8081
}
8182

82-
/// This function determines what expressions are to be propagated as
83-
/// "constants"
84-
bool goto_symex_statet::constant_propagation(const exprt &expr) const
85-
{
86-
if(expr.is_constant())
87-
return true;
88-
89-
if(expr.id()==ID_address_of)
90-
{
91-
const address_of_exprt &address_of_expr=to_address_of_expr(expr);
92-
93-
return constant_propagation_reference(address_of_expr.object());
94-
}
95-
else if(expr.id()==ID_typecast)
96-
{
97-
const typecast_exprt &typecast_expr=to_typecast_expr(expr);
98-
99-
return constant_propagation(typecast_expr.op());
100-
}
101-
else if(expr.id()==ID_plus)
102-
{
103-
forall_operands(it, expr)
104-
if(!constant_propagation(*it))
105-
return false;
106-
107-
return true;
108-
}
109-
else if(expr.id()==ID_mult)
110-
{
111-
// propagate stuff with sizeof in it
112-
forall_operands(it, expr)
113-
{
114-
if(it->find(ID_C_c_sizeof_type).is_not_nil())
115-
return true;
116-
else if(!constant_propagation(*it))
117-
return false;
118-
}
119-
120-
return true;
121-
}
122-
else if(expr.id()==ID_array)
123-
{
124-
forall_operands(it, expr)
125-
if(!constant_propagation(*it))
126-
return false;
127-
128-
return true;
129-
}
130-
else if(expr.id()==ID_array_of)
131-
{
132-
return constant_propagation(expr.op0());
133-
}
134-
else if(expr.id()==ID_with)
135-
{
136-
// this is bad
137-
/*
138-
forall_operands(it, expr)
139-
if(!constant_propagation(expr.op0()))
140-
return false;
141-
142-
return true;
143-
*/
144-
return false;
145-
}
146-
else if(expr.id()==ID_struct)
147-
{
148-
forall_operands(it, expr)
149-
if(!constant_propagation(*it))
150-
return false;
151-
152-
return true;
153-
}
154-
else if(expr.id()==ID_union)
155-
{
156-
forall_operands(it, expr)
157-
if(!constant_propagation(*it))
158-
return false;
159-
160-
return true;
161-
}
162-
// byte_update works, byte_extract may be out-of-bounds
163-
else if(expr.id()==ID_byte_update_big_endian ||
164-
expr.id()==ID_byte_update_little_endian)
165-
{
166-
forall_operands(it, expr)
167-
if(!constant_propagation(*it))
168-
return false;
169-
170-
return true;
171-
}
172-
173-
return false;
174-
}
175-
176-
/// this function determines which reference-typed expressions are constant
177-
bool goto_symex_statet::constant_propagation_reference(const exprt &expr) const
178-
{
179-
if(expr.id()==ID_symbol)
180-
return true;
181-
else if(expr.id()==ID_index)
182-
{
183-
const index_exprt &index_expr=to_index_expr(expr);
184-
185-
return constant_propagation_reference(index_expr.array()) &&
186-
constant_propagation(index_expr.index());
187-
}
188-
else if(expr.id()==ID_member)
189-
{
190-
if(expr.operands().size()!=1)
191-
throw "member expects one operand";
192-
193-
return constant_propagation_reference(expr.op0());
194-
}
195-
else if(expr.id()==ID_string_constant)
196-
return true;
197-
198-
return false;
199-
}
200-
20183
/// write to a variable
20284
static bool check_renaming(const exprt &expr);
20385

@@ -306,6 +188,41 @@ static void assert_l2_renaming(const exprt &expr)
306188
#endif
307189
}
308190

191+
class goto_symex_is_constantt : public is_constantt
192+
{
193+
protected:
194+
bool is_constant(const exprt &expr) const override
195+
{
196+
if(expr.id()==ID_mult)
197+
{
198+
// propagate stuff with sizeof in it
199+
forall_operands(it, expr)
200+
{
201+
if(it->find(ID_C_c_sizeof_type).is_not_nil())
202+
return true;
203+
else if(!is_constant(*it))
204+
return false;
205+
}
206+
207+
return true;
208+
}
209+
else if(expr.id()==ID_with)
210+
{
211+
// this is bad
212+
/*
213+
forall_operands(it, expr)
214+
if(!is_constant(expr.op0()))
215+
return false;
216+
217+
return true;
218+
*/
219+
return false;
220+
}
221+
222+
return is_constantt::is_constant(expr);
223+
}
224+
};
225+
309226
void goto_symex_statet::assignment(
310227
ssa_exprt &lhs, // L0/L1
311228
const exprt &rhs, // L2
@@ -344,7 +261,7 @@ void goto_symex_statet::assignment(
344261

345262
// for value propagation -- the RHS is L2
346263

347-
if(!is_shared && record_value && constant_propagation(rhs))
264+
if(!is_shared && record_value && goto_symex_is_constantt(rhs))
348265
propagation.values[l1_identifier]=rhs;
349266
else
350267
propagation.remove(l1_identifier);

src/goto-symex/goto_symex_state.h

-4
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,6 @@ class goto_symex_statet final
177177
bool rhs_is_simplified,
178178
bool record_value);
179179

180-
// what to propagate
181-
bool constant_propagation(const exprt &expr) const;
182-
bool constant_propagation_reference(const exprt &expr) const;
183-
184180
// undoes all levels of renaming
185181
void get_original_name(exprt &expr) const;
186182
void get_original_name(typet &type) const;

src/util/expr_util.cpp

+64-1
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ Author: Daniel Kroening, [email protected]
66
77
\*******************************************************************/
88

9-
109
#include "expr_util.h"
1110

11+
#include <algorithm>
1212
#include <unordered_set>
13+
1314
#include "expr.h"
1415
#include "expr_iterator.h"
1516
#include "fixedbv.h"
@@ -201,3 +202,65 @@ if_exprt lift_if(const exprt &src, std::size_t operand_number)
201202

202203
return result;
203204
}
205+
206+
bool is_constantt::is_constant(const exprt &expr) const
207+
{
208+
if(expr.is_constant())
209+
return true;
210+
211+
if(expr.id() == ID_address_of)
212+
{
213+
const address_of_exprt &address_of_expr = to_address_of_expr(expr);
214+
215+
return is_constant_reference(address_of_expr.object());
216+
}
217+
else if(expr.id() == ID_typecast)
218+
{
219+
const typecast_exprt &typecast_expr = to_typecast_expr(expr);
220+
221+
return is_constant(typecast_expr.op());
222+
}
223+
else if(expr.id() == ID_array_of)
224+
{
225+
return is_constant(expr.op0());
226+
}
227+
else if(
228+
expr.id() == ID_plus || expr.id() == ID_mult || expr.id() == ID_array ||
229+
expr.id() == ID_with || expr.id() == ID_struct || expr.id() == ID_union ||
230+
// byte_update works, byte_extract may be out-of-bounds
231+
expr.id() == ID_byte_update_big_endian ||
232+
expr.id() == ID_byte_update_little_endian)
233+
{
234+
return std::all_of(
235+
expr.operands().begin(),
236+
expr.operands().end(),
237+
[](const exprt &) { return is_constant(expr); });
238+
}
239+
240+
return false;
241+
}
242+
243+
bool is_constantt::is_constant_address_of(const exprt &expr) const
244+
{
245+
if(expr.id() == ID_symbol)
246+
{
247+
return true;
248+
}
249+
else if(expr.id() == ID_index)
250+
{
251+
const index_exprt &index_expr = to_index_expr(expr);
252+
253+
return is_constant_address_of(index_expr.array()) &&
254+
is_constant(index_expr.index());
255+
}
256+
else if(expr.id() == ID_member)
257+
{
258+
const member_exprt &member_expr = to_member_expr(expr);
259+
260+
return is_constant_address_of(member_expr.struct_op());
261+
}
262+
else if(expr.id() == ID_string_constant)
263+
return true;
264+
265+
return false;
266+
}

src/util/expr_util.h

+19
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,23 @@ bool has_subtype(const typet &, const irep_idt &id, const namespacet &);
7272
/// lift up an if_exprt one level
7373
if_exprt lift_if(const exprt &, std::size_t operand_number);
7474

75+
/// Determine whether an expression is constant. A literal constant is
76+
/// constant, but so are, e.g., sums over constants or addresses of objects.
77+
/// An implementation derive from this class to refine what it considers
78+
/// constant in a particular context by overriding is_constant and/or
79+
/// is_constant_address_of.
80+
class is_constantt
81+
{
82+
public:
83+
/// returns true iff the expression can be considered constant
84+
bool operator(const exprt &e) const
85+
{
86+
return is_constant(e);
87+
}
88+
89+
protected:
90+
virtual bool is_constant(const exprt &) const;
91+
virtual bool is_constant_address_of(const exprt &) const;
92+
};
93+
7594
#endif // CPROVER_UTIL_EXPR_UTIL_H

0 commit comments

Comments
 (0)