-
Notifications
You must be signed in to change notification settings - Fork 273
Do not sort operands as part of simplification [blocks: #3486] #1997
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
#include <assert.h> | ||
#include <math.h> | ||
|
||
int main() | ||
{ | ||
float a; | ||
float b; | ||
// We could do "if (isnormal(a) && isnormal(b))", but __CPROVER_isnanf(a+b) | ||
// will permit solving this entirely via the simplifier, if, and only if, the | ||
// equality is successfully simplified (despite the different order of | ||
// operands). | ||
assert(__CPROVER_isnanf(a + b) || a + b == b + a); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
CORE | ||
main.c | ||
|
||
(Starting CEGAR Loop|VCC\(s\), 0 remaining after simplification$) | ||
^VERIFICATION SUCCESSFUL$ | ||
^EXIT=0$ | ||
^SIGNAL=0$ | ||
-- | ||
^warning: ignoring | ||
-- | ||
This requires simplification of commutative, but not associative operations. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ Author: Daniel Kroening, [email protected] | |
#include "invariant.h" | ||
#include "namespace.h" | ||
#include "simplify_expr.h" | ||
#include "simplify_utils.h" | ||
#include "std_expr.h" | ||
|
||
simplify_exprt::resultt<> | ||
|
@@ -361,7 +362,15 @@ simplify_exprt::simplify_ieee_float_relation(const binary_relation_exprt &expr) | |
UNREACHABLE; | ||
} | ||
|
||
if(expr.lhs() == expr.rhs()) | ||
// addition and multiplication are commutative, but not associative | ||
exprt lhs_sorted = expr.lhs(); | ||
if(lhs_sorted.id() == ID_floatbv_plus || lhs_sorted.id() == ID_floatbv_mult) | ||
sort_operands(lhs_sorted.operands()); | ||
exprt rhs_sorted = expr.rhs(); | ||
if(rhs_sorted.id() == ID_floatbv_plus || rhs_sorted.id() == ID_floatbv_mult) | ||
sort_operands(rhs_sorted.operands()); | ||
|
||
if(lhs_sorted == rhs_sorted) | ||
{ | ||
// x!=x is the same as saying isnan(op) | ||
exprt isnan = isnan_exprt(expr.lhs()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -105,7 +105,7 @@ struct saj_tablet | |
{ irep_idt(), { irep_idt() }} | ||
}; | ||
|
||
static bool sort_and_join( | ||
static bool is_associative_and_commutative_for_type( | ||
const struct saj_tablet &saj_entry, | ||
const irep_idt &type_id) | ||
{ | ||
|
@@ -116,42 +116,44 @@ static bool sort_and_join( | |
return false; | ||
} | ||
|
||
static const struct saj_tablet &sort_and_join( | ||
const irep_idt &id, | ||
const irep_idt &type_id) | ||
static const struct saj_tablet & | ||
get_sort_and_join_table_entry(const irep_idt &id, const irep_idt &type_id) | ||
{ | ||
unsigned i=0; | ||
|
||
for( ; !saj_table[i].id.empty(); i++) | ||
if(id==saj_table[i].id && | ||
sort_and_join(saj_table[i], type_id)) | ||
{ | ||
if( | ||
id == saj_table[i].id && | ||
is_associative_and_commutative_for_type(saj_table[i], type_id)) | ||
return saj_table[i]; | ||
} | ||
|
||
return saj_table[i]; | ||
} | ||
|
||
bool sort_and_join(exprt &expr) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ! This needs a new name There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Because it no longer necessarily sorts! A person reading |
||
static bool sort_and_join(exprt &expr, bool do_sort) | ||
{ | ||
bool no_change = true; | ||
|
||
if(!expr.has_operands()) | ||
return true; | ||
|
||
const struct saj_tablet &saj_entry = | ||
sort_and_join(expr.id(), as_const(expr).type().id()); | ||
get_sort_and_join_table_entry(expr.id(), as_const(expr).type().id()); | ||
if(saj_entry.id.empty()) | ||
return true; | ||
|
||
// check operand types | ||
|
||
forall_operands(it, expr) | ||
if(!sort_and_join(saj_entry, it->type().id())) | ||
if(!is_associative_and_commutative_for_type(saj_entry, it->type().id())) | ||
return true; | ||
|
||
// join expressions | ||
|
||
exprt::operandst new_ops; | ||
new_ops.reserve(expr.operands().size()); | ||
new_ops.reserve(as_const(expr).operands().size()); | ||
|
||
forall_operands(it, expr) | ||
{ | ||
|
@@ -169,13 +171,25 @@ bool sort_and_join(exprt &expr) | |
} | ||
|
||
// sort it | ||
if(do_sort) | ||
no_change = sort_operands(new_ops) && no_change; | ||
|
||
no_change = sort_operands(new_ops) && no_change; | ||
expr.operands().swap(new_ops); | ||
if(!no_change) | ||
expr.operands().swap(new_ops); | ||
|
||
return no_change; | ||
} | ||
|
||
bool sort_and_join(exprt &expr) | ||
{ | ||
return sort_and_join(expr, true); | ||
} | ||
|
||
bool join_operands(exprt &expr) | ||
{ | ||
return sort_and_join(expr, false); | ||
} | ||
|
||
optionalt<exprt> bits2expr( | ||
const std::string &bits, | ||
const typet &type, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually; this raises an interesting question. Floating-point addition and multiplication are commutative but not associative. If seems like normalising / sorting these would be worth while.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I am able to follow: why would sorting (which this PR largely disables) be particularly beneficial for those operations? We surely can selectively re-enable sorting, but I don't think I understand the rationale just yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normalising the order of commutative-but-not-associative operations means we can resolve this at simplification, rather than an expensive solver call. It is not a massively common case but it is very cheap to implement and IIRC is a huge speed up in this case. Note that this can be purely local as it is not associative.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems we didn't actually simplify such expressions before as commutative-but-not-associative operations were exempt. I have now added 375f208 to take care of this, thank you very much for raising this!