2021-02-01 20:41:37 -05:00
|
|
|
#include <algorithm>
|
2021-01-22 20:50:37 -05:00
|
|
|
#include "FormStack.h"
|
|
|
|
#include "Form.h"
|
|
|
|
|
|
|
|
namespace decompiler {
|
|
|
|
std::string FormStack::StackEntry::print(const Env& env) const {
|
|
|
|
if (destination.has_value()) {
|
|
|
|
assert(source && !elt);
|
2021-01-27 15:39:50 -05:00
|
|
|
return fmt::format("d: {} s: {} | {} <- {} f: {}", active, sequence_point,
|
|
|
|
destination.value().reg().to_charp(), source->to_string(env),
|
|
|
|
non_seq_source.has_value());
|
2021-01-22 20:50:37 -05:00
|
|
|
} else {
|
|
|
|
assert(elt && !source);
|
2021-01-27 15:39:50 -05:00
|
|
|
return fmt::format("d: {} s: {} | {} f: {}", active, sequence_point, elt->to_string(env),
|
|
|
|
non_seq_source.has_value());
|
2021-01-22 20:50:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string FormStack::print(const Env& env) {
|
|
|
|
std::string result;
|
|
|
|
for (auto& x : m_stack) {
|
|
|
|
result += x.print(env);
|
|
|
|
result += '\n';
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2021-02-11 16:13:03 -05:00
|
|
|
void FormStack::push_value_to_reg(Variable var,
|
|
|
|
Form* value,
|
|
|
|
bool sequence_point,
|
|
|
|
const SetVarInfo& info) {
|
2021-02-05 19:41:09 -05:00
|
|
|
assert(value);
|
2021-01-22 20:50:37 -05:00
|
|
|
StackEntry entry;
|
|
|
|
entry.active = true; // by default, we should display everything!
|
|
|
|
entry.sequence_point = sequence_point;
|
|
|
|
entry.destination = var;
|
|
|
|
entry.source = value;
|
2021-02-11 16:13:03 -05:00
|
|
|
entry.set_info = info;
|
2021-01-22 20:50:37 -05:00
|
|
|
m_stack.push_back(entry);
|
|
|
|
}
|
|
|
|
|
2021-01-27 15:39:50 -05:00
|
|
|
void FormStack::push_non_seq_reg_to_reg(const Variable& dst,
|
|
|
|
const Variable& src,
|
2021-02-09 20:59:14 -05:00
|
|
|
Form* src_as_form,
|
2021-02-11 16:13:03 -05:00
|
|
|
const SetVarInfo& info) {
|
2021-02-05 19:41:09 -05:00
|
|
|
assert(src_as_form);
|
2021-01-27 15:39:50 -05:00
|
|
|
StackEntry entry;
|
|
|
|
entry.active = true;
|
|
|
|
entry.sequence_point = false;
|
|
|
|
entry.destination = dst;
|
|
|
|
entry.non_seq_source = src;
|
|
|
|
entry.source = src_as_form;
|
2021-02-11 16:13:03 -05:00
|
|
|
entry.set_info = info;
|
2021-01-27 15:39:50 -05:00
|
|
|
m_stack.push_back(entry);
|
|
|
|
}
|
|
|
|
|
2021-01-22 20:50:37 -05:00
|
|
|
bool FormStack::is_single_expression() {
|
|
|
|
int count = 0;
|
|
|
|
for (auto& e : m_stack) {
|
|
|
|
if (e.active) {
|
|
|
|
count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count == 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void FormStack::push_form_element(FormElement* elt, bool sequence_point) {
|
|
|
|
StackEntry entry;
|
|
|
|
entry.active = true;
|
|
|
|
entry.elt = elt;
|
|
|
|
entry.sequence_point = sequence_point;
|
|
|
|
m_stack.push_back(entry);
|
|
|
|
}
|
|
|
|
|
2021-02-05 19:41:09 -05:00
|
|
|
Form* FormStack::pop_reg(const Variable& var,
|
|
|
|
const RegSet& barrier,
|
|
|
|
const Env& env,
|
|
|
|
bool allow_side_effects) {
|
|
|
|
return pop_reg(var.reg(), barrier, env, allow_side_effects);
|
2021-02-01 20:41:37 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
bool nonempty_intersection(const RegSet& a, const RegSet& b) {
|
|
|
|
// todo - if we ever switch to bit reg sets, this could be a lot faster.
|
|
|
|
std::vector<Register> isect;
|
|
|
|
std::set_intersection(a.begin(), a.end(), b.begin(), b.end(), std::back_inserter(isect));
|
|
|
|
return !isect.empty();
|
|
|
|
}
|
|
|
|
} // namespace
|
|
|
|
|
2021-02-05 19:41:09 -05:00
|
|
|
Form* FormStack::pop_reg(Register reg,
|
|
|
|
const RegSet& barrier,
|
|
|
|
const Env& env,
|
|
|
|
bool allow_side_effects) {
|
2021-02-01 20:41:37 -05:00
|
|
|
(void)env; // keep this for easy debugging.
|
|
|
|
RegSet modified;
|
2021-01-22 20:50:37 -05:00
|
|
|
for (size_t i = m_stack.size(); i-- > 0;) {
|
|
|
|
auto& entry = m_stack.at(i);
|
|
|
|
if (entry.active) {
|
2021-02-05 19:41:09 -05:00
|
|
|
if (entry.destination.has_value() && entry.destination->reg() == reg) {
|
2021-02-01 20:41:37 -05:00
|
|
|
entry.source->get_modified_regs(modified);
|
2021-02-05 19:41:09 -05:00
|
|
|
if (!allow_side_effects && entry.source->has_side_effects()) {
|
|
|
|
// the source of the set! has a side effect and that's not allowed, so abort.
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-02-01 20:41:37 -05:00
|
|
|
if (nonempty_intersection(modified, barrier)) {
|
2021-02-05 19:41:09 -05:00
|
|
|
// violating the barrier registers.
|
2021-02-01 20:41:37 -05:00
|
|
|
return nullptr;
|
|
|
|
}
|
2021-01-22 20:50:37 -05:00
|
|
|
entry.active = false;
|
|
|
|
assert(entry.source);
|
2021-01-27 15:39:50 -05:00
|
|
|
if (entry.non_seq_source.has_value()) {
|
|
|
|
assert(entry.sequence_point == false);
|
2021-02-05 19:41:09 -05:00
|
|
|
auto result = pop_reg(entry.non_seq_source->reg(), barrier, env, allow_side_effects);
|
2021-01-27 15:39:50 -05:00
|
|
|
if (result) {
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|
2021-01-22 20:50:37 -05:00
|
|
|
return entry.source;
|
|
|
|
} else {
|
|
|
|
// we didn't match
|
|
|
|
if (entry.sequence_point) {
|
|
|
|
// and it's a sequence point! can't look any more back than this.
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-02-01 20:41:37 -05:00
|
|
|
// no match, and not a sequence:
|
|
|
|
if (entry.source) {
|
|
|
|
assert(!entry.elt);
|
|
|
|
entry.source->get_modified_regs(modified);
|
2021-02-05 19:41:09 -05:00
|
|
|
if (!allow_side_effects) {
|
|
|
|
// shouldn't allow skipping past a set! (may be too conservative?)
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-02-01 20:41:37 -05:00
|
|
|
} else {
|
|
|
|
assert(entry.elt);
|
|
|
|
entry.elt->get_modified_regs(modified);
|
2021-02-05 19:41:09 -05:00
|
|
|
if (!allow_side_effects && entry.elt->has_side_effects()) {
|
|
|
|
// shouldn't allow skipping past something with a set! (also may be too conservative?)
|
|
|
|
return nullptr;
|
|
|
|
}
|
2021-02-01 20:41:37 -05:00
|
|
|
}
|
2021-01-22 20:50:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// we didn't have it...
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-02-13 16:35:27 -05:00
|
|
|
Form* FormStack::unsafe_peek(Register reg) {
|
|
|
|
RegSet modified;
|
|
|
|
for (size_t i = m_stack.size(); i-- > 0;) {
|
|
|
|
auto& entry = m_stack.at(i);
|
|
|
|
if (entry.active) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.source->get_modified_regs(modified);
|
|
|
|
if (modified.find(reg) != modified.end()) {
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entry.destination.has_value() && entry.destination->reg() == reg) {
|
|
|
|
return entry.source;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2021-01-22 20:50:37 -05:00
|
|
|
std::vector<FormElement*> FormStack::rewrite(FormPool& pool) {
|
|
|
|
std::vector<FormElement*> result;
|
|
|
|
|
|
|
|
for (auto& e : m_stack) {
|
|
|
|
if (!e.active) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (e.destination.has_value()) {
|
2021-02-11 16:13:03 -05:00
|
|
|
auto elt =
|
|
|
|
pool.alloc_element<SetVarElement>(*e.destination, e.source, e.sequence_point, e.set_info);
|
2021-01-22 20:50:37 -05:00
|
|
|
e.source->parent_element = elt;
|
|
|
|
result.push_back(elt);
|
|
|
|
} else {
|
|
|
|
result.push_back(e.elt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
2021-01-23 16:32:56 -05:00
|
|
|
|
2021-01-25 22:08:58 -05:00
|
|
|
std::vector<FormElement*> FormStack::rewrite_to_get_var(FormPool& pool,
|
|
|
|
const Variable& var,
|
|
|
|
const Env&) {
|
2021-01-23 16:32:56 -05:00
|
|
|
// first, rewrite as normal.
|
|
|
|
auto default_result = rewrite(pool);
|
|
|
|
|
|
|
|
// try a few different ways to "naturally" rewrite this so the value of the form is the
|
|
|
|
// value in the given register.
|
|
|
|
|
|
|
|
auto last_op_as_set = dynamic_cast<SetVarElement*>(default_result.back());
|
2021-01-25 22:08:58 -05:00
|
|
|
if (last_op_as_set && last_op_as_set->dst().reg() == var.reg()) {
|
2021-01-23 16:32:56 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
return default_result;
|
|
|
|
} else {
|
2021-01-25 22:08:58 -05:00
|
|
|
default_result.push_back(pool.alloc_element<SimpleAtomElement>(SimpleAtom::make_var(var)));
|
|
|
|
return default_result;
|
2021-01-23 16:32:56 -05:00
|
|
|
}
|
|
|
|
}
|
2021-01-22 20:50:37 -05:00
|
|
|
} // namespace decompiler
|