Skip to content

Commit 17a985a

Browse files
committed
Add constant string resolution for .equals in expression simplifier
If we are comparing two constant strings against each other we should be able to answer the question of comparison without passing it to the solver.
1 parent b1bf1ef commit 17a985a

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

src/util/simplify_expr.cpp

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,15 @@ Author: Daniel Kroening, [email protected]
1919
#include "expr_util.h"
2020
#include "fixedbv.h"
2121
#include "invariant.h"
22+
#include "mathematical_expr.h"
2223
#include "namespace.h"
2324
#include "pointer_offset_size.h"
2425
#include "rational.h"
2526
#include "rational_tools.h"
2627
#include "simplify_utils.h"
2728
#include "std_expr.h"
29+
#include "string_expr.h"
30+
#include "symbol.h"
2831
#include "type_eq.h"
2932

3033
// #define DEBUGX
@@ -158,6 +161,77 @@ bool simplify_exprt::simplify_popcount(popcount_exprt &expr)
158161
return true;
159162
}
160163

164+
bool simplify_exprt::simplify_function_application(exprt &expr)
165+
{
166+
const function_application_exprt &function_app =
167+
to_function_application_expr(expr);
168+
irep_idt func_id =
169+
function_app.function().find(ID_expression).get(ID_identifier);
170+
171+
// Starts-with is used for .equals.
172+
if(func_id == ID_cprover_string_startswith_func)
173+
{
174+
// We want to get both arguments of any starts-with comparison, and
175+
// trace them back to the actual string instance. All variables on the
176+
// way must be constant for us to be sure this will work.
177+
auto &first_argument = to_string_expr(function_app.arguments().at(0));
178+
auto &second_argument = to_string_expr(function_app.arguments().at(1));
179+
180+
if(
181+
first_argument.content().id() != ID_address_of ||
182+
second_argument.content().id() != ID_address_of)
183+
{
184+
return true;
185+
}
186+
187+
const address_of_exprt &first_address_of =
188+
to_address_of_expr(first_argument.content());
189+
const address_of_exprt &second_address_of =
190+
to_address_of_expr(second_argument.content());
191+
192+
// Constants are got via address_of expressions, so this helps filter out
193+
// things that are non-constant.
194+
if(
195+
first_address_of.object().id() != ID_index ||
196+
first_address_of.object().id() != ID_index)
197+
{
198+
return true;
199+
}
200+
201+
const index_exprt &first_index_expression =
202+
to_index_expr(first_address_of.object());
203+
const index_exprt &second_index_expression =
204+
to_index_expr(second_address_of.object());
205+
206+
const exprt &first_string_array = first_index_expression.array();
207+
const exprt &second_string_array = second_index_expression.array();
208+
209+
// Check if our symbols type is an array.
210+
if(
211+
first_string_array.type().id() != ID_array ||
212+
second_string_array.type().id() != ID_array)
213+
{
214+
return true;
215+
}
216+
217+
// If so, it'll be a string array that we can use.
218+
const array_string_exprt &first_string = to_array_string_expr(
219+
ns.lookup(first_string_array.get(ID_identifier)).value);
220+
221+
const array_string_exprt &second_string = to_array_string_expr(
222+
ns.lookup(second_string_array.get(ID_identifier)).value);
223+
224+
// If the lengths are the same we can do the .equals substitute.
225+
if(first_string.length() == second_string.length())
226+
{
227+
expr = from_integer(first_string == second_string ? 1 : 0, expr.type());
228+
return false;
229+
}
230+
}
231+
232+
return true;
233+
}
234+
161235
bool simplify_exprt::simplify_typecast(exprt &expr)
162236
{
163237
if(expr.operands().size()!=1)
@@ -2265,6 +2339,8 @@ bool simplify_exprt::simplify_node(exprt &expr)
22652339
result=simplify_sign(expr) && result;
22662340
else if(expr.id() == ID_popcount)
22672341
result = simplify_popcount(to_popcount_expr(expr)) && result;
2342+
else if(expr.id() == ID_function_application)
2343+
result = simplify_function_application(expr) && result;
22682344

22692345
#ifdef DEBUGX
22702346
if(!result

src/util/simplify_expr_class.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class simplify_exprt
114114
bool simplify_sign(exprt &expr);
115115
bool simplify_popcount(popcount_exprt &expr);
116116

117+
/// Attempt to simplify mathematical function applications if we have
118+
/// enough information to do so. Currently focused on constant comparisons.
119+
bool simplify_function_application(exprt &expr);
120+
117121
// auxiliary
118122
bool simplify_if_implies(
119123
exprt &expr, const exprt &cond, bool truth, bool &new_truth);

0 commit comments

Comments
 (0)