[Decompiler] Fix coloring moves (#281)

* fixed

* final fix
This commit is contained in:
water111
2021-02-24 19:08:55 -05:00
committed by GitHub
parent 5ec9a91eb9
commit f6a6b4c107
5 changed files with 144 additions and 29 deletions
+34 -15
View File
@@ -959,29 +959,17 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
}
assert(m_src->parent_element == this);
// hack for method stuff
if (is_dead_set()) {
stack.push_value_to_reg_dead(m_dst, m_src, true, m_var_info);
return;
}
m_src->update_children_from_stack(env, pool, stack, true);
for (auto x : m_src->elts()) {
assert(x->parent_form == m_src);
}
// if we are a reg-reg move that consumes the original, push it without popping from stack.
// it is the Stack's responsibility to untangle these later on.
if (m_src->is_single_element()) {
auto src_as_se = dynamic_cast<SimpleExpressionElement*>(m_src->back());
if (src_as_se) {
if (src_as_se->expr().kind() == SimpleExpression::Kind::IDENTITY &&
m_dst.reg().get_kind() == Reg::FPR && src_as_se->expr().get_arg(0).is_int() &&
src_as_se->expr().get_arg(0).get_int() == 0) {
stack.push_value_to_reg(m_dst,
pool.alloc_single_element_form<ConstantFloatElement>(nullptr, 0.0),
true, m_var_info);
return;
}
if (src_as_se->expr().kind() == SimpleExpression::Kind::IDENTITY &&
src_as_se->expr().get_arg(0).is_var()) {
// this can happen late in the case of coloring moves which are also gpr -> fpr's
@@ -1001,6 +989,37 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
}
}
// we aren't a reg-reg move, so update our source
m_src->update_children_from_stack(env, pool, stack, true);
for (auto x : m_src->elts()) {
assert(x->parent_form == m_src);
}
if (m_src->is_single_element()) {
auto src_as_se = dynamic_cast<SimpleExpressionElement*>(m_src->back());
if (src_as_se) {
if (src_as_se->expr().kind() == SimpleExpression::Kind::IDENTITY &&
m_dst.reg().get_kind() == Reg::FPR && src_as_se->expr().get_arg(0).is_int() &&
src_as_se->expr().get_arg(0).get_int() == 0) {
// not sure this is the best place for this.
stack.push_value_to_reg(m_dst,
pool.alloc_single_element_form<ConstantFloatElement>(nullptr, 0.0),
true, m_var_info);
return;
}
// this might get skipped earlier because gpr->fpr gets wrapped in an operation that's
// stripped off by update_children_from_stack.
if (src_as_se->expr().kind() == SimpleExpression::Kind::IDENTITY &&
src_as_se->expr().get_arg(0).is_var()) {
if (env.op_id_is_eliminated_coloring_move(src_as_se->expr().get_arg(0).var().idx())) {
m_var_info.is_eliminated_coloring_move = true;
}
}
}
}
stack.push_value_to_reg(m_dst, m_src, true, m_var_info);
for (auto x : m_src->elts()) {
assert(x->parent_form == m_src);
+75 -14
View File
@@ -7,13 +7,25 @@ namespace decompiler {
std::string FormStack::StackEntry::print(const Env& env) const {
if (destination.has_value()) {
assert(source && !elt);
return fmt::format("d: {} s: {} | {} <- {} f: {}", active, sequence_point,
destination.value().reg().to_charp(), source->to_string(env),
non_seq_source.has_value());
if (active) {
return fmt::format("d: {} s: {} | {} <- {} f: {} w: {}", active, sequence_point,
destination.value().reg().to_charp(), source->to_string(env),
non_seq_source.has_value(), is_compactable);
} else {
return fmt::format(" d: {} s: {} | {} <- {} f: {} w: {}", active, sequence_point,
destination.value().reg().to_charp(), source->to_string(env),
non_seq_source.has_value(), is_compactable);
}
} else {
assert(elt && !source);
return fmt::format("d: {} s: {} | {} f: {}", active, sequence_point, elt->to_string(env),
non_seq_source.has_value());
if (active) {
return fmt::format("d: {} s: {} | {} f: {}", active, sequence_point, elt->to_string(env),
non_seq_source.has_value());
} else {
return fmt::format(" d: {} s: {} | {} f: {}", active, sequence_point, elt->to_string(env),
non_seq_source.has_value());
}
}
}
@@ -66,6 +78,7 @@ void FormStack::push_non_seq_reg_to_reg(const Variable& dst,
entry.non_seq_source = src;
entry.source = src_as_form;
entry.set_info = info;
entry.is_compactable = true;
m_stack.push_back(entry);
}
@@ -109,6 +122,7 @@ Form* FormStack::pop_reg(Register reg,
const Env& env,
bool allow_side_effects,
int begin_idx) {
assert(allow_side_effects);
(void)env; // keep this for easy debugging.
RegSet modified;
size_t begin = m_stack.size();
@@ -279,8 +293,32 @@ std::vector<FormElement*> FormStack::rewrite(FormPool& pool, const Env& env) {
if (e.destination.has_value()) {
// (set! x (+ x y)) -> (+! x y)
auto elt =
pool.alloc_element<SetVarElement>(*e.destination, e.source, e.sequence_point, e.set_info);
// we want to untangle coloring moves here
auto simplified_source = e.source;
auto src_as_var = dynamic_cast<SimpleExpressionElement*>(e.source->try_as_single_element());
if (src_as_var && src_as_var->expr().is_var() && e.is_compactable) {
bool keep_going = true;
auto var_to_get = src_as_var->expr().var();
while (keep_going && !result.empty()) {
keep_going = false;
auto last_op_as_set = dynamic_cast<SetVarElement*>(result.back());
if (last_op_as_set && last_op_as_set->dst().reg() == var_to_get.reg()) {
result.pop_back();
auto as_one = dynamic_cast<SimpleExpressionElement*>(
last_op_as_set->src()->try_as_single_element());
if (as_one && as_one->expr().is_identity() && as_one->expr().is_var() &&
!result.empty()) {
keep_going = true;
var_to_get = as_one->expr().var();
}
simplified_source = last_op_as_set->src();
// result = last_op_as_set->src()->elts();
}
}
}
auto elt = pool.alloc_element<SetVarElement>(*e.destination, simplified_source,
e.sequence_point, e.set_info);
e.source->parent_element = elt;
auto final_elt = try_rewrites_in_place(elt, env, pool);
@@ -296,15 +334,38 @@ void rewrite_to_get_var(std::vector<FormElement*>& default_result,
FormPool& pool,
const Variable& var,
const Env&) {
auto last_op_as_set = dynamic_cast<SetVarElement*>(default_result.back());
if (last_op_as_set && last_op_as_set->dst().reg() == var.reg()) {
default_result.pop_back();
for (auto form : last_op_as_set->src()->elts()) {
form->parent_form = nullptr; // will get set later, this makes it obvious if I forget.
default_result.push_back(form);
bool keep_going = true;
Variable var_to_get = var;
std::vector<FormElement*> result;
bool first = true;
while (keep_going) {
keep_going = false;
auto last_op_as_set = dynamic_cast<SetVarElement*>(default_result.back());
if (last_op_as_set && last_op_as_set->dst().reg() == var_to_get.reg() &&
(first || last_op_as_set->info().is_compactable)) {
default_result.pop_back();
auto as_one =
dynamic_cast<SimpleExpressionElement*>(last_op_as_set->src()->try_as_single_element());
if (as_one && as_one->expr().is_identity() && as_one->expr().is_var() &&
!default_result.empty()) {
keep_going = true;
var_to_get = as_one->expr().var();
}
result = last_op_as_set->src()->elts();
}
} else {
first = false;
}
if (result.empty()) {
default_result.push_back(pool.alloc_element<SimpleAtomElement>(SimpleAtom::make_var(var)));
} else {
for (auto x : result) {
x->parent_form = nullptr;
default_result.push_back(x);
}
}
}
+1
View File
@@ -53,6 +53,7 @@ class FormStack {
FormElement* elt = nullptr;
bool sequence_point = false;
TP_Type type;
bool is_compactable = false;
SetVarInfo set_info;
+3
View File
@@ -166,6 +166,9 @@ struct SetVarInfo {
bool is_dead_set = false;
// is this a (set! var #f) where the value of #f isn't used?
bool is_dead_false = false;
// it this a move that can be compacted? For now, this is always false, but we may want to
// allow more advanced compaction later.
bool is_compactable = false;
};
} // namespace decompiler
@@ -2503,4 +2503,35 @@ TEST_F(FormRegressionTest, StringLt) {
" #f\n"
" )";
test_with_expr(func, type, expected, false, "");
}
TEST_F(FormRegressionTest, ExprAssert) {
std::string func =
" sll r0, r0, 0\n"
" daddiu sp, sp, -16\n"
" sd ra, 0(sp)\n"
" sd fp, 8(sp)\n"
" or fp, t9, r0\n"
" bne s7, a0, L12\n"
" or v1, s7, r0\n"
" lw t9, format(s7)\n"
" daddiu a0, s7, #t\n"
" daddiu v1, fp, L17\n"
" or a2, a1, r0\n"
" or a1, v1, r0\n"
" jalr ra, t9\n"
" sll v0, ra, 0\n"
"L12:\n"
" or v0, r0, r0\n"
" ld ra, 0(sp)\n"
" ld fp, 8(sp)\n"
" jr ra\n"
" daddiu sp, sp, 16";
std::string type = "(function symbol string int)";
std::string expected = "(begin (if (not arg0) (format (quote #t) \"A ~A\" arg1)) 0)";
test_with_expr(func, type, expected, false, "", {{"L17", "A ~A"}});
}