mirror of
https://github.com/open-goal/jak-project
synced 2026-06-29 03:31:21 -04:00
[Decompiler] WIP: Stack Spills (#382)
* set up types * cleaned up type analysis and got things working through atomic ops * expression working, need types * improved types and names * getting close * finish up dma-disasm * fix
This commit is contained in:
@@ -308,8 +308,8 @@ bool is_uint_type(const Env& env, int my_idx, RegisterAccess var) {
|
||||
|
||||
bool is_ptr_or_child(const Env& env, int my_idx, RegisterAccess var, bool) {
|
||||
// Now that decompiler types are synced up properly, we don't want this.
|
||||
// auto type = as_var ? env.get_variable_type(var, true).base_type()
|
||||
// : env.get_types_before_op(my_idx).get(var.reg()).typespec().base_type();
|
||||
// auto type = as_var ? env.get_variable_type(var, true).base_type()
|
||||
// : env.get_types_before_op(my_idx).get(var.reg()).typespec().base_type();
|
||||
auto type = env.get_types_before_op(my_idx).get(var.reg()).typespec().base_type();
|
||||
return type == "pointer";
|
||||
}
|
||||
@@ -603,7 +603,7 @@ void SimpleExpressionElement::update_from_stack_add_i(const Env& env,
|
||||
args.push_back(pool.alloc_single_element_form<SimpleAtomElement>(nullptr, m_expr.get_arg(1)));
|
||||
}
|
||||
|
||||
bool arg0_ptr = is_ptr_or_child(env, m_my_idx, m_expr.get_arg(0).var(), is_var(args.at(0)));
|
||||
bool arg0_ptr = is_ptr_or_child(env, m_my_idx, m_expr.get_arg(0).var(), true);
|
||||
|
||||
// Look for getting an address inside of an object.
|
||||
// (+ <integer 108 + int> process). array style access with a stride of 1.
|
||||
@@ -943,7 +943,7 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||
}
|
||||
|
||||
BitfieldManip step(manip_kind, m_expr.get_arg(1).get_int());
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
if (other) {
|
||||
result->push_back(other);
|
||||
} else {
|
||||
@@ -983,7 +983,7 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||
assert(false);
|
||||
}
|
||||
BitfieldManip step(manip_kind, arg1_atom->get_int());
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(!other); // shouldn't be complete.
|
||||
result->push_back(read_elt);
|
||||
return;
|
||||
@@ -997,7 +997,7 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||
assert(false);
|
||||
}
|
||||
auto step = BitfieldManip::from_form(manip_kind, stripped_arg1);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
if (other) {
|
||||
result->push_back(other);
|
||||
} else {
|
||||
@@ -1066,7 +1066,7 @@ void SimpleExpressionElement::update_from_stack_left_shift(const Env& env,
|
||||
auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
BitfieldManip step(BitfieldManip::Kind::LEFT_SHIFT, m_expr.get_arg(1).get_int());
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(!other); // shouldn't be complete.
|
||||
result->push_back(read_elt);
|
||||
} else {
|
||||
@@ -1087,7 +1087,7 @@ void SimpleExpressionElement::update_from_stack_right_shift_logic(const Env& env
|
||||
auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_LOGICAL, m_expr.get_arg(1).get_int());
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should be a high field.
|
||||
result->push_back(other);
|
||||
} else {
|
||||
@@ -1100,7 +1100,7 @@ void SimpleExpressionElement::update_from_stack_right_shift_logic(const Env& env
|
||||
|
||||
if (as_bitfield_access) {
|
||||
BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_LOGICAL, m_expr.get_arg(1).get_int());
|
||||
auto next = as_bitfield_access->push_step(step, env.dts->ts, pool);
|
||||
auto next = as_bitfield_access->push_step(step, env.dts->ts, pool, env);
|
||||
if (next) {
|
||||
result->push_back(next);
|
||||
} else {
|
||||
@@ -1139,7 +1139,7 @@ void SimpleExpressionElement::update_from_stack_right_shift_arith(const Env& env
|
||||
auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_ARITH, m_expr.get_arg(1).get_int());
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should be a high field.
|
||||
result->push_back(other);
|
||||
} else {
|
||||
@@ -2068,6 +2068,12 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
|
||||
form->push_back(stack.pop_back(pool));
|
||||
} else {
|
||||
FormStack temp_stack(false);
|
||||
if (form == entry.body) {
|
||||
auto as_setvar = dynamic_cast<SetVarElement*>(form->elts().back());
|
||||
if (as_setvar && as_setvar->is_dead_set() && as_setvar->src_type() != TypeSpec("float")) {
|
||||
rewrite_as_set = false;
|
||||
}
|
||||
}
|
||||
for (auto& elt : form->elts()) {
|
||||
elt->push_to_stack(env, pool, temp_stack);
|
||||
}
|
||||
@@ -2119,8 +2125,9 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac
|
||||
source_types.push_back(last_in_body->src_type());
|
||||
}
|
||||
last_var = last_in_body->dst();
|
||||
} // For now, I am fine with letting this fail. For example, if the set is eliminated by a
|
||||
// coloring move. If this makes really ugly code later on, we could use this to disable
|
||||
}
|
||||
// For now, I am fine with letting this fail. For example, if the set is eliminated by a
|
||||
// coloring move. If this makes really ugly code later on, we could use this to disable
|
||||
// write as set.
|
||||
}
|
||||
|
||||
@@ -2320,7 +2327,7 @@ FormElement* ConditionElement::make_nonzero_check_generic(const Env& env,
|
||||
dynamic_cast<BitfieldAccessElement*>(source_forms.at(0)->try_as_single_element());
|
||||
if (as_bitfield_op) {
|
||||
bitfield_compare = as_bitfield_op->push_step(
|
||||
BitfieldManip(BitfieldManip::Kind::NONZERO_COMPARE, 0), env.dts->ts, pool);
|
||||
BitfieldManip(BitfieldManip::Kind::NONZERO_COMPARE, 0), env.dts->ts, pool, env);
|
||||
}
|
||||
|
||||
if (bitfield_compare) {
|
||||
@@ -2698,7 +2705,7 @@ void push_asm_srl_to_stack(const AsmOp* op,
|
||||
auto base = pop_to_forms({*var}, env, pool, stack, true).at(0);
|
||||
auto read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
||||
BitfieldManip step(BitfieldManip::Kind::RIGHT_SHIFT_LOGICAL_32BIT, integer);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool);
|
||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||
assert(other); // should be a high field.
|
||||
stack.push_value_to_reg(*dst, pool.alloc_single_form(nullptr, other), true,
|
||||
env.get_variable_type(*dst, true));
|
||||
@@ -2740,6 +2747,7 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool& pool, FormStack& s
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Can't push atomic op to stack: " + m_op->to_string(env));
|
||||
}
|
||||
|
||||
@@ -3079,6 +3087,20 @@ void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool,
|
||||
true, TypeSpec("symbol"));
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// StackSpillStoreElement
|
||||
///////////////////////////
|
||||
void StackSpillStoreElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
mark_popped();
|
||||
auto src = pop_to_forms({m_value}, env, pool, stack, true).at(0);
|
||||
auto dst = pool.alloc_single_element_form<ConstantTokenElement>(
|
||||
nullptr, env.get_spill_slot_var_name(m_stack_offset));
|
||||
if (m_cast_type) {
|
||||
src = cast_form(src, *m_cast_type, pool, env);
|
||||
}
|
||||
stack.push_form_element(pool.alloc_element<SetFormFormElement>(dst, src), true);
|
||||
}
|
||||
|
||||
void VectorFloatLoadStoreElement::push_to_stack(const Env&, FormPool&, FormStack& stack) {
|
||||
mark_popped();
|
||||
stack.push_form_element(this, true);
|
||||
@@ -3147,4 +3169,13 @@ void StackVarDefElement::update_from_stack(const Env&,
|
||||
result->push_back(this);
|
||||
}
|
||||
|
||||
void StackSpillValueElement::update_from_stack(const Env&,
|
||||
FormPool&,
|
||||
FormStack&,
|
||||
std::vector<FormElement*>* result,
|
||||
bool) {
|
||||
mark_popped();
|
||||
result->push_back(this);
|
||||
}
|
||||
|
||||
} // namespace decompiler
|
||||
|
||||
Reference in New Issue
Block a user