fix use def issues (#629)

This commit is contained in:
water111
2021-06-26 16:31:38 -04:00
committed by GitHub
parent 1ffd42e090
commit ae2666a7c5
7 changed files with 126 additions and 18 deletions
+16
View File
@@ -1593,6 +1593,8 @@ class Form {
std::vector<FormElement*> m_elements;
};
class CfgVtx;
/*!
* A FormPool is used to allocate forms and form elements.
* It will clean up everything when it is destroyed.
@@ -1640,11 +1642,25 @@ class FormPool {
return form;
}
Form* lookup_cached_conversion(const CfgVtx* vtx) const {
auto it = m_vtx_to_form_cache.find(vtx);
if (it == m_vtx_to_form_cache.end()) {
return nullptr;
}
return it->second;
}
void cache_conversion(const CfgVtx* vtx, Form* form) {
assert(m_vtx_to_form_cache.find(vtx) == m_vtx_to_form_cache.end());
m_vtx_to_form_cache[vtx] = form;
}
~FormPool();
private:
std::vector<Form*> m_forms;
std::vector<FormElement*> m_elements;
std::unordered_map<const CfgVtx*, Form*> m_vtx_to_form_cache;
};
std::optional<SimpleAtom> form_element_as_atom(const FormElement* f);
+16 -6
View File
@@ -2229,6 +2229,7 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
x->push_to_stack(env, pool, stack);
}
RegisterAccess write_as_value = final_destination;
bool first = true;
for (auto& entry : entries) {
for (auto form : {entry.condition, entry.body}) {
@@ -2243,8 +2244,15 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
}
std::vector<FormElement*> new_entries;
if (form == entry.body && used_as_value) {
new_entries = rewrite_to_get_var(temp_stack, pool, final_destination, env);
// try to advance us to the real write so we don't use the final_destination,
// which may contain the wrong variable, but right register.
std::optional<RegisterAccess> written_var;
new_entries = rewrite_to_get_var(temp_stack, pool, final_destination, env, &written_var);
if (written_var) {
write_as_value = *written_var;
}
} else {
new_entries = temp_stack.rewrite(pool, env);
}
@@ -2259,7 +2267,7 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack&
if (used_as_value) {
// TODO - is this wrong?
stack.push_value_to_reg(final_destination, pool.alloc_single_form(nullptr, this), true,
stack.push_value_to_reg(write_as_value, pool.alloc_single_form(nullptr, this), true,
env.get_variable_type(final_destination, false));
} else {
stack.push_form_element(this, true);
@@ -2386,10 +2394,12 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
if (rewrite_as_set && !set_unused) {
// might not be the same if a set is eliminated by a coloring move.
// assert(dest_sets.size() == write_output_forms.size());
for (size_t i = 0; i < dest_sets.size() - 1; i++) {
auto var = dest_sets.at(i)->dst();
auto* env2 = const_cast<Env*>(&env);
env2->disable_def(var, env2->func->warnings);
if (!dest_sets.empty()) {
for (size_t i = 0; i < dest_sets.size() - 1; i++) {
auto var = dest_sets.at(i)->dst();
auto* env2 = const_cast<Env*>(&env);
env2->disable_def(var, env2->func->warnings);
}
}
}
+14 -6
View File
@@ -350,14 +350,15 @@ std::vector<FormElement*> FormStack::rewrite(FormPool& pool, const Env& env) con
return result;
}
void rewrite_to_get_var(std::vector<FormElement*>& default_result,
FormPool& pool,
const RegisterAccess& var,
const Env& env) {
std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& default_result,
FormPool& pool,
const RegisterAccess& var,
const Env& env) {
bool keep_going = true;
RegisterAccess var_to_get = var;
std::vector<FormElement*> result;
std::optional<RegisterAccess> result_access;
bool first = true;
while (keep_going && !default_result.empty()) {
@@ -386,26 +387,33 @@ void rewrite_to_get_var(std::vector<FormElement*>& default_result,
} else {
result = last_op_as_set->src()->elts();
}
result_access = last_op_as_set->dst();
}
first = false;
}
if (result.empty()) {
default_result.push_back(pool.alloc_element<SimpleAtomElement>(SimpleAtom::make_var(var)));
return {};
} else {
for (auto x : result) {
x->parent_form = nullptr;
default_result.push_back(x);
}
return result_access;
}
}
std::vector<FormElement*> rewrite_to_get_var(FormStack& stack,
FormPool& pool,
const RegisterAccess& var,
const Env& env) {
const Env& env,
std::optional<RegisterAccess>* used_var) {
auto default_result = stack.rewrite(pool, env);
rewrite_to_get_var(default_result, pool, var, env);
auto uv = rewrite_to_get_var(default_result, pool, var, env);
if (used_var) {
*used_var = uv;
}
return default_result;
}
+6 -5
View File
@@ -68,12 +68,13 @@ class FormStack {
bool m_is_root_stack = false;
};
void rewrite_to_get_var(std::vector<FormElement*>& default_result,
FormPool& pool,
const RegisterAccess& var,
const Env& env);
std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& default_result,
FormPool& pool,
const RegisterAccess& var,
const Env& env);
std::vector<FormElement*> rewrite_to_get_var(FormStack& stack,
FormPool& pool,
const RegisterAccess& var,
const Env& env);
const Env& env,
std::optional<RegisterAccess>* used_var = nullptr);
} // namespace decompiler
+8
View File
@@ -1653,11 +1653,19 @@ Form* cfg_to_ir_helper(FormPool& pool, Function& f, const CfgVtx* vtx) {
}
Form* cfg_to_ir(FormPool& pool, Function& f, const CfgVtx* vtx) {
// we cache these because some functions will do a conversion, give up, and throw away the result.
// converting multiple times means that env-modifications will happen multiple times.
auto cached = pool.lookup_cached_conversion(vtx);
if (cached) {
return cached;
}
Form* result = cfg_to_ir_helper(pool, f, vtx);
if (vtx->needs_label) {
result->elts().insert(result->elts().begin(),
pool.alloc_element<LabelElement>(vtx->get_first_block_id()));
}
pool.cache_conversion(vtx, result);
return result;
}
@@ -149,7 +149,6 @@
)
;; definition for function file-info-correct-version?
;; WARN: disable def twice: 16. This may happen when a cond (no else) is nested inside of another conditional, but it should be rare.
(defun
file-info-correct-version?
((info file-info) (kind file-kind) (version-override int))
@@ -1316,4 +1316,70 @@ TEST_F(FormRegressionTest, SoundNameEqual) {
std::string type = "(function sound-name sound-name symbol)";
std::string expected = "(and (= arg0 arg1) (= (-> arg0 hi) (-> arg1 hi)))";
test_with_expr(func, type, expected);
}
TEST_F(FormRegressionTest, DebugMenuFuncDecode) {
std::string func =
"sll r0, r0, 0\n"
" dsll32 v1, a0, 29\n"
" beql v1, r0, L203\n"
" lw v1, binteger(s7)\n"
" bgtzl v1, L203\n"
" lw v1, pair(s7)\n"
" lwu v1, -4(a0)\n"
"L203:\n"
" lw a1, symbol(s7)\n"
" dsubu a1, v1, a1\n"
" daddiu a2, s7, 8\n"
" movn a2, s7, a1\n"
" bnel s7, a2, L204\n"
" or a1, a2, r0\n"
" lw a1, type(s7)\n"
" dsubu a2, v1, a1\n"
" daddiu a1, s7, 8\n"
" movn a1, s7, a2\n"
"L204:\n"
" beq s7, a1, L205\n"
" sll r0, r0, 0\n"
" lw v0, 0(a0)\n"
" beq r0, r0, L207\n"
" sll r0, r0, 0\n"
"L205:\n"
" lw a1, function(s7)\n"
" bne v1, a1, L206\n"
" sll r0, r0, 0\n"
" or v0, a0, r0\n"
" beq r0, r0, L207\n"
" sll r0, r0, 0\n"
"L206:\n"
" lw v0, nothing(s7)\n"
"L207:\n"
" jr ra\n"
" daddu sp, sp, r0";
std::string type = "(function object function)";
std::string expected =
"(let ((v1-1 (rtype-of arg0)))\n"
" (the-as function (cond\n"
" ((or (= v1-1 symbol) (= v1-1 type))\n"
" (-> (the-as symbol arg0) value)\n"
" )\n"
" ((= v1-1 function)\n"
" arg0\n"
" )\n"
" (else\n"
" nothing\n"
" )\n"
" )\n"
" )\n"
" )";
test_with_expr(func, type, expected, false, "", {}, "[[13, \"a0\", \"symbol\"]]");
}