wip: better stack var support (#4222)

Closes #736

---------

Co-authored-by: Hat Kid <6624576+Hat-Kid@users.noreply.github.com>
This commit is contained in:
water111
2026-04-18 18:14:44 -04:00
committed by GitHub
parent 3e3542cb10
commit 637990314b
1385 changed files with 94985 additions and 111624 deletions
+81 -17
View File
@@ -9,6 +9,26 @@
#include "decompiler/util/DecompilerTypeSystem.h"
namespace decompiler {
namespace {
bool nonempty_intersection(const RegSet& a, const RegSet& b) {
for (auto x : a) {
if (b.find(x) != b.end()) {
return true;
}
}
return false;
}
bool can_inline_non_seq_source(const RegisterAccess& src, const Env& env) {
if (!is_stack_slot_access(src)) {
return true;
}
const auto& use_def = env.get_use_def_info(src);
return use_def.use_count() == 1 && use_def.def_count() == 1;
}
} // namespace
std::string FormStack::StackEntry::print(const Env& env) const {
if (destination.has_value()) {
ASSERT(source && !elt);
@@ -116,19 +136,61 @@ Form* FormStack::pop_reg(const RegisterAccess& var,
const Env& env,
bool allow_side_effects,
int begin_idx) {
return pop_reg(var.reg(), barrier, env, allow_side_effects, begin_idx);
}
RegSet modified;
size_t begin = m_stack.size();
if (begin_idx >= 0) {
begin = begin_idx;
}
for (size_t i = begin; i-- > 0;) {
auto& entry = m_stack.at(i);
if (entry.active) {
if (entry.destination.has_value() && same_expression_var(*entry.destination, var)) {
entry.source->get_modified_regs(modified);
if (!allow_side_effects && entry.source->has_side_effects()) {
return nullptr;
}
if (nonempty_intersection(modified, barrier)) {
return nullptr;
}
entry.active = false;
ASSERT(entry.source);
if (entry.non_seq_source.has_value()) {
ASSERT(entry.sequence_point == false);
if (can_inline_non_seq_source(*entry.non_seq_source, env)) {
auto result = pop_reg(*entry.non_seq_source, barrier, env, allow_side_effects, i);
if (result) {
return result;
}
}
}
namespace {
bool nonempty_intersection(const RegSet& a, const RegSet& b) {
for (auto x : a) {
if (b.find(x) != b.end()) {
return true;
return entry.source;
} else {
if (entry.sequence_point) {
return nullptr;
}
if (entry.source) {
ASSERT(!entry.elt);
entry.source->get_modified_regs(modified);
if (!allow_side_effects) {
return nullptr;
}
} else {
ASSERT(entry.elt);
entry.elt->get_modified_regs(modified);
if (!allow_side_effects && entry.elt->has_side_effects()) {
return nullptr;
}
}
}
} else {
if (entry.destination.has_value() && same_expression_var(*entry.destination, var)) {
return nullptr;
}
}
}
return false;
return nullptr;
}
} // namespace
Form* FormStack::pop_reg(Register reg,
const RegSet& barrier,
@@ -164,13 +226,15 @@ Form* FormStack::pop_reg(Register reg,
ASSERT(entry.source);
if (entry.non_seq_source.has_value()) {
ASSERT(entry.sequence_point == false);
auto result = pop_reg(entry.non_seq_source->reg(), barrier, env, allow_side_effects, i);
if (result) {
if (found_orig_out) {
*found_orig_out = true;
*orig_out = *entry.destination;
if (can_inline_non_seq_source(*entry.non_seq_source, env)) {
auto result = pop_reg(entry.non_seq_source->reg(), barrier, env, allow_side_effects, i);
if (result) {
if (found_orig_out) {
*found_orig_out = true;
*orig_out = *entry.destination;
}
return result;
}
return result;
}
}
@@ -325,7 +389,7 @@ std::vector<FormElement*> FormStack::rewrite(FormPool& pool, const Env& env) con
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()) {
if (last_op_as_set && same_expression_var(last_op_as_set->dst(), var_to_get)) {
result.pop_back();
auto as_one = dynamic_cast<SimpleExpressionElement*>(
last_op_as_set->src()->try_as_single_element());
@@ -384,7 +448,7 @@ std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& defa
while (keep_going && !default_result.empty()) {
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() &&
if (last_op_as_set && same_expression_var(last_op_as_set->dst(), var_to_get) &&
(first || last_op_as_set->info().is_compactable)) {
default_result.pop_back();
auto as_one =