mirror of
https://github.com/open-goal/jak-project.git
synced 2024-10-20 11:26:18 -04:00
get res decompiling (#705)
This commit is contained in:
parent
e7bc3eb3b0
commit
2754a8f2c4
|
@ -187,13 +187,13 @@ TP_Type SimpleExpression::get_type(const TypeState& input,
|
||||||
case Kind::XOR:
|
case Kind::XOR:
|
||||||
case Kind::LEFT_SHIFT:
|
case Kind::LEFT_SHIFT:
|
||||||
case Kind::MUL_UNSIGNED:
|
case Kind::MUL_UNSIGNED:
|
||||||
|
case Kind::PCPYLD:
|
||||||
return get_type_int2(input, env, dts);
|
return get_type_int2(input, env, dts);
|
||||||
case Kind::NEG:
|
case Kind::NEG:
|
||||||
case Kind::LOGNOT:
|
case Kind::LOGNOT:
|
||||||
return get_type_int1(input, env, dts);
|
return get_type_int1(input, env, dts);
|
||||||
case Kind::DIV_UNSIGNED:
|
case Kind::DIV_UNSIGNED:
|
||||||
case Kind::MOD_UNSIGNED:
|
case Kind::MOD_UNSIGNED:
|
||||||
case Kind::PCPYLD:
|
|
||||||
return TP_Type::make_from_ts("uint");
|
return TP_Type::make_from_ts("uint");
|
||||||
case Kind::VECTOR_PLUS:
|
case Kind::VECTOR_PLUS:
|
||||||
case Kind::VECTOR_MINUS:
|
case Kind::VECTOR_MINUS:
|
||||||
|
@ -427,6 +427,21 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (arg0_type.kind == TP_Type::Kind::PCPYUD_BITFIELD &&
|
||||||
|
(m_kind == Kind::AND || m_kind == Kind::OR)) {
|
||||||
|
// anding a bitfield should return the bitfield type.
|
||||||
|
return TP_Type::make_from_pcpyud_bitfield(arg0_type.get_bitfield_type());
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is right but breaks something else right now.
|
||||||
|
if (m_kind == Kind::PCPYLD && arg0_type.kind == TP_Type::Kind::PCPYUD_BITFIELD) {
|
||||||
|
return arg1_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_kind == Kind::PCPYLD) {
|
||||||
|
return TP_Type::make_from_ts("uint");
|
||||||
|
}
|
||||||
|
|
||||||
if (arg0_type.kind == TP_Type::Kind::INTEGER_CONSTANT_PLUS_VAR_MULT && m_kind == Kind::ADD) {
|
if (arg0_type.kind == TP_Type::Kind::INTEGER_CONSTANT_PLUS_VAR_MULT && m_kind == Kind::ADD) {
|
||||||
FieldReverseLookupInput rd_in;
|
FieldReverseLookupInput rd_in;
|
||||||
rd_in.offset = arg0_type.get_add_int_constant();
|
rd_in.offset = arg0_type.get_add_int_constant();
|
||||||
|
|
|
@ -82,6 +82,7 @@ class Env {
|
||||||
VariableWithCast get_variable_and_cast(const RegisterAccess& access) const;
|
VariableWithCast get_variable_and_cast(const RegisterAccess& access) const;
|
||||||
std::optional<TypeSpec> get_user_cast_for_access(const RegisterAccess& access) const;
|
std::optional<TypeSpec> get_user_cast_for_access(const RegisterAccess& access) const;
|
||||||
TypeSpec get_variable_type(const RegisterAccess& access, bool using_user_var_types) const;
|
TypeSpec get_variable_type(const RegisterAccess& access, bool using_user_var_types) const;
|
||||||
|
TP_Type get_variable_tp_type(const RegisterAccess& access, bool using_user_var_types) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Get the types in registers _after_ the given operation has completed.
|
* Get the types in registers _after_ the given operation has completed.
|
||||||
|
|
|
@ -1904,10 +1904,11 @@ void GenericElement::get_modified_regs(RegSet& regs) const {
|
||||||
|
|
||||||
CastElement::CastElement(TypeSpec type, Form* source, bool numeric)
|
CastElement::CastElement(TypeSpec type, Form* source, bool numeric)
|
||||||
: m_type(std::move(type)), m_source(source), m_numeric(numeric) {
|
: m_type(std::move(type)), m_source(source), m_numeric(numeric) {
|
||||||
source->parent_element = this;
|
m_source->parent_element = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
goos::Object CastElement::to_form_internal(const Env& env) const {
|
goos::Object CastElement::to_form_internal(const Env& env) const {
|
||||||
|
// assert(m_source->parent_element == this);
|
||||||
auto atom = form_as_atom(m_source);
|
auto atom = form_as_atom(m_source);
|
||||||
if (atom && atom->is_var()) {
|
if (atom && atom->is_var()) {
|
||||||
return pretty_print::build_list(
|
return pretty_print::build_list(
|
||||||
|
@ -1919,21 +1920,25 @@ goos::Object CastElement::to_form_internal(const Env& env) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CastElement::apply(const std::function<void(FormElement*)>& f) {
|
void CastElement::apply(const std::function<void(FormElement*)>& f) {
|
||||||
|
// assert(m_source->parent_element == this);
|
||||||
f(this);
|
f(this);
|
||||||
m_source->apply(f);
|
m_source->apply(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CastElement::apply_form(const std::function<void(Form*)>& f) {
|
void CastElement::apply_form(const std::function<void(Form*)>& f) {
|
||||||
|
// assert(m_source->parent_element == this);
|
||||||
m_source->apply_form(f);
|
m_source->apply_form(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CastElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
void CastElement::collect_vars(RegAccessSet& vars, bool recursive) const {
|
||||||
|
// assert(m_source->parent_element == this);
|
||||||
if (recursive) {
|
if (recursive) {
|
||||||
m_source->collect_vars(vars, recursive);
|
m_source->collect_vars(vars, recursive);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CastElement::get_modified_regs(RegSet& regs) const {
|
void CastElement::get_modified_regs(RegSet& regs) const {
|
||||||
|
assert(m_source->parent_element == this);
|
||||||
m_source->get_modified_regs(regs);
|
m_source->get_modified_regs(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,10 @@ class FormElement {
|
||||||
bool allow_side_effects);
|
bool allow_side_effects);
|
||||||
bool is_popped() const { return m_popped; }
|
bool is_popped() const { return m_popped; }
|
||||||
|
|
||||||
|
FormElement() = default;
|
||||||
|
FormElement(const FormElement& other) = delete;
|
||||||
|
FormElement& operator=(const FormElement& other) = delete;
|
||||||
|
|
||||||
void mark_popped() {
|
void mark_popped() {
|
||||||
assert(!m_popped);
|
assert(!m_popped);
|
||||||
m_popped = true;
|
m_popped = true;
|
||||||
|
|
|
@ -1113,6 +1113,29 @@ void SimpleExpressionElement::update_from_stack_pcypld(const Env& env,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pcpyud v1, s4, r0
|
||||||
|
ld a0, L152(fp)
|
||||||
|
and v1, v1, a0
|
||||||
|
lui a0, 1
|
||||||
|
dsll32 a0, a0, 0
|
||||||
|
or v1, v1, a0
|
||||||
|
pcpyld v1, v1, s4
|
||||||
|
por s4, v1, r0
|
||||||
|
*/
|
||||||
|
|
||||||
|
auto as_mod = args.at(0)->try_as_element<ModifiedCopyBitfieldElement>();
|
||||||
|
if (as_mod && as_mod->from_pcpyud()) {
|
||||||
|
auto base_form = as_mod->base()->to_form(env);
|
||||||
|
auto a1_form = args.at(1)->to_form(env);
|
||||||
|
if (base_form == a1_form) {
|
||||||
|
as_mod->clear_pcpyud_flag();
|
||||||
|
result->push_back(as_mod);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
fmt::print("pcpyud rewrite form fail: {} {}\n", base_form.print(), a1_form.print());
|
||||||
|
}
|
||||||
|
}
|
||||||
auto new_form = pool.alloc_element<GenericElement>(
|
auto new_form = pool.alloc_element<GenericElement>(
|
||||||
GenericOperator::make_fixed(FixedOperatorKind::PCPYLD), args.at(0), args.at(1));
|
GenericOperator::make_fixed(FixedOperatorKind::PCPYLD), args.at(0), args.at(1));
|
||||||
result->push_back(new_form);
|
result->push_back(new_form);
|
||||||
|
@ -1262,16 +1285,45 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||||
FormStack& stack,
|
FormStack& stack,
|
||||||
std::vector<FormElement*>* result,
|
std::vector<FormElement*>* result,
|
||||||
bool allow_side_effects) {
|
bool allow_side_effects) {
|
||||||
|
// grab the normal variable type
|
||||||
auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true);
|
auto arg0_type = env.get_variable_type(m_expr.get_arg(0).var(), true);
|
||||||
|
|
||||||
|
// and try to get it as a bitfield
|
||||||
auto type_info = env.dts->ts.lookup_type(arg0_type);
|
auto type_info = env.dts->ts.lookup_type(arg0_type);
|
||||||
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
auto bitfield_info = dynamic_cast<BitFieldType*>(type_info);
|
||||||
|
bool had_pcpyud = false;
|
||||||
|
TypeSpec bitfield_type = arg0_type;
|
||||||
|
|
||||||
|
if (!bitfield_info) {
|
||||||
|
// the above won't work if we're already done a pcpyud to grab the upper 64 bits.
|
||||||
|
// we need to grab the type in the register (a TP_type) and check
|
||||||
|
const auto& arg0_reg_type =
|
||||||
|
env.get_types_before_op(m_expr.get_arg(0).var().idx()).get(m_expr.get_arg(0).var().reg());
|
||||||
|
if (arg0_reg_type.kind == TP_Type::Kind::PCPYUD_BITFIELD) {
|
||||||
|
// yes!
|
||||||
|
had_pcpyud = true;
|
||||||
|
bitfield_info =
|
||||||
|
dynamic_cast<BitFieldType*>(env.dts->ts.lookup_type(arg0_reg_type.get_bitfield_type()));
|
||||||
|
assert(bitfield_info);
|
||||||
|
} else if (arg0_reg_type.kind == TP_Type::Kind::PCPYUD_BITFIELD_AND) {
|
||||||
|
// already have the pcpyud in the thing.
|
||||||
|
bitfield_info =
|
||||||
|
dynamic_cast<BitFieldType*>(env.dts->ts.lookup_type(arg0_reg_type.get_bitfield_type()));
|
||||||
|
assert(bitfield_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (bitfield_info && m_expr.get_arg(1).is_int()) {
|
if (bitfield_info && m_expr.get_arg(1).is_int()) {
|
||||||
// andi, ori with bitfield.
|
// andi, ori with bitfield.
|
||||||
auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0);
|
||||||
auto read_elt = dynamic_cast<BitfieldAccessElement*>(base->try_as_single_element());
|
auto read_elt = dynamic_cast<BitfieldAccessElement*>(base->try_as_single_element());
|
||||||
if (!read_elt) {
|
if (!read_elt) {
|
||||||
read_elt = pool.alloc_element<BitfieldAccessElement>(base, arg0_type);
|
read_elt = pool.alloc_element<BitfieldAccessElement>(base, bitfield_type);
|
||||||
|
assert(!had_pcpyud);
|
||||||
|
} else {
|
||||||
|
if (had_pcpyud) {
|
||||||
|
assert(read_elt->has_pcpyud());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BitfieldManip::Kind manip_kind;
|
BitfieldManip::Kind manip_kind;
|
||||||
|
@ -1313,13 +1365,19 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||||
bool made_new_read_elt = false;
|
bool made_new_read_elt = false;
|
||||||
auto read_elt = dynamic_cast<BitfieldAccessElement*>(args.at(0)->try_as_single_element());
|
auto read_elt = dynamic_cast<BitfieldAccessElement*>(args.at(0)->try_as_single_element());
|
||||||
if (!read_elt) {
|
if (!read_elt) {
|
||||||
read_elt = pool.alloc_element<BitfieldAccessElement>(args.at(0), arg0_type);
|
read_elt = pool.alloc_element<BitfieldAccessElement>(args.at(0), bitfield_type);
|
||||||
made_new_read_elt = true;
|
made_new_read_elt = true;
|
||||||
|
assert(!had_pcpyud);
|
||||||
|
} else {
|
||||||
|
if (had_pcpyud) {
|
||||||
|
assert(read_elt->has_pcpyud());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto stripped_arg1 = strip_int_or_uint_cast(args.at(1));
|
auto stripped_arg1 = strip_int_or_uint_cast(args.at(1));
|
||||||
auto arg1_atom = form_as_atom(strip_int_or_uint_cast(args.at(1)));
|
// auto arg1_atom = form_as_atom(strip_int_or_uint_cast(args.at(1)));
|
||||||
if (arg1_atom && arg1_atom->is_int()) {
|
auto arg1_as_int = get_goal_integer_constant(stripped_arg1, env);
|
||||||
|
if (arg1_as_int) {
|
||||||
BitfieldManip::Kind manip_kind;
|
BitfieldManip::Kind manip_kind;
|
||||||
if (kind == FixedOperatorKind::LOGAND) {
|
if (kind == FixedOperatorKind::LOGAND) {
|
||||||
manip_kind = BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT;
|
manip_kind = BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT;
|
||||||
|
@ -1328,10 +1386,14 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env,
|
||||||
} else {
|
} else {
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
BitfieldManip step(manip_kind, arg1_atom->get_int());
|
BitfieldManip step(manip_kind, *arg1_as_int);
|
||||||
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
auto other = read_elt->push_step(step, env.dts->ts, pool, env);
|
||||||
assert(!other); // shouldn't be complete.
|
// assert(!other); // shouldn't be complete.
|
||||||
|
if (other) {
|
||||||
|
result->push_back(other);
|
||||||
|
} else {
|
||||||
result->push_back(read_elt);
|
result->push_back(read_elt);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
} else if (!made_new_read_elt) {
|
} else if (!made_new_read_elt) {
|
||||||
BitfieldManip::Kind manip_kind;
|
BitfieldManip::Kind manip_kind;
|
||||||
|
@ -1847,6 +1909,13 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bool skip = false;
|
||||||
|
// auto dst_type = env.get_variable_type(m_dst, false);
|
||||||
|
// auto as_bitfield = dynamic_cast<BitFieldType*>(env.dts->ts.lookup_type(dst_type));
|
||||||
|
// if (as_bitfield && as_bitfield->get_load_size() == 16) {
|
||||||
|
// skip = true;
|
||||||
|
// }
|
||||||
|
|
||||||
// if we are a reg-reg move that consumes the original, push it without popping from stack.
|
// 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.
|
// it is the Stack's responsibility to untangle these later on.
|
||||||
if (m_src->is_single_element()) {
|
if (m_src->is_single_element()) {
|
||||||
|
@ -1874,6 +1943,28 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||||
// we aren't a reg-reg move, so update our source
|
// we aren't a reg-reg move, so update our source
|
||||||
m_src->update_children_from_stack(env, pool, stack, true);
|
m_src->update_children_from_stack(env, pool, stack, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
auto src_as_bf_set = dynamic_cast<ModifiedCopyBitfieldElement*>(m_src->try_as_single_element());
|
||||||
|
if (src_as_bf_set && !src_as_bf_set->from_pcpyud() && src_as_bf_set->mods().size() == 1) {
|
||||||
|
auto dst_form = m_dst.to_form(env, RegisterAccess::Print::AS_VARIABLE_NO_CAST);
|
||||||
|
auto src_form = src_as_bf_set->base()->to_form(env);
|
||||||
|
if (dst_form == src_form) {
|
||||||
|
// success!
|
||||||
|
auto value = src_as_bf_set->mods().at(0).value;
|
||||||
|
value->parent_element = this;
|
||||||
|
|
||||||
|
// make the (-> thing bitfield)
|
||||||
|
auto field_token = DerefToken::make_field_name(src_as_bf_set->mods().at(0).field_name);
|
||||||
|
auto dst_dform = pool.alloc_single_element_form<SimpleAtomElement>(nullptr,
|
||||||
|
SimpleAtom::make_var(m_dst)); auto loc_elt = pool.alloc_element<DerefElement>(dst_dform, false,
|
||||||
|
field_token); loc_elt->inline_nested(); auto loc = pool.alloc_single_form(nullptr, loc_elt); auto
|
||||||
|
new_form_el = pool.alloc_element<SetFormFormElement>(loc, value);
|
||||||
|
stack.push_form_element(new_form_el, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
for (auto x : m_src->elts()) {
|
for (auto x : m_src->elts()) {
|
||||||
assert(x->parent_form == m_src);
|
assert(x->parent_form == m_src);
|
||||||
}
|
}
|
||||||
|
@ -1915,7 +2006,7 @@ void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack
|
||||||
|
|
||||||
// check for bitfield setting:
|
// check for bitfield setting:
|
||||||
auto src_as_bf_set = dynamic_cast<ModifiedCopyBitfieldElement*>(m_src->try_as_single_element());
|
auto src_as_bf_set = dynamic_cast<ModifiedCopyBitfieldElement*>(m_src->try_as_single_element());
|
||||||
if (src_as_bf_set && src_as_bf_set->mods().size() == 1) {
|
if (src_as_bf_set && !src_as_bf_set->from_pcpyud() && src_as_bf_set->mods().size() == 1) {
|
||||||
auto dst_form = m_dst->to_form(env);
|
auto dst_form = m_dst->to_form(env);
|
||||||
auto src_form = src_as_bf_set->base()->to_form(env);
|
auto src_form = src_as_bf_set->base()->to_form(env);
|
||||||
if (dst_form == src_form) {
|
if (dst_form == src_form) {
|
||||||
|
@ -1933,6 +2024,8 @@ void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack
|
||||||
m_dst = loc;
|
m_dst = loc;
|
||||||
m_src = value;
|
m_src = value;
|
||||||
}
|
}
|
||||||
|
} else if (src_as_bf_set) {
|
||||||
|
fmt::print("invalid bf set: {}\n", src_as_bf_set->to_string(env));
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.push_form_element(this, true);
|
stack.push_form_element(this, true);
|
||||||
|
@ -2314,15 +2407,20 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
||||||
"type.");
|
"type.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!env.dts->ts.should_use_virtual_methods(tp_type.method_from_type(),
|
bool is_res_lump = tp_type.method_from_type().base_type() == "res-lump";
|
||||||
tp_type.method_id())) {
|
bool should_use_virtual =
|
||||||
|
env.dts->ts.should_use_virtual_methods(tp_type.method_from_type(), tp_type.method_id());
|
||||||
|
|
||||||
|
if (!should_use_virtual && !is_res_lump) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
fmt::format("Method call on {} id {} used a virtual call unexpectedly.",
|
fmt::format("Method call on {} id {} used a virtual call unexpectedly.",
|
||||||
tp_type.method_from_type().print(), tp_type.method_id()));
|
tp_type.method_from_type().print(), tp_type.method_id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (should_use_virtual) {
|
||||||
// fmt::print("STACK\n{}\n\n", stack.print(env));
|
// fmt::print("STACK\n{}\n\n", stack.print(env));
|
||||||
auto pop =
|
auto pop = pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects,
|
||||||
pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects, {}, {2})
|
{}, {2})
|
||||||
.at(0);
|
.at(0);
|
||||||
// fmt::print("GOT: {}\n", pop->to_string(env));
|
// fmt::print("GOT: {}\n", pop->to_string(env));
|
||||||
arg_forms.at(0) = pop;
|
arg_forms.at(0) = pop;
|
||||||
|
@ -2334,6 +2432,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
new_form = pool.alloc_element<GenericElement>(GenericOperator::make_function(unstacked.at(0)),
|
new_form = pool.alloc_element<GenericElement>(GenericOperator::make_function(unstacked.at(0)),
|
||||||
arg_forms);
|
arg_forms);
|
||||||
|
@ -3525,9 +3624,11 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<FormElement*> new_entries;
|
std::vector<FormElement*> new_entries;
|
||||||
new_entries = rewrite_to_get_var(temp_stack, pool, env.end_var(), env);
|
std::optional<RegisterAccess> var;
|
||||||
|
new_entries = rewrite_to_get_var(temp_stack, pool, env.end_var(), env, &var);
|
||||||
|
|
||||||
assert(!new_entries.empty());
|
assert(!new_entries.empty());
|
||||||
|
|
||||||
return_code->clear();
|
return_code->clear();
|
||||||
|
|
||||||
for (int i = 0; i < ((int)new_entries.size()) - 1; i++) {
|
for (int i = 0; i < ((int)new_entries.size()) - 1; i++) {
|
||||||
|
@ -3535,6 +3636,20 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta
|
||||||
}
|
}
|
||||||
|
|
||||||
return_code->push_back(new_entries.back());
|
return_code->push_back(new_entries.back());
|
||||||
|
if (var) {
|
||||||
|
const auto& func_type = env.func->type.last_arg();
|
||||||
|
if (!env.dts->ts.tc(func_type, env.get_variable_type(*var, false))) {
|
||||||
|
auto as_cast = return_code->try_as_element<CastElement>();
|
||||||
|
if (as_cast) {
|
||||||
|
return_code->clear();
|
||||||
|
as_cast->set_type(func_type);
|
||||||
|
return_code->push_back(as_cast);
|
||||||
|
} else {
|
||||||
|
return_code = cast_form(return_code, func_type, pool, env);
|
||||||
|
return_code->parent_element = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
stack.push_form_element(this, true);
|
stack.push_form_element(this, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -349,9 +349,9 @@ std::vector<FormElement*> FormStack::rewrite(FormPool& pool, const Env& env) con
|
||||||
|
|
||||||
auto elt = pool.alloc_element<SetVarElement>(*e.destination, simplified_source,
|
auto elt = pool.alloc_element<SetVarElement>(*e.destination, simplified_source,
|
||||||
e.sequence_point, type, e.set_info);
|
e.sequence_point, type, e.set_info);
|
||||||
e.source->parent_element = elt;
|
|
||||||
|
|
||||||
auto final_elt = try_rewrites_in_place(elt, env, pool);
|
auto final_elt = try_rewrites_in_place(elt, env, pool);
|
||||||
|
simplified_source->parent_element = final_elt;
|
||||||
result.push_back(final_elt);
|
result.push_back(final_elt);
|
||||||
} else {
|
} else {
|
||||||
result.push_back(e.elt);
|
result.push_back(e.elt);
|
||||||
|
@ -411,7 +411,6 @@ std::optional<RegisterAccess> rewrite_to_get_var(std::vector<FormElement*>& defa
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
for (auto x : result) {
|
for (auto x : result) {
|
||||||
x->parent_form = nullptr;
|
|
||||||
default_result.push_back(x);
|
default_result.push_back(x);
|
||||||
}
|
}
|
||||||
return result_access;
|
return result_access;
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "common/util/BitUtils.h"
|
#include "common/util/BitUtils.h"
|
||||||
#include "decompiler/util/DecompilerTypeSystem.h"
|
#include "decompiler/util/DecompilerTypeSystem.h"
|
||||||
#include "decompiler/IR2/GenericElementMatcher.h"
|
#include "decompiler/IR2/GenericElementMatcher.h"
|
||||||
|
#include "decompiler/Function/Function.h"
|
||||||
|
|
||||||
namespace decompiler {
|
namespace decompiler {
|
||||||
|
|
||||||
|
@ -84,8 +85,12 @@ void BitfieldStaticDefElement::get_modified_regs(RegSet& regs) const {
|
||||||
ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement(
|
ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement(
|
||||||
const TypeSpec& type,
|
const TypeSpec& type,
|
||||||
Form* base,
|
Form* base,
|
||||||
|
bool from_pcpyud,
|
||||||
const std::vector<BitFieldDef>& field_modifications)
|
const std::vector<BitFieldDef>& field_modifications)
|
||||||
: m_type(type), m_base(base), m_field_modifications(field_modifications) {
|
: m_type(type),
|
||||||
|
m_base(base),
|
||||||
|
m_field_modifications(field_modifications),
|
||||||
|
m_from_pcpyud(from_pcpyud) {
|
||||||
m_base->parent_element = this;
|
m_base->parent_element = this;
|
||||||
for (auto& mod : m_field_modifications) {
|
for (auto& mod : m_field_modifications) {
|
||||||
if (mod.value) {
|
if (mod.value) {
|
||||||
|
@ -95,13 +100,23 @@ ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement(
|
||||||
}
|
}
|
||||||
|
|
||||||
goos::Object ModifiedCopyBitfieldElement::to_form_internal(const Env& env) const {
|
goos::Object ModifiedCopyBitfieldElement::to_form_internal(const Env& env) const {
|
||||||
std::vector<goos::Object> result = {pretty_print::to_symbol("copy-and-set-bf")};
|
if (m_field_modifications.size() == 1) {
|
||||||
|
std::vector<goos::Object> result = {pretty_print::to_symbol("copy-and-set-field")};
|
||||||
|
result.push_back(m_base->to_form(env));
|
||||||
|
for (auto& def : m_field_modifications) {
|
||||||
|
result.push_back(pretty_print::to_symbol(fmt::format("{}", def.field_name)));
|
||||||
|
result.push_back(def.value->to_form(env));
|
||||||
|
}
|
||||||
|
return pretty_print::build_list(result);
|
||||||
|
} else {
|
||||||
|
std::vector<goos::Object> result = {pretty_print::to_symbol("copy-and-set-bf-multi")};
|
||||||
result.push_back(m_base->to_form(env));
|
result.push_back(m_base->to_form(env));
|
||||||
for (auto& def : m_field_modifications) {
|
for (auto& def : m_field_modifications) {
|
||||||
result.push_back(pretty_print::to_symbol(fmt::format(":{}", def.field_name)));
|
result.push_back(pretty_print::to_symbol(fmt::format(":{}", def.field_name)));
|
||||||
result.push_back(def.value->to_form(env));
|
result.push_back(def.value->to_form(env));
|
||||||
}
|
}
|
||||||
return pretty_print::build_list(result);
|
return pretty_print::build_list(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModifiedCopyBitfieldElement::apply(const std::function<void(FormElement*)>& f) {
|
void ModifiedCopyBitfieldElement::apply(const std::function<void(FormElement*)>& f) {
|
||||||
|
@ -220,7 +235,8 @@ BitField find_field(const TypeSystem& ts,
|
||||||
namespace {
|
namespace {
|
||||||
std::optional<BitField> find_field_from_mask(const TypeSystem& ts,
|
std::optional<BitField> find_field_from_mask(const TypeSystem& ts,
|
||||||
const BitFieldType* type,
|
const BitFieldType* type,
|
||||||
uint64_t mask) {
|
uint64_t mask,
|
||||||
|
bool upper_64) {
|
||||||
// try to find a field that is masked by this:
|
// try to find a field that is masked by this:
|
||||||
auto mask_range = get_bit_range(mask);
|
auto mask_range = get_bit_range(mask);
|
||||||
if (!mask_range) {
|
if (!mask_range) {
|
||||||
|
@ -228,6 +244,10 @@ std::optional<BitField> find_field_from_mask(const TypeSystem& ts,
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (upper_64) {
|
||||||
|
mask_range = Range<int>(mask_range->first() + 64, mask_range->last() + 64);
|
||||||
|
}
|
||||||
|
|
||||||
return find_field(ts, type, mask_range->first(), mask_range->size(), {});
|
return find_field(ts, type, mask_range->first(), mask_range->size(), {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,7 +261,8 @@ Form* strip_int_or_uint_cast(Form* in) {
|
||||||
|
|
||||||
std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||||
const BitFieldType* type,
|
const BitFieldType* type,
|
||||||
const TypeSystem& ts) {
|
const TypeSystem& ts,
|
||||||
|
int offset_in_bitfield) {
|
||||||
// (shr (shl arg1 59) 44) for example
|
// (shr (shl arg1 59) 44) for example
|
||||||
{
|
{
|
||||||
auto matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHR),
|
auto matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHR),
|
||||||
|
@ -255,7 +276,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||||
int right = mr.maps.ints.at(2);
|
int right = mr.maps.ints.at(2);
|
||||||
int size = 64 - left;
|
int size = 64 - left;
|
||||||
int offset = left - right;
|
int offset = left - right;
|
||||||
auto f = find_field(ts, type, offset, size, {});
|
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||||
BitFieldDef def;
|
BitFieldDef def;
|
||||||
def.value = value;
|
def.value = value;
|
||||||
def.field_name = f.name();
|
def.field_name = f.name();
|
||||||
|
@ -278,7 +299,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||||
int right = *power_of_two;
|
int right = *power_of_two;
|
||||||
int size = 64 - left;
|
int size = 64 - left;
|
||||||
int offset = left - right;
|
int offset = left - right;
|
||||||
auto f = find_field(ts, type, offset, size, {});
|
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||||
BitFieldDef def;
|
BitFieldDef def;
|
||||||
def.value = value;
|
def.value = value;
|
||||||
def.field_name = f.name();
|
def.field_name = f.name();
|
||||||
|
@ -298,7 +319,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||||
int right = 0;
|
int right = 0;
|
||||||
int size = 64 - left;
|
int size = 64 - left;
|
||||||
int offset = left - right;
|
int offset = left - right;
|
||||||
auto f = find_field(ts, type, offset, size, {});
|
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||||
BitFieldDef def;
|
BitFieldDef def;
|
||||||
def.value = value;
|
def.value = value;
|
||||||
def.field_name = f.name();
|
def.field_name = f.name();
|
||||||
|
@ -313,7 +334,7 @@ std::optional<BitFieldDef> get_bitfield_initial_set(Form* form,
|
||||||
auto value = mr_sllv.maps.forms.at(0);
|
auto value = mr_sllv.maps.forms.at(0);
|
||||||
int size = 32;
|
int size = 32;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
auto f = find_field(ts, type, offset, size, {});
|
auto f = find_field(ts, type, offset + offset_in_bitfield, size, {});
|
||||||
BitFieldDef def;
|
BitFieldDef def;
|
||||||
def.value = value;
|
def.value = value;
|
||||||
def.field_name = f.name();
|
def.field_name = f.name();
|
||||||
|
@ -345,6 +366,19 @@ void BitfieldAccessElement::push_pcpyud(const TypeSystem& ts, FormPool& pool, co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string BitfieldAccessElement::debug_print(const Env& env) const {
|
||||||
|
std::string result = "BitfieldAccessElement:";
|
||||||
|
if (m_got_pcpyud) {
|
||||||
|
result += "pcpyud";
|
||||||
|
}
|
||||||
|
result += '\n';
|
||||||
|
result += fmt::format("base: {}\n", m_base->to_string(env));
|
||||||
|
for (auto& step : m_steps) {
|
||||||
|
result += fmt::format(" {}\n", step.print());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* Add a step to the bitfield access. If this completes the access, returns a form representing the
|
* Add a step to the bitfield access. If this completes the access, returns a form representing the
|
||||||
* access
|
* access
|
||||||
|
@ -434,9 +468,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
|
|
||||||
if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT) {
|
if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT) {
|
||||||
// and with mask
|
// and with mask
|
||||||
if (m_got_pcpyud) {
|
// no need to do anything with pcpyud here.
|
||||||
throw std::runtime_error("unknown pcpyud LOGAND_WITH_CONSTANT_INT sequence in bitfield");
|
|
||||||
}
|
|
||||||
m_steps.push_back(step);
|
m_steps.push_back(step);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -449,7 +481,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
auto type = ts.lookup_type(m_type);
|
auto type = ts.lookup_type(m_type);
|
||||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||||
assert(as_bitfield);
|
assert(as_bitfield);
|
||||||
auto field = find_field_from_mask(ts, as_bitfield, m_steps.at(0).amount);
|
auto field = find_field_from_mask(ts, as_bitfield, m_steps.at(0).amount, false); // todo PCPYUP
|
||||||
if (field) {
|
if (field) {
|
||||||
auto get_field = pool.alloc_element<DerefElement>(m_base, false,
|
auto get_field = pool.alloc_element<DerefElement>(m_base, false,
|
||||||
DerefToken::make_field_name(field->name()));
|
DerefToken::make_field_name(field->name()));
|
||||||
|
@ -462,9 +494,6 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
|
|
||||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
||||||
step.kind == BitfieldManip::Kind::LOGIOR_WITH_CONSTANT_INT) {
|
step.kind == BitfieldManip::Kind::LOGIOR_WITH_CONSTANT_INT) {
|
||||||
if (m_got_pcpyud) {
|
|
||||||
throw std::runtime_error("unknown pcpyud LOGIOR_WITH_CONSTANT_INT sequence in bitfield");
|
|
||||||
}
|
|
||||||
// this is setting a bitfield to a constant.
|
// this is setting a bitfield to a constant.
|
||||||
// first, let's check that the mask is used properly:
|
// first, let's check that the mask is used properly:
|
||||||
u64 mask = m_steps.at(0).amount;
|
u64 mask = m_steps.at(0).amount;
|
||||||
|
@ -477,7 +506,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||||
assert(as_bitfield);
|
assert(as_bitfield);
|
||||||
// use the mask to figure out the field.
|
// use the mask to figure out the field.
|
||||||
auto field = find_field_from_mask(ts, as_bitfield, ~mask);
|
auto field = find_field_from_mask(ts, as_bitfield, ~mask, m_got_pcpyud);
|
||||||
assert(field);
|
assert(field);
|
||||||
bool is_signed =
|
bool is_signed =
|
||||||
ts.tc(TypeSpec("int"), field->type()) && !ts.tc(TypeSpec("uint"), field->type());
|
ts.tc(TypeSpec("int"), field->type()) && !ts.tc(TypeSpec("uint"), field->type());
|
||||||
|
@ -485,24 +514,21 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
// use the field to figure out what value is being set.
|
// use the field to figure out what value is being set.
|
||||||
u64 set_value;
|
u64 set_value;
|
||||||
if (is_signed) {
|
if (is_signed) {
|
||||||
set_value = extract_bitfield<s64>(value, field->offset(), field->size());
|
set_value = extract_bitfield<s64>(value, field->offset() - pcpyud_offset, field->size());
|
||||||
} else {
|
} else {
|
||||||
set_value = extract_bitfield<u64>(value, field->offset(), field->size());
|
set_value = extract_bitfield<u64>(value, field->offset() - pcpyud_offset, field->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
BitFieldDef def;
|
BitFieldDef def;
|
||||||
def.field_name = field->name();
|
def.field_name = field->name();
|
||||||
def.value = pool.alloc_single_element_form<SimpleAtomElement>(
|
def.value = pool.alloc_single_element_form<SimpleAtomElement>(
|
||||||
nullptr, SimpleAtom::make_int_constant(set_value));
|
nullptr, SimpleAtom::make_int_constant(set_value));
|
||||||
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base,
|
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base, m_got_pcpyud,
|
||||||
std::vector<BitFieldDef>{def});
|
std::vector<BitFieldDef>{def});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT &&
|
||||||
step.kind == BitfieldManip::Kind::LOGIOR_WITH_FORM) {
|
step.kind == BitfieldManip::Kind::LOGIOR_WITH_FORM) {
|
||||||
if (m_got_pcpyud) {
|
|
||||||
throw std::runtime_error("unknown pcpyud LOGIOR_WITH_FORM sequence in bitfield");
|
|
||||||
}
|
|
||||||
// this is setting a bitfield to a variable
|
// this is setting a bitfield to a variable
|
||||||
u64 mask = m_steps.at(0).amount;
|
u64 mask = m_steps.at(0).amount;
|
||||||
|
|
||||||
|
@ -510,10 +536,10 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
auto as_bitfield = dynamic_cast<BitFieldType*>(type);
|
||||||
assert(as_bitfield);
|
assert(as_bitfield);
|
||||||
// use the mask to figure out the field.
|
// use the mask to figure out the field.
|
||||||
auto field = find_field_from_mask(ts, as_bitfield, ~mask);
|
auto field = find_field_from_mask(ts, as_bitfield, ~mask, m_got_pcpyud);
|
||||||
assert(field);
|
assert(field);
|
||||||
|
|
||||||
auto val = get_bitfield_initial_set(step.value, as_bitfield, ts);
|
auto val = get_bitfield_initial_set(step.value, as_bitfield, ts, pcpyud_offset);
|
||||||
|
|
||||||
if (!val) {
|
if (!val) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
|
@ -524,7 +550,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
throw std::runtime_error("Incompatible bitfield set");
|
throw std::runtime_error("Incompatible bitfield set");
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base,
|
return pool.alloc_element<ModifiedCopyBitfieldElement>(m_type, m_base, m_got_pcpyud,
|
||||||
std::vector<BitFieldDef>{*val});
|
std::vector<BitFieldDef>{*val});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -532,7 +558,10 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step,
|
||||||
for (auto& old_step : m_steps) {
|
for (auto& old_step : m_steps) {
|
||||||
lg::error(" {}", old_step.print());
|
lg::error(" {}", old_step.print());
|
||||||
}
|
}
|
||||||
lg::error("Current: {}\n", step.print());
|
lg::error("Current: {}", step.print());
|
||||||
|
if (m_got_pcpyud) {
|
||||||
|
lg::error("Got pcpyud\n");
|
||||||
|
}
|
||||||
|
|
||||||
throw std::runtime_error("Unknown state in BitfieldReadElement");
|
throw std::runtime_error("Unknown state in BitfieldReadElement");
|
||||||
}
|
}
|
||||||
|
@ -595,6 +624,22 @@ std::optional<u64> get_goal_integer_constant(Form* in, const Env&) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// also (shl (shl <something> 16) 32)
|
||||||
|
// why.
|
||||||
|
matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
|
||||||
|
{Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHL),
|
||||||
|
{Matcher::any(1), Matcher::integer(16)}),
|
||||||
|
Matcher::integer(32)});
|
||||||
|
mr = match(matcher, in);
|
||||||
|
if (mr.matched) {
|
||||||
|
auto arg_as_atom = form_as_atom(mr.maps.forms.at(1));
|
||||||
|
if (arg_as_atom && arg_as_atom->is_int()) {
|
||||||
|
u64 result = arg_as_atom->get_int();
|
||||||
|
result <<= 48ull;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,8 +758,9 @@ Form* cast_to_bitfield(const BitFieldType* type_info,
|
||||||
|
|
||||||
// now variables
|
// now variables
|
||||||
for (auto& arg : args) {
|
for (auto& arg : args) {
|
||||||
|
// it's a 64-bit constant so correct to set offset 0 here.
|
||||||
auto maybe_field =
|
auto maybe_field =
|
||||||
get_bitfield_initial_set(strip_int_or_uint_cast(arg), type_info, env.dts->ts);
|
get_bitfield_initial_set(strip_int_or_uint_cast(arg), type_info, env.dts->ts, 0);
|
||||||
if (!maybe_field) {
|
if (!maybe_field) {
|
||||||
// failed, just return cast.
|
// failed, just return cast.
|
||||||
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);
|
return pool.alloc_single_element_form<CastElement>(nullptr, typespec, in);
|
||||||
|
|
|
@ -101,6 +101,8 @@ class BitfieldAccessElement : public FormElement {
|
||||||
FormPool& pool,
|
FormPool& pool,
|
||||||
const Env& env);
|
const Env& env);
|
||||||
void push_pcpyud(const TypeSystem& ts, FormPool& pool, const Env& env);
|
void push_pcpyud(const TypeSystem& ts, FormPool& pool, const Env& env);
|
||||||
|
std::string debug_print(const Env& env) const;
|
||||||
|
bool has_pcpyud() const { return m_got_pcpyud; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_got_pcpyud = false;
|
bool m_got_pcpyud = false;
|
||||||
|
@ -155,6 +157,7 @@ class ModifiedCopyBitfieldElement : public FormElement {
|
||||||
public:
|
public:
|
||||||
ModifiedCopyBitfieldElement(const TypeSpec& type,
|
ModifiedCopyBitfieldElement(const TypeSpec& type,
|
||||||
Form* base,
|
Form* base,
|
||||||
|
bool from_pcpyud,
|
||||||
const std::vector<BitFieldDef>& field_modifications);
|
const std::vector<BitFieldDef>& field_modifications);
|
||||||
goos::Object to_form_internal(const Env& env) const override;
|
goos::Object to_form_internal(const Env& env) const override;
|
||||||
void apply(const std::function<void(FormElement*)>& f) override;
|
void apply(const std::function<void(FormElement*)>& f) override;
|
||||||
|
@ -164,11 +167,17 @@ class ModifiedCopyBitfieldElement : public FormElement {
|
||||||
|
|
||||||
Form* base() const { return m_base; }
|
Form* base() const { return m_base; }
|
||||||
const std::vector<BitFieldDef> mods() const { return m_field_modifications; }
|
const std::vector<BitFieldDef> mods() const { return m_field_modifications; }
|
||||||
|
bool from_pcpyud() const { return m_from_pcpyud; }
|
||||||
|
void clear_pcpyud_flag() {
|
||||||
|
assert(m_from_pcpyud);
|
||||||
|
m_from_pcpyud = false;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TypeSpec m_type;
|
TypeSpec m_type;
|
||||||
Form* m_base = nullptr;
|
Form* m_base = nullptr;
|
||||||
std::vector<BitFieldDef> m_field_modifications;
|
std::vector<BitFieldDef> m_field_modifications;
|
||||||
|
bool m_from_pcpyud = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
Form* cast_to_bitfield(const BitFieldType* type_info,
|
Form* cast_to_bitfield(const BitFieldType* type_info,
|
||||||
|
|
|
@ -85,11 +85,16 @@ bool convert_to_expressions(
|
||||||
if (!dts.ts.tc(f.type.last_arg(), return_type)) {
|
if (!dts.ts.tc(f.type.last_arg(), return_type)) {
|
||||||
// we need to cast the final value.
|
// we need to cast the final value.
|
||||||
auto to_cast = new_entries.back();
|
auto to_cast = new_entries.back();
|
||||||
|
auto as_cast = dynamic_cast<CastElement*>(to_cast);
|
||||||
|
if (as_cast) {
|
||||||
|
as_cast->set_type(f.type.last_arg());
|
||||||
|
} else {
|
||||||
new_entries.pop_back();
|
new_entries.pop_back();
|
||||||
auto cast = pool.alloc_element<CastElement>(f.type.last_arg(),
|
auto cast = pool.alloc_element<CastElement>(f.type.last_arg(),
|
||||||
pool.alloc_single_form(nullptr, to_cast));
|
pool.alloc_single_form(nullptr, to_cast));
|
||||||
new_entries.push_back(cast);
|
new_entries.push_back(cast);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// or just get all the expressions
|
// or just get all the expressions
|
||||||
new_entries = stack.rewrite(pool, f.ir2.env);
|
new_entries = stack.rewrite(pool, f.ir2.env);
|
||||||
|
|
|
@ -79,8 +79,8 @@ Form* lca_form(Form* a, Form* b, const Env& env) {
|
||||||
bi--;
|
bi--;
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
auto* bad = b->parent_element;
|
fmt::print("{} bad form is {}\n\n{}\n", env.func->guessed_name.to_string(), a->to_string(env),
|
||||||
fmt::print("bad form is {} {}\n", bad->to_string(env), (void*)bad);
|
b->to_string(env));
|
||||||
}
|
}
|
||||||
assert(result);
|
assert(result);
|
||||||
|
|
||||||
|
|
|
@ -730,6 +730,25 @@ void SSA::make_vars(const Function& function, const DecompilerTypeSystem& dts) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if (function.type.last_arg() != TypeSpec("none")) {
|
||||||
|
// auto return_var = function.ir2.atomic_ops->end_op().return_var();
|
||||||
|
// auto return_reg = return_var.reg();
|
||||||
|
// const auto& last_block = blocks.at(blocks.size() - 1);
|
||||||
|
// const auto& last_ins = last_block.ins.at(last_block.ins.size() - 1);
|
||||||
|
// assert(last_ins.src.size() == 1);
|
||||||
|
// auto return_idx = map.var_id(last_ins.src.at(0));
|
||||||
|
//
|
||||||
|
// if (!program_read_vars[return_reg].empty()) {
|
||||||
|
// program_read_vars[return_reg].at(return_idx).type =
|
||||||
|
// TP_Type::make_from_ts(function.type.last_arg());
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!program_write_vars[return_reg].empty()) {
|
||||||
|
// program_write_vars[return_reg].at(return_idx).type =
|
||||||
|
// TP_Type::make_from_ts(function.type.last_arg());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
merge_infos(program_write_vars, program_read_vars, dts);
|
merge_infos(program_write_vars, program_read_vars, dts);
|
||||||
|
|
||||||
// copy types from input argument coloring moves:
|
// copy types from input argument coloring moves:
|
||||||
|
|
|
@ -9325,10 +9325,10 @@
|
||||||
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
||||||
(get-tag-index-data (_type_ int) pointer 13)
|
(get-tag-index-data (_type_ int) pointer 13)
|
||||||
(get-tag-data (_type_ res-tag) pointer 14)
|
(get-tag-data (_type_ res-tag) pointer 14)
|
||||||
(dummy-15 (_type_ res-tag) res-tag 15)
|
(allocate-data-memory-for-tag! (_type_ res-tag) res-tag 15)
|
||||||
(sort! (_type_) _type_ 16)
|
(sort! (_type_) _type_ 16)
|
||||||
(dummy-17 (_type_ res-tag pointer) res-lump 17)
|
(add-data! (_type_ res-tag pointer) res-lump 17)
|
||||||
(dummy-18 (_type_ res-tag res-tag) res-lump 18)
|
(add-32bit-data! (_type_ res-tag object) res-lump 18)
|
||||||
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
||||||
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
||||||
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
||||||
|
@ -9346,9 +9346,6 @@
|
||||||
;; Containing DGOs - ['GAME', 'ENGINE']
|
;; Containing DGOs - ['GAME', 'ENGINE']
|
||||||
;; Version - 3
|
;; Version - 3
|
||||||
|
|
||||||
;; - Functions
|
|
||||||
|
|
||||||
(define-extern part-group-pointer? function)
|
|
||||||
|
|
||||||
;; - Symbols
|
;; - Symbols
|
||||||
|
|
||||||
|
@ -13254,6 +13251,8 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
(define-extern part-group-pointer? (function pointer symbol))
|
||||||
|
|
||||||
;; ----------------------
|
;; ----------------------
|
||||||
;; File - sparticle-h
|
;; File - sparticle-h
|
||||||
;; Source Path - engine/sparticle/sparticle-h.gc
|
;; Source Path - engine/sparticle/sparticle-h.gc
|
||||||
|
|
|
@ -453,7 +453,12 @@
|
||||||
|
|
||||||
"trajectory": [["L18", "uint64", true]],
|
"trajectory": [["L18", "uint64", true]],
|
||||||
|
|
||||||
"res": [["L150", "uint64", true]],
|
"res": [
|
||||||
|
["L150", "uint64", true],
|
||||||
|
["L152", "uint64", true],
|
||||||
|
["L151", "uint64", true],
|
||||||
|
["L153", "uint64", true]
|
||||||
|
],
|
||||||
|
|
||||||
"ripple": [
|
"ripple": [
|
||||||
["L73", "float", true],
|
["L73", "float", true],
|
||||||
|
@ -559,9 +564,7 @@
|
||||||
["L12", "uint64", true]
|
["L12", "uint64", true]
|
||||||
],
|
],
|
||||||
|
|
||||||
"shadow-cpu": [
|
"shadow-cpu": [["L122", "shadow-data", true]],
|
||||||
["L122", "shadow-data", true]
|
|
||||||
],
|
|
||||||
|
|
||||||
"entity-table": [["L8", "(array entity-info)", true]],
|
"entity-table": [["L8", "(array entity-info)", true]],
|
||||||
|
|
||||||
|
|
|
@ -414,9 +414,7 @@
|
||||||
[157, "a0", "(pointer process-drawable)"]
|
[157, "a0", "(pointer process-drawable)"]
|
||||||
],
|
],
|
||||||
|
|
||||||
"load-game-text-info": [
|
"load-game-text-info": [[4, "v1", "game-text-info"]],
|
||||||
[4, "v1", "game-text-info"]
|
|
||||||
],
|
|
||||||
|
|
||||||
"texture-relocate": [
|
"texture-relocate": [
|
||||||
[[17, 21], "t4", "dma-packet"],
|
[[17, 21], "t4", "dma-packet"],
|
||||||
|
@ -506,12 +504,29 @@
|
||||||
[22, "t1", "(pointer uint64)"],
|
[22, "t1", "(pointer uint64)"],
|
||||||
[29, "t2", "(pointer uint64)"]
|
[29, "t2", "(pointer uint64)"]
|
||||||
],
|
],
|
||||||
"(method 18 res-lump)": [["_stack_", 16, "res-tag"]],
|
"(method 18 res-lump)": [["_stack_", 16, "object"]],
|
||||||
"(method 21 res-lump)": [
|
"(method 21 res-lump)": [
|
||||||
["_stack_", 16, "res-tag"],
|
["_stack_", 16, "res-tag"],
|
||||||
["_stack_", 32, "res-tag"]
|
["_stack_", 32, "res-tag"]
|
||||||
],
|
],
|
||||||
|
|
||||||
|
"(method 15 res-lump)": [[132, "s5", "res-tag-pair"]],
|
||||||
|
|
||||||
|
"(method 17 res-lump)": [[22, "s4", "(pointer pointer)"]],
|
||||||
|
|
||||||
|
"(method 20 res-lump)": [[331, "a3", "(inline-array vector)"]],
|
||||||
|
|
||||||
|
"(method 8 res-lump)": [
|
||||||
|
[215, "s0", "array"],
|
||||||
|
[[0, 100], "s0", "basic"],
|
||||||
|
[[102, 120], "s0", "basic"],
|
||||||
|
[[147, 150], "s0", "collide-mesh"],
|
||||||
|
[[157, 200], "s0", "(array object)"],
|
||||||
|
//[[197, 199], "s0", "(array basic)"],
|
||||||
|
//[[236, 240], "a0", "basic"]
|
||||||
|
[235, "s0", "basic"]
|
||||||
|
],
|
||||||
|
|
||||||
// SHADOW-CPU-H
|
// SHADOW-CPU-H
|
||||||
"(method 10 shadow-control)": [[1, "v1", "int"]],
|
"(method 10 shadow-control)": [[1, "v1", "int"]],
|
||||||
|
|
||||||
|
@ -1172,5 +1187,7 @@
|
||||||
|
|
||||||
"blackout": [[[20, 24], "v1", "dma-packet"]],
|
"blackout": [[[20, 24], "v1", "dma-packet"]],
|
||||||
|
|
||||||
|
"(method 10 external-art-control)": [[18, "v1", "pointer"]],
|
||||||
|
|
||||||
"placeholder-do-not-add-below": []
|
"placeholder-do-not-add-below": []
|
||||||
}
|
}
|
||||||
|
|
|
@ -1798,7 +1798,29 @@
|
||||||
},
|
},
|
||||||
"(method 15 res-lump)": {
|
"(method 15 res-lump)": {
|
||||||
"vars": {
|
"vars": {
|
||||||
"s5-0": ["tag-pair", "res-tag-pair"]
|
"s5-0": ["tag-pair", "res-tag-pair"],
|
||||||
|
"s2-0": "existing-tag",
|
||||||
|
"s3-0": "data-size",
|
||||||
|
"v1-25": "resource-mem"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"(method 17 res-lump)": {
|
||||||
|
"vars": {
|
||||||
|
"a0-2": "new-tag",
|
||||||
|
"s4-0": "tag-mem"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"(method 8 res-lump)": {
|
||||||
|
"args": ["obj", "block", "flags"],
|
||||||
|
"vars": {
|
||||||
|
"s3-0":"mem-use-id",
|
||||||
|
"s2-0":"mem-use-name",
|
||||||
|
"v1-22":"obj-size",
|
||||||
|
"s1-0":"tag-idx",
|
||||||
|
"s0-0":"tag-data"
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -67,6 +67,8 @@ std::string TP_Type::print() const {
|
||||||
}
|
}
|
||||||
case Kind::PCPYUD_BITFIELD:
|
case Kind::PCPYUD_BITFIELD:
|
||||||
return fmt::format("<pcpyud {}>", m_ts.print());
|
return fmt::format("<pcpyud {}>", m_ts.print());
|
||||||
|
case Kind::PCPYUD_BITFIELD_AND:
|
||||||
|
return fmt::format("<pcpyud-and {}>", m_ts.print());
|
||||||
case Kind::LABEL_ADDR:
|
case Kind::LABEL_ADDR:
|
||||||
return "<label-addr>";
|
return "<label-addr>";
|
||||||
case Kind::INVALID:
|
case Kind::INVALID:
|
||||||
|
@ -119,6 +121,8 @@ bool TP_Type::operator==(const TP_Type& other) const {
|
||||||
return m_int == other.m_int && m_ts == other.m_ts && m_pcpyud == other.m_pcpyud;
|
return m_int == other.m_int && m_ts == other.m_ts && m_pcpyud == other.m_pcpyud;
|
||||||
case Kind::PCPYUD_BITFIELD:
|
case Kind::PCPYUD_BITFIELD:
|
||||||
return m_pcpyud == other.m_pcpyud && m_ts == other.m_ts;
|
return m_pcpyud == other.m_pcpyud && m_ts == other.m_ts;
|
||||||
|
case Kind::PCPYUD_BITFIELD_AND:
|
||||||
|
return m_pcpyud == other.m_pcpyud && m_ts == other.m_ts;
|
||||||
case Kind::LABEL_ADDR:
|
case Kind::LABEL_ADDR:
|
||||||
return true;
|
return true;
|
||||||
case Kind::INVALID:
|
case Kind::INVALID:
|
||||||
|
@ -177,6 +181,8 @@ TypeSpec TP_Type::typespec() const {
|
||||||
return TypeSpec("int"); // ideally this is never used.
|
return TypeSpec("int"); // ideally this is never used.
|
||||||
case Kind::PCPYUD_BITFIELD:
|
case Kind::PCPYUD_BITFIELD:
|
||||||
return TypeSpec("int");
|
return TypeSpec("int");
|
||||||
|
case Kind::PCPYUD_BITFIELD_AND:
|
||||||
|
return TypeSpec("int");
|
||||||
case Kind::LABEL_ADDR:
|
case Kind::LABEL_ADDR:
|
||||||
return TypeSpec("pointer"); // ?
|
return TypeSpec("pointer"); // ?
|
||||||
case Kind::INVALID:
|
case Kind::INVALID:
|
||||||
|
|
|
@ -33,6 +33,7 @@ class TP_Type {
|
||||||
VIRTUAL_METHOD,
|
VIRTUAL_METHOD,
|
||||||
NON_VIRTUAL_METHOD,
|
NON_VIRTUAL_METHOD,
|
||||||
PCPYUD_BITFIELD,
|
PCPYUD_BITFIELD,
|
||||||
|
PCPYUD_BITFIELD_AND,
|
||||||
LEFT_SHIFTED_BITFIELD, // (bitfield << some-constant)
|
LEFT_SHIFTED_BITFIELD, // (bitfield << some-constant)
|
||||||
LABEL_ADDR,
|
LABEL_ADDR,
|
||||||
INVALID
|
INVALID
|
||||||
|
@ -62,6 +63,7 @@ class TP_Type {
|
||||||
case Kind::NON_VIRTUAL_METHOD:
|
case Kind::NON_VIRTUAL_METHOD:
|
||||||
case Kind::LEFT_SHIFTED_BITFIELD:
|
case Kind::LEFT_SHIFTED_BITFIELD:
|
||||||
case Kind::PCPYUD_BITFIELD:
|
case Kind::PCPYUD_BITFIELD:
|
||||||
|
case Kind::PCPYUD_BITFIELD_AND:
|
||||||
case Kind::LABEL_ADDR:
|
case Kind::LABEL_ADDR:
|
||||||
return false;
|
return false;
|
||||||
case Kind::UNINITIALIZED:
|
case Kind::UNINITIALIZED:
|
||||||
|
@ -244,6 +246,14 @@ class TP_Type {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static TP_Type make_from_pcpyud_and_bitfield(const TypeSpec& ts) {
|
||||||
|
TP_Type result;
|
||||||
|
result.kind = Kind::PCPYUD_BITFIELD_AND;
|
||||||
|
result.m_ts = ts;
|
||||||
|
result.m_pcpyud = true;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
static TP_Type make_label_addr() {
|
static TP_Type make_label_addr() {
|
||||||
TP_Type result;
|
TP_Type result;
|
||||||
result.kind = Kind::LABEL_ADDR;
|
result.kind = Kind::LABEL_ADDR;
|
||||||
|
@ -296,7 +306,8 @@ class TP_Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
const TypeSpec& get_bitfield_type() const {
|
const TypeSpec& get_bitfield_type() const {
|
||||||
assert(kind == Kind::LEFT_SHIFTED_BITFIELD || kind == Kind::PCPYUD_BITFIELD);
|
assert(kind == Kind::LEFT_SHIFTED_BITFIELD || kind == Kind::PCPYUD_BITFIELD ||
|
||||||
|
kind == Kind::PCPYUD_BITFIELD_AND);
|
||||||
return m_ts;
|
return m_ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,10 +47,10 @@
|
||||||
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
||||||
(get-tag-index-data (_type_ int) pointer 13)
|
(get-tag-index-data (_type_ int) pointer 13)
|
||||||
(get-tag-data (_type_ res-tag) pointer 14)
|
(get-tag-data (_type_ res-tag) pointer 14)
|
||||||
(dummy-15 (_type_ res-tag) res-tag 15)
|
(allocate-data-memory-for-tag! (_type_ res-tag) res-tag 15)
|
||||||
(sort! (_type_) _type_ 16)
|
(sort! (_type_) _type_ 16)
|
||||||
(dummy-17 (_type_ res-tag pointer) res-lump 17)
|
(add-data! (_type_ res-tag pointer) res-lump 17)
|
||||||
(dummy-18 (_type_ res-tag res-tag) res-lump 18)
|
(add-32bit-data! (_type_ res-tag object) res-lump 18)
|
||||||
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
||||||
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
||||||
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
||||||
|
|
|
@ -67,7 +67,7 @@ This is updated from the entity system used in Crash 2, which had most of these
|
||||||
(the int
|
(the int
|
||||||
(if (res-ref? obj)
|
(if (res-ref? obj)
|
||||||
|
|
||||||
(* (-> obj elt-count) 4)
|
(* (-> obj elt-count) 4) ;; elements are pointers/references to data.
|
||||||
|
|
||||||
(* (-> obj elt-count) (-> obj elt-type size))
|
(* (-> obj elt-count) (-> obj elt-type size))
|
||||||
)
|
)
|
||||||
|
@ -685,6 +685,148 @@ This is updated from the entity system used in Crash 2, which had most of these
|
||||||
obj
|
obj
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(defmethod allocate-data-memory-for-tag! res-lump ((obj res-lump) (arg0 res-tag))
|
||||||
|
"Find space for the data described by arg0 in obj.
|
||||||
|
Returns a tag with data-offset set correctly for this res-lump.
|
||||||
|
If the lump already contains memory for the given tag, and it is big enough,
|
||||||
|
it will be reused. Alignment will be at least 8 bytes.
|
||||||
|
If the input tag has elt-count = 0, it will return a tag for elt-count = 1."
|
||||||
|
(local-vars (resource-mem pointer))
|
||||||
|
|
||||||
|
;; first, look up the tag to see if it already exists in this res-lump
|
||||||
|
(let ((tag-pair (lookup-tag-idx obj (-> arg0 name) 'exact (-> arg0 key-frame))))
|
||||||
|
(let ((existing-tag (-> obj tag (-> tag-pair lo))))
|
||||||
|
;; If our existing tag is valid, but our key-frame is NaN, then we forget about it.
|
||||||
|
(if (and (>= (the-as int tag-pair) 0)
|
||||||
|
(!= (-> arg0 key-frame) (-> arg0 key-frame)) ;; check for NaN
|
||||||
|
)
|
||||||
|
(set! tag-pair (new 'static 'res-tag-pair :lo #xffffffff :hi #xffffffff))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; modify the input to have at least one element
|
||||||
|
(if (zero? (-> arg0 elt-count))
|
||||||
|
(set! (-> arg0 elt-count) 1)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; next, we try to find some memory
|
||||||
|
(let ((data-size (length arg0))) ;; size in bytes to store the data.
|
||||||
|
(cond
|
||||||
|
((and (>= (the-as int tag-pair) 0)
|
||||||
|
(>= (the-as uint (length existing-tag)) (the-as uint data-size))
|
||||||
|
)
|
||||||
|
;; we have enough memory in the existing tag.
|
||||||
|
;; so we can just reuse it.
|
||||||
|
(set! resource-mem (&+ (-> obj data-base) (-> existing-tag data-offset)))
|
||||||
|
|
||||||
|
;; but we want at least 8 byte alignment. If this fails, allocate with 16-byte alignment from the top.
|
||||||
|
(when (nonzero? (logand (the-as int resource-mem) 7))
|
||||||
|
(set! resource-mem (logand -16 (&+ (-> obj data-top) 15)))
|
||||||
|
(set! (-> obj data-top) (&+ resource-mem data-size))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(else
|
||||||
|
;; the existing tag wasn't there, or it wasn't big enough.
|
||||||
|
;; just allocate new memory.
|
||||||
|
(set! resource-mem (logand -16 (&+ (-> obj data-top) 15)))
|
||||||
|
(set! (-> obj data-top) (&+ resource-mem data-size))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; set our data offset.
|
||||||
|
(set! (-> arg0 data-offset) (&- resource-mem (the-as uint (-> obj data-base))))
|
||||||
|
|
||||||
|
;; check for overflow of the data memory
|
||||||
|
;; this will leave things in a bad state.
|
||||||
|
(when (>= (the-as int (&+ resource-mem data-size))
|
||||||
|
(the-as int (&+ (-> obj data-base) (-> obj data-size)))
|
||||||
|
)
|
||||||
|
(format 0 "ERROR: attempting to a new tag ~`res-tag`P data of #x~X bytes to ~A, but data memory is full.~%"
|
||||||
|
arg0
|
||||||
|
data-size
|
||||||
|
obj
|
||||||
|
)
|
||||||
|
(return (the-as res-tag #f))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; next step is to add us to the list of tags.
|
||||||
|
(cond
|
||||||
|
((< (the-as int tag-pair) 0)
|
||||||
|
;; we couldn't reuse an existing tag. Need to allocate another
|
||||||
|
(cond
|
||||||
|
((>= (-> obj length) (-> obj allocated-length))
|
||||||
|
;; but there isn't room for another tag.
|
||||||
|
(format 0 "ERROR: attempting to a new tag ~`res-tag`P to ~A, but tag memory is full.~%"
|
||||||
|
arg0
|
||||||
|
obj
|
||||||
|
)
|
||||||
|
(return (the-as res-tag #f))
|
||||||
|
)
|
||||||
|
(else
|
||||||
|
;; allocate a new tag and sort, so the binary search works properly.
|
||||||
|
(set! (-> obj tag (-> obj length)) arg0)
|
||||||
|
(set! (-> obj length) (+ (-> obj length) 1))
|
||||||
|
(sort! obj)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(else
|
||||||
|
;; reuse the existing tag.
|
||||||
|
(set! (-> obj tag (-> tag-pair lo)) arg0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
arg0
|
||||||
|
)
|
||||||
|
|
||||||
|
(defmethod add-data! res-lump ((obj res-lump) (arg0 res-tag) (arg1 pointer))
|
||||||
|
"Given a tag and a pointer to its data, copy it to this res-lump.
|
||||||
|
This doesn't seem to do the right thing if the given tag is a non-inline tag
|
||||||
|
with > 1 element."
|
||||||
|
|
||||||
|
;; get a tag for this lump with memory for the given tag.
|
||||||
|
(let ((new-tag (allocate-data-memory-for-tag! obj arg0)))
|
||||||
|
(when new-tag
|
||||||
|
;; get pointer to new tag's memory
|
||||||
|
(let* ((v1-2 obj)
|
||||||
|
(a1-1 new-tag)
|
||||||
|
(tag-mem (&+ (-> v1-2 data-base) (-> a1-1 data-offset)))
|
||||||
|
)
|
||||||
|
(cond
|
||||||
|
((zero? (-> new-tag inlined?))
|
||||||
|
;; this seems wrong, it should loop over the length maybe?
|
||||||
|
(length new-tag) ;; unused?
|
||||||
|
(set! (-> (the-as (pointer pointer) tag-mem)) arg1)
|
||||||
|
)
|
||||||
|
(else
|
||||||
|
;; otherwise, copy the memory.
|
||||||
|
(let ((a2-1 (length new-tag)))
|
||||||
|
(mem-copy! tag-mem arg1 a2-1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
obj
|
||||||
|
)
|
||||||
|
|
||||||
|
(defmethod add-32bit-data! res-lump ((obj res-lump) (arg0 res-tag) (arg1 object))
|
||||||
|
"Add a single 32-bit value using add-data."
|
||||||
|
(set! (-> arg0 inlined?) 1)
|
||||||
|
(add-data! obj arg0 (& arg1)) ;; note, only 32-bits are spilled to the stack here.
|
||||||
|
#|
|
||||||
|
(local-vars (sv-16 object))
|
||||||
|
(set! sv-16 arg1)
|
||||||
|
(let* ((v1-0 arg0)
|
||||||
|
(a1-4 (copy-and-set-bf v1-0 :inlined? 1))
|
||||||
|
)
|
||||||
|
(add-data! obj a1-4 (& sv-16))
|
||||||
|
)
|
||||||
|
|#
|
||||||
|
)
|
||||||
|
|
||||||
(defmethod get-curve-data! res-lump ((obj res-lump) (curve-target curve) (points-name symbol) (knots-name symbol) (time float))
|
(defmethod get-curve-data! res-lump ((obj res-lump) (curve-target curve) (points-name symbol) (knots-name symbol) (time float))
|
||||||
"Read curve data and write it to curve-target. Return #t if both control points and knots data was succesfully read, #f otherwise."
|
"Read curve data and write it to curve-target. Return #t if both control points and knots data was succesfully read, #f otherwise."
|
||||||
|
|
||||||
|
@ -720,10 +862,139 @@ This is updated from the entity system used in Crash 2, which had most of these
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
;; method 15 res-lump
|
(define-extern part-group-pointer? (function pointer symbol))
|
||||||
;; method 17 res-lump
|
(declare-type nav-mesh basic)
|
||||||
;; method 18 res-lump
|
(declare-type collide-mesh basic)
|
||||||
;; mem-usage res-lump
|
(defmethod mem-usage res-lump ((obj res-lump) (block memory-usage-block) (flags int))
|
||||||
|
"Get the memory usage of this lump and its data"
|
||||||
|
(local-vars (sv-16 int))
|
||||||
|
|
||||||
|
;; get the name and ID
|
||||||
|
(let ((mem-use-id (mem-usage-id res))
|
||||||
|
(mem-use-name "res")
|
||||||
|
)
|
||||||
|
(cond
|
||||||
|
((nonzero? (logand flags 256))
|
||||||
|
(set! mem-use-id (mem-usage-id camera))
|
||||||
|
(set! mem-use-name "camera")
|
||||||
|
)
|
||||||
|
((nonzero? (logand flags 64))
|
||||||
|
(set! mem-use-id (mem-usage-id entity))
|
||||||
|
(set! mem-use-name "entity")
|
||||||
|
)
|
||||||
|
((nonzero? (logand flags 128))
|
||||||
|
(set! mem-use-id (mem-usage-id ambient))
|
||||||
|
(set! mem-use-name "ambient")
|
||||||
|
)
|
||||||
|
((nonzero? (logand flags 512))
|
||||||
|
(set! mem-use-id (mem-usage-id art-joint-geo))
|
||||||
|
(set! mem-use-name "art-joint-geo")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; set up the block
|
||||||
|
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||||
|
(set! (-> block data mem-use-id name) mem-use-name)
|
||||||
|
|
||||||
|
;; the lump counts as 1 in the count field
|
||||||
|
(set! (-> block data mem-use-id count) (+ (-> block data mem-use-id count) 1))
|
||||||
|
|
||||||
|
;; add the size of the lump itself.
|
||||||
|
(let ((obj-size (asize-of obj)))
|
||||||
|
(set! (-> block data mem-use-id used)
|
||||||
|
(+ (-> block data mem-use-id used) obj-size)
|
||||||
|
)
|
||||||
|
(set! (-> block data mem-use-id total)
|
||||||
|
(+ (-> block data mem-use-id total) (logand -16 (+ obj-size 15)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; add the tags
|
||||||
|
(dotimes (tag-idx (-> obj length))
|
||||||
|
(when (zero? (-> obj tag tag-idx inlined?))
|
||||||
|
(let* ((a1-4 obj)
|
||||||
|
(a0-15 tag-idx)
|
||||||
|
(tag-data
|
||||||
|
(the-as basic
|
||||||
|
(-> (the-as (pointer uint32) (&+ (-> a1-4 data-base) (-> a1-4 tag a0-15 data-offset)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;; ref to non-inline data. Inline data would have been counted above.
|
||||||
|
(when (not (part-group-pointer? (the-as pointer tag-data)))
|
||||||
|
(case (-> (the-as basic tag-data) type)
|
||||||
|
((symbol type)
|
||||||
|
)
|
||||||
|
((string)
|
||||||
|
;; strings add like a normal object.
|
||||||
|
;; this seems identical to the else case.
|
||||||
|
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||||
|
(set! (-> block data mem-use-id name) mem-use-name)
|
||||||
|
(set! (-> block data mem-use-id count)
|
||||||
|
(+ (-> block data mem-use-id count) 1)
|
||||||
|
)
|
||||||
|
(let ((v1-47 (asize-of tag-data)))
|
||||||
|
(set! (-> block data mem-use-id used)
|
||||||
|
(+ (-> block data mem-use-id used) v1-47)
|
||||||
|
)
|
||||||
|
(set! (-> block data mem-use-id total)
|
||||||
|
(+ (-> block data mem-use-id total) (logand -16 (+ v1-47 15)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
((nav-mesh collide-mesh)
|
||||||
|
;; these have their own implementation.
|
||||||
|
(mem-usage tag-data block flags)
|
||||||
|
)
|
||||||
|
((array)
|
||||||
|
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||||
|
(set! (-> block data mem-use-id name) mem-use-name)
|
||||||
|
(set! (-> block data mem-use-id count)
|
||||||
|
(+ (-> block data mem-use-id count) 1)
|
||||||
|
)
|
||||||
|
(let ((v1-63 (asize-of (the-as (array object) tag-data))))
|
||||||
|
(set! (-> block data mem-use-id used)
|
||||||
|
(+ (-> block data mem-use-id used) v1-63)
|
||||||
|
)
|
||||||
|
(set! (-> block data mem-use-id total)
|
||||||
|
(+ (-> block data mem-use-id total) (logand -16 (+ v1-63 15)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
;; call mem usage on all of our children.
|
||||||
|
(set! sv-16 0)
|
||||||
|
(while (< sv-16 (-> (the-as array tag-data) length))
|
||||||
|
(let ((a0-58 (-> (the-as (array object) tag-data) sv-16)))
|
||||||
|
((method-of-type (rtype-of a0-58) mem-usage) a0-58 block flags)
|
||||||
|
)
|
||||||
|
(set! sv-16 (+ sv-16 1))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(else
|
||||||
|
;; unknown type.
|
||||||
|
;; we assume its nothing fancy and use the asize of.
|
||||||
|
(set! (-> block length) (max (-> block length) (+ mem-use-id 1)))
|
||||||
|
(set! (-> block data mem-use-id name) mem-use-name)
|
||||||
|
(set! (-> block data mem-use-id count)
|
||||||
|
(+ (-> block data mem-use-id count) 1)
|
||||||
|
)
|
||||||
|
(let ((v1-88 (asize-of tag-data)))
|
||||||
|
(set! (-> block data mem-use-id used)
|
||||||
|
(+ (-> block data mem-use-id used) v1-88)
|
||||||
|
)
|
||||||
|
(set! (-> block data mem-use-id total)
|
||||||
|
(+ (-> block data mem-use-id total) (logand -16 (+ v1-88 15)))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(the-as res-lump 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
(define *res-static-buf* (malloc 'global 128))
|
(define *res-static-buf* (malloc 'global 128))
|
||||||
|
|
|
@ -81,3 +81,5 @@
|
||||||
:size-assert #x34
|
:size-assert #x34
|
||||||
:flag-assert #x900000034
|
:flag-assert #x900000034
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(define-extern part-group-pointer? (function pointer symbol))
|
||||||
|
|
|
@ -1388,3 +1388,13 @@
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
;; the decompiler may fail to recognize setting fields of a 128-bit bitfield
|
||||||
|
;; and will rely on this macro:
|
||||||
|
(defmacro copy-and-set-field (original field-name field-value)
|
||||||
|
`(let ((temp-copy ,original))
|
||||||
|
(set! (-> temp-copy ,field-name) ,field-value)
|
||||||
|
temp-copy
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
@ -190,3 +190,10 @@
|
||||||
`(* (/ 1.0 ,TICKS_PER_SECOND) ,vel)
|
`(* (/ 1.0 ,TICKS_PER_SECOND) ,vel)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(defmacro copy-and-set-field (original field-name field-value)
|
||||||
|
`(let ((temp-copy ,original))
|
||||||
|
(set! (-> temp-copy ,field-name) ,field-value)
|
||||||
|
temp-copy
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
@ -36,10 +36,10 @@
|
||||||
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
(get-property-value-float (_type_ symbol symbol float float (pointer res-tag) pointer) float :no-virtual 12)
|
||||||
(get-tag-index-data (_type_ int) pointer 13)
|
(get-tag-index-data (_type_ int) pointer 13)
|
||||||
(get-tag-data (_type_ res-tag) pointer 14)
|
(get-tag-data (_type_ res-tag) pointer 14)
|
||||||
(dummy-15 (_type_ res-tag) res-tag 15)
|
(allocate-data-memory-for-tag! (_type_ res-tag) res-tag 15)
|
||||||
(sort! (_type_) _type_ 16)
|
(sort! (_type_) _type_ 16)
|
||||||
(dummy-17 (_type_ res-tag pointer) res-lump 17)
|
(add-data! (_type_ res-tag pointer) res-lump 17)
|
||||||
(dummy-18 (_type_ res-tag res-tag) res-lump 18)
|
(add-32bit-data! (_type_ res-tag object) res-lump 18)
|
||||||
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
(lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19)
|
||||||
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
(make-property-data (_type_ float res-tag-pair pointer) pointer 20)
|
||||||
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
(get-curve-data! (_type_ curve symbol symbol float) symbol 21)
|
||||||
|
@ -47,6 +47,7 @@
|
||||||
)
|
)
|
||||||
|
|
||||||
;; definition for method 3 of type res-lump
|
;; definition for method 3 of type res-lump
|
||||||
|
;; INFO: this function exists in multiple non-identical object files
|
||||||
(defmethod inspect res-lump ((obj res-lump))
|
(defmethod inspect res-lump ((obj res-lump))
|
||||||
(format #t "[~8x] ~A~%" obj (-> obj type))
|
(format #t "[~8x] ~A~%" obj (-> obj type))
|
||||||
(format #t "~Tlength: ~D~%" (-> obj length))
|
(format #t "~Tlength: ~D~%" (-> obj length))
|
||||||
|
|
1151
test/decompiler/reference/engine/data/res_REF.gc
Normal file
1151
test/decompiler/reference/engine/data/res_REF.gc
Normal file
File diff suppressed because it is too large
Load diff
|
@ -726,12 +726,9 @@
|
||||||
;; INFO: Return type mismatch object vs function.
|
;; INFO: Return type mismatch object vs function.
|
||||||
(defun debug-menu-func-decode ((arg0 object))
|
(defun debug-menu-func-decode ((arg0 object))
|
||||||
(let ((v1-1 (rtype-of arg0)))
|
(let ((v1-1 (rtype-of arg0)))
|
||||||
(the-as function (the-as symbol (cond
|
(the-as function (cond
|
||||||
((or (= v1-1 symbol) (= v1-1 type))
|
((or (= v1-1 symbol) (= v1-1 type))
|
||||||
(the-as
|
(the-as symbol (-> (the-as symbol arg0) value))
|
||||||
symbol
|
|
||||||
(-> (the-as symbol arg0) value)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
((= v1-1 function)
|
((= v1-1 function)
|
||||||
(the-as symbol arg0)
|
(the-as symbol arg0)
|
||||||
|
@ -743,7 +740,6 @@
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
;; definition for function debug-menu-make-from-template
|
;; definition for function debug-menu-make-from-template
|
||||||
;; WARN: Stack slot load mismatch: defined as size 4, got size 16
|
;; WARN: Stack slot load mismatch: defined as size 4, got size 16
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
;; INFO: Return type mismatch object vs cspace.
|
;; INFO: Return type mismatch object vs cspace.
|
||||||
(defun cspace-by-name-no-fail ((arg0 process-drawable) (arg1 string))
|
(defun cspace-by-name-no-fail ((arg0 process-drawable) (arg1 string))
|
||||||
(let ((result (cspace-by-name arg0 arg1)))
|
(let ((result (cspace-by-name arg0 arg1)))
|
||||||
(the-as cspace (the-as cspace (cond
|
(the-as cspace (cond
|
||||||
(result
|
(result
|
||||||
(empty)
|
(empty)
|
||||||
(the-as cspace result)
|
(the-as cspace result)
|
||||||
|
@ -18,7 +18,6 @@
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
;; definition for function cspace-index-by-name-no-fail
|
;; definition for function cspace-index-by-name-no-fail
|
||||||
(defun cspace-index-by-name-no-fail ((arg0 process-drawable) (arg1 string))
|
(defun cspace-index-by-name-no-fail ((arg0 process-drawable) (arg1 string))
|
||||||
|
|
|
@ -166,7 +166,7 @@
|
||||||
(-> arg0 method-table 13)
|
(-> arg0 method-table 13)
|
||||||
(the-as function (-> v1-1 a1-0))
|
(the-as function (-> v1-1 a1-0))
|
||||||
)
|
)
|
||||||
(return (-> v1-1 a1-0))
|
(return (the-as entity-info (-> v1-1 a1-0)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -5417,7 +5417,7 @@
|
||||||
(task-available? (-> gp-0 stage s5-0) gp-0)
|
(task-available? (-> gp-0 stage s5-0) gp-0)
|
||||||
)
|
)
|
||||||
(first-any gp-0 #t)
|
(first-any gp-0 #t)
|
||||||
(return (the-as int (-> gp-0 stage s5-0 status)))
|
(return (the-as task-status (-> gp-0 stage s5-0 status)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue