From 2754a8f2c4bf58043694c0140b0522356c72d430 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 17 Jul 2021 13:41:05 -0400 Subject: [PATCH] get res decompiling (#705) --- decompiler/IR2/AtomicOpTypeAnalysis.cpp | 17 +- decompiler/IR2/Env.h | 1 + decompiler/IR2/Form.cpp | 7 +- decompiler/IR2/Form.h | 4 + decompiler/IR2/FormExpressionAnalysis.cpp | 157 ++- decompiler/IR2/FormStack.cpp | 3 +- decompiler/IR2/bitfields.cpp | 110 +- decompiler/IR2/bitfields.h | 9 + decompiler/analysis/expression_build.cpp | 13 +- decompiler/analysis/insert_lets.cpp | 4 +- decompiler/analysis/variable_naming.cpp | 19 + decompiler/config/all-types.gc | 11 +- .../jak1_ntsc_black_label/label_types.jsonc | 17 +- .../jak1_ntsc_black_label/type_casts.jsonc | 25 +- .../jak1_ntsc_black_label/var_names.jsonc | 24 +- decompiler/util/TP_Type.cpp | 6 + decompiler/util/TP_Type.h | 13 +- goal_src/engine/data/res-h.gc | 6 +- goal_src/engine/data/res.gc | 281 +++- goal_src/engine/sparticle/sparticle-h.gc | 2 + goal_src/kernel/gcommon.gc | 10 + .../decompiler/reference/decompiler-macros.gc | 7 + .../reference/engine/data/res-h_REF.gc | 7 +- .../reference/engine/data/res_REF.gc | 1151 +++++++++++++++++ .../reference/engine/debug/menu_REF.gc | 24 +- .../engine/draw/process-drawable-h_REF.gc | 19 +- .../engine/entity/entity-table_REF.gc | 2 +- .../engine/game/task/task-control_REF.gc | 2 +- 28 files changed, 1832 insertions(+), 119 deletions(-) create mode 100644 test/decompiler/reference/engine/data/res_REF.gc diff --git a/decompiler/IR2/AtomicOpTypeAnalysis.cpp b/decompiler/IR2/AtomicOpTypeAnalysis.cpp index 58f5c1e941..dabf071443 100644 --- a/decompiler/IR2/AtomicOpTypeAnalysis.cpp +++ b/decompiler/IR2/AtomicOpTypeAnalysis.cpp @@ -187,13 +187,13 @@ TP_Type SimpleExpression::get_type(const TypeState& input, case Kind::XOR: case Kind::LEFT_SHIFT: case Kind::MUL_UNSIGNED: + case Kind::PCPYLD: return get_type_int2(input, env, dts); case Kind::NEG: case Kind::LOGNOT: return get_type_int1(input, env, dts); case Kind::DIV_UNSIGNED: case Kind::MOD_UNSIGNED: - case Kind::PCPYLD: return TP_Type::make_from_ts("uint"); case Kind::VECTOR_PLUS: case Kind::VECTOR_MINUS: @@ -427,6 +427,21 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input, 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) { FieldReverseLookupInput rd_in; rd_in.offset = arg0_type.get_add_int_constant(); diff --git a/decompiler/IR2/Env.h b/decompiler/IR2/Env.h index df5de86c37..42afcbcdba 100644 --- a/decompiler/IR2/Env.h +++ b/decompiler/IR2/Env.h @@ -82,6 +82,7 @@ class Env { VariableWithCast get_variable_and_cast(const RegisterAccess& access) const; std::optional get_user_cast_for_access(const RegisterAccess& access) 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. diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index df47048ee9..189e6b41f4 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -1904,10 +1904,11 @@ void GenericElement::get_modified_regs(RegSet& regs) const { CastElement::CastElement(TypeSpec type, Form* source, bool 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 { + // assert(m_source->parent_element == this); auto atom = form_as_atom(m_source); if (atom && atom->is_var()) { 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& f) { + // assert(m_source->parent_element == this); f(this); m_source->apply(f); } void CastElement::apply_form(const std::function& f) { + // assert(m_source->parent_element == this); m_source->apply_form(f); } void CastElement::collect_vars(RegAccessSet& vars, bool recursive) const { + // assert(m_source->parent_element == this); if (recursive) { m_source->collect_vars(vars, recursive); } } void CastElement::get_modified_regs(RegSet& regs) const { + assert(m_source->parent_element == this); m_source->get_modified_regs(regs); } diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 06d36e1c1f..d0bc3995e9 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -54,6 +54,10 @@ class FormElement { bool allow_side_effects); bool is_popped() const { return m_popped; } + FormElement() = default; + FormElement(const FormElement& other) = delete; + FormElement& operator=(const FormElement& other) = delete; + void mark_popped() { assert(!m_popped); m_popped = true; diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 658ba88ac0..0a98b07948 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -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(); + 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( GenericOperator::make_fixed(FixedOperatorKind::PCPYLD), args.at(0), args.at(1)); result->push_back(new_form); @@ -1262,16 +1285,45 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + // grab the normal variable type 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 bitfield_info = dynamic_cast(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(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(env.dts->ts.lookup_type(arg0_reg_type.get_bitfield_type())); + assert(bitfield_info); + } + } + if (bitfield_info && m_expr.get_arg(1).is_int()) { // andi, ori with bitfield. auto base = pop_to_forms({m_expr.get_arg(0).var()}, env, pool, stack, allow_side_effects).at(0); auto read_elt = dynamic_cast(base->try_as_single_element()); if (!read_elt) { - read_elt = pool.alloc_element(base, arg0_type); + read_elt = pool.alloc_element(base, bitfield_type); + assert(!had_pcpyud); + } else { + if (had_pcpyud) { + assert(read_elt->has_pcpyud()); + } } 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; auto read_elt = dynamic_cast(args.at(0)->try_as_single_element()); if (!read_elt) { - read_elt = pool.alloc_element(args.at(0), arg0_type); + read_elt = pool.alloc_element(args.at(0), bitfield_type); 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 arg1_atom = form_as_atom(strip_int_or_uint_cast(args.at(1))); - if (arg1_atom && arg1_atom->is_int()) { + // auto arg1_atom = form_as_atom(strip_int_or_uint_cast(args.at(1))); + auto arg1_as_int = get_goal_integer_constant(stripped_arg1, env); + if (arg1_as_int) { BitfieldManip::Kind manip_kind; if (kind == FixedOperatorKind::LOGAND) { manip_kind = BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT; @@ -1328,10 +1386,14 @@ void SimpleExpressionElement::update_from_stack_logor_or_logand(const Env& env, } else { 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); - assert(!other); // shouldn't be complete. - result->push_back(read_elt); + // assert(!other); // shouldn't be complete. + if (other) { + result->push_back(other); + } else { + result->push_back(read_elt); + } return; } else if (!made_new_read_elt) { BitfieldManip::Kind manip_kind; @@ -1847,6 +1909,13 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta return; } + // bool skip = false; + // auto dst_type = env.get_variable_type(m_dst, false); + // auto as_bitfield = dynamic_cast(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. // it is the Stack's responsibility to untangle these later on. 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 m_src->update_children_from_stack(env, pool, stack, true); + /* + auto src_as_bf_set = dynamic_cast(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(nullptr, + SimpleAtom::make_var(m_dst)); auto loc_elt = pool.alloc_element(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(loc, value); + stack.push_form_element(new_form_el, true); + return; + } + } + */ + for (auto x : m_src->elts()) { 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: auto src_as_bf_set = dynamic_cast(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 src_form = src_as_bf_set->base()->to_form(env); if (dst_form == src_form) { @@ -1933,6 +2024,8 @@ void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack m_dst = loc; 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); @@ -2314,23 +2407,29 @@ void FunctionCallElement::update_from_stack(const Env& env, "type."); } - if (!env.dts->ts.should_use_virtual_methods(tp_type.method_from_type(), - tp_type.method_id())) { + bool is_res_lump = tp_type.method_from_type().base_type() == "res-lump"; + 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( fmt::format("Method call on {} id {} used a virtual call unexpectedly.", tp_type.method_from_type().print(), tp_type.method_id())); } - // fmt::print("STACK\n{}\n\n", stack.print(env)); - auto pop = - pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects, {}, {2}) - .at(0); - // fmt::print("GOT: {}\n", pop->to_string(env)); - arg_forms.at(0) = pop; - new_form = pool.alloc_element( - GenericOperator::make_function(mr.maps.forms.at(1)), arg_forms); - result->push_back(new_form); - return; + if (should_use_virtual) { + // fmt::print("STACK\n{}\n\n", stack.print(env)); + auto pop = pop_to_forms({*arg0_mr.maps.regs.at(0)}, env, pool, stack, allow_side_effects, + {}, {2}) + .at(0); + // fmt::print("GOT: {}\n", pop->to_string(env)); + arg_forms.at(0) = pop; + + new_form = pool.alloc_element( + GenericOperator::make_function(mr.maps.forms.at(1)), arg_forms); + result->push_back(new_form); + return; + } } } } @@ -3525,9 +3624,11 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta } std::vector new_entries; - new_entries = rewrite_to_get_var(temp_stack, pool, env.end_var(), env); + std::optional var; + new_entries = rewrite_to_get_var(temp_stack, pool, env.end_var(), env, &var); assert(!new_entries.empty()); + return_code->clear(); 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()); + 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(); + 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); } diff --git a/decompiler/IR2/FormStack.cpp b/decompiler/IR2/FormStack.cpp index e2ea9b77ba..7538fd1121 100644 --- a/decompiler/IR2/FormStack.cpp +++ b/decompiler/IR2/FormStack.cpp @@ -349,9 +349,9 @@ std::vector FormStack::rewrite(FormPool& pool, const Env& env) con auto elt = pool.alloc_element(*e.destination, simplified_source, e.sequence_point, type, e.set_info); - e.source->parent_element = elt; auto final_elt = try_rewrites_in_place(elt, env, pool); + simplified_source->parent_element = final_elt; result.push_back(final_elt); } else { result.push_back(e.elt); @@ -411,7 +411,6 @@ std::optional rewrite_to_get_var(std::vector& defa return {}; } else { for (auto x : result) { - x->parent_form = nullptr; default_result.push_back(x); } return result_access; diff --git a/decompiler/IR2/bitfields.cpp b/decompiler/IR2/bitfields.cpp index c7777c316b..c426fe3140 100644 --- a/decompiler/IR2/bitfields.cpp +++ b/decompiler/IR2/bitfields.cpp @@ -6,6 +6,7 @@ #include "common/util/BitUtils.h" #include "decompiler/util/DecompilerTypeSystem.h" #include "decompiler/IR2/GenericElementMatcher.h" +#include "decompiler/Function/Function.h" namespace decompiler { @@ -84,8 +85,12 @@ void BitfieldStaticDefElement::get_modified_regs(RegSet& regs) const { ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement( const TypeSpec& type, Form* base, + bool from_pcpyud, const std::vector& 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; for (auto& mod : m_field_modifications) { if (mod.value) { @@ -95,13 +100,23 @@ ModifiedCopyBitfieldElement::ModifiedCopyBitfieldElement( } goos::Object ModifiedCopyBitfieldElement::to_form_internal(const Env& env) const { - std::vector result = {pretty_print::to_symbol("copy-and-set-bf")}; - 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)); + if (m_field_modifications.size() == 1) { + std::vector 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 result = {pretty_print::to_symbol("copy-and-set-bf-multi")}; + 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); } - return pretty_print::build_list(result); } void ModifiedCopyBitfieldElement::apply(const std::function& f) { @@ -220,7 +235,8 @@ BitField find_field(const TypeSystem& ts, namespace { std::optional find_field_from_mask(const TypeSystem& ts, const BitFieldType* type, - uint64_t mask) { + uint64_t mask, + bool upper_64) { // try to find a field that is masked by this: auto mask_range = get_bit_range(mask); if (!mask_range) { @@ -228,6 +244,10 @@ std::optional find_field_from_mask(const TypeSystem& ts, return {}; } + if (upper_64) { + mask_range = Range(mask_range->first() + 64, mask_range->last() + 64); + } + 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 get_bitfield_initial_set(Form* form, const BitFieldType* type, - const TypeSystem& ts) { + const TypeSystem& ts, + int offset_in_bitfield) { // (shr (shl arg1 59) 44) for example { auto matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::SHR), @@ -255,7 +276,7 @@ std::optional get_bitfield_initial_set(Form* form, int right = mr.maps.ints.at(2); int size = 64 - left; 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; def.value = value; def.field_name = f.name(); @@ -278,7 +299,7 @@ std::optional get_bitfield_initial_set(Form* form, int right = *power_of_two; int size = 64 - left; 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; def.value = value; def.field_name = f.name(); @@ -298,7 +319,7 @@ std::optional get_bitfield_initial_set(Form* form, int right = 0; int size = 64 - left; 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; def.value = value; def.field_name = f.name(); @@ -313,7 +334,7 @@ std::optional get_bitfield_initial_set(Form* form, auto value = mr_sllv.maps.forms.at(0); int size = 32; int offset = 0; - auto f = find_field(ts, type, offset, size, {}); + auto f = find_field(ts, type, offset + offset_in_bitfield, size, {}); BitFieldDef def; def.value = value; 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 * access @@ -434,9 +468,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step, if (m_steps.empty() && step.kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT) { // and with mask - if (m_got_pcpyud) { - throw std::runtime_error("unknown pcpyud LOGAND_WITH_CONSTANT_INT sequence in bitfield"); - } + // no need to do anything with pcpyud here. m_steps.push_back(step); return nullptr; } @@ -449,7 +481,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step, auto type = ts.lookup_type(m_type); auto as_bitfield = dynamic_cast(type); 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) { auto get_field = pool.alloc_element(m_base, false, 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 && 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. // first, let's check that the mask is used properly: u64 mask = m_steps.at(0).amount; @@ -477,7 +506,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step, auto as_bitfield = dynamic_cast(type); assert(as_bitfield); // 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); bool is_signed = 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. u64 set_value; if (is_signed) { - set_value = extract_bitfield(value, field->offset(), field->size()); + set_value = extract_bitfield(value, field->offset() - pcpyud_offset, field->size()); } else { - set_value = extract_bitfield(value, field->offset(), field->size()); + set_value = extract_bitfield(value, field->offset() - pcpyud_offset, field->size()); } BitFieldDef def; def.field_name = field->name(); def.value = pool.alloc_single_element_form( nullptr, SimpleAtom::make_int_constant(set_value)); - return pool.alloc_element(m_type, m_base, + return pool.alloc_element(m_type, m_base, m_got_pcpyud, std::vector{def}); } if (m_steps.size() == 1 && m_steps.at(0).kind == BitfieldManip::Kind::LOGAND_WITH_CONSTANT_INT && 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 u64 mask = m_steps.at(0).amount; @@ -510,10 +536,10 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step, auto as_bitfield = dynamic_cast(type); assert(as_bitfield); // 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); - 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) { throw std::runtime_error( @@ -524,7 +550,7 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step, throw std::runtime_error("Incompatible bitfield set"); } - return pool.alloc_element(m_type, m_base, + return pool.alloc_element(m_type, m_base, m_got_pcpyud, std::vector{*val}); } @@ -532,7 +558,10 @@ FormElement* BitfieldAccessElement::push_step(const BitfieldManip step, for (auto& old_step : m_steps) { 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"); } @@ -595,6 +624,22 @@ std::optional get_goal_integer_constant(Form* in, const Env&) { return result; } } + + // also (shl (shl 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 {}; } @@ -713,8 +758,9 @@ Form* cast_to_bitfield(const BitFieldType* type_info, // now variables for (auto& arg : args) { + // it's a 64-bit constant so correct to set offset 0 here. 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) { // failed, just return cast. return pool.alloc_single_element_form(nullptr, typespec, in); diff --git a/decompiler/IR2/bitfields.h b/decompiler/IR2/bitfields.h index 1ae1b8f09d..8715378b67 100644 --- a/decompiler/IR2/bitfields.h +++ b/decompiler/IR2/bitfields.h @@ -101,6 +101,8 @@ class BitfieldAccessElement : public FormElement { 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: bool m_got_pcpyud = false; @@ -155,6 +157,7 @@ class ModifiedCopyBitfieldElement : public FormElement { public: ModifiedCopyBitfieldElement(const TypeSpec& type, Form* base, + bool from_pcpyud, const std::vector& field_modifications); goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; @@ -164,11 +167,17 @@ class ModifiedCopyBitfieldElement : public FormElement { Form* base() const { return m_base; } const std::vector 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: TypeSpec m_type; Form* m_base = nullptr; std::vector m_field_modifications; + bool m_from_pcpyud = false; }; Form* cast_to_bitfield(const BitFieldType* type_info, diff --git a/decompiler/analysis/expression_build.cpp b/decompiler/analysis/expression_build.cpp index aa9b637935..97e495db5f 100644 --- a/decompiler/analysis/expression_build.cpp +++ b/decompiler/analysis/expression_build.cpp @@ -85,10 +85,15 @@ bool convert_to_expressions( if (!dts.ts.tc(f.type.last_arg(), return_type)) { // we need to cast the final value. auto to_cast = new_entries.back(); - new_entries.pop_back(); - auto cast = pool.alloc_element(f.type.last_arg(), - pool.alloc_single_form(nullptr, to_cast)); - new_entries.push_back(cast); + auto as_cast = dynamic_cast(to_cast); + if (as_cast) { + as_cast->set_type(f.type.last_arg()); + } else { + new_entries.pop_back(); + auto cast = pool.alloc_element(f.type.last_arg(), + pool.alloc_single_form(nullptr, to_cast)); + new_entries.push_back(cast); + } } } else { // or just get all the expressions diff --git a/decompiler/analysis/insert_lets.cpp b/decompiler/analysis/insert_lets.cpp index ff390f8db0..7ab2b4d838 100644 --- a/decompiler/analysis/insert_lets.cpp +++ b/decompiler/analysis/insert_lets.cpp @@ -79,8 +79,8 @@ Form* lca_form(Form* a, Form* b, const Env& env) { bi--; } if (!result) { - auto* bad = b->parent_element; - fmt::print("bad form is {} {}\n", bad->to_string(env), (void*)bad); + fmt::print("{} bad form is {}\n\n{}\n", env.func->guessed_name.to_string(), a->to_string(env), + b->to_string(env)); } assert(result); diff --git a/decompiler/analysis/variable_naming.cpp b/decompiler/analysis/variable_naming.cpp index 2d473ab7ca..7115642180 100644 --- a/decompiler/analysis/variable_naming.cpp +++ b/decompiler/analysis/variable_naming.cpp @@ -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); // copy types from input argument coloring moves: diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 1ce871a73d..66fb25521f 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -9325,10 +9325,10 @@ (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-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) - (dummy-17 (_type_ res-tag pointer) res-lump 17) - (dummy-18 (_type_ res-tag res-tag) res-lump 18) + (add-data! (_type_ res-tag pointer) res-lump 17) + (add-32bit-data! (_type_ res-tag object) res-lump 18) (lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19) (make-property-data (_type_ float res-tag-pair pointer) pointer 20) (get-curve-data! (_type_ curve symbol symbol float) symbol 21) @@ -9346,9 +9346,6 @@ ;; Containing DGOs - ['GAME', 'ENGINE'] ;; Version - 3 -;; - Functions - -(define-extern part-group-pointer? function) ;; - Symbols @@ -13254,6 +13251,8 @@ ) +(define-extern part-group-pointer? (function pointer symbol)) + ;; ---------------------- ;; File - sparticle-h ;; Source Path - engine/sparticle/sparticle-h.gc diff --git a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc index fd2dd9306d..d8c69f6f60 100644 --- a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc @@ -154,13 +154,13 @@ ["L17", "ocean-colors", true], ["L15", "ocean-near-indices", true], ["L9", "ocean-near-indices", true], - + ["L14", "ocean-trans-indices", true], ["L8", "ocean-trans-indices", true], - + ["L13", "ocean-mid-indices", true], ["L7", "ocean-mid-indices", true], - + ["L11", "ocean-mid-masks", true], ["L5", "ocean-mid-masks", true], ["L4", "ocean-map", true], @@ -453,7 +453,12 @@ "trajectory": [["L18", "uint64", true]], - "res": [["L150", "uint64", true]], + "res": [ + ["L150", "uint64", true], + ["L152", "uint64", true], + ["L151", "uint64", true], + ["L153", "uint64", true] + ], "ripple": [ ["L73", "float", true], @@ -559,9 +564,7 @@ ["L12", "uint64", true] ], - "shadow-cpu": [ - ["L122", "shadow-data", true] - ], + "shadow-cpu": [["L122", "shadow-data", true]], "entity-table": [["L8", "(array entity-info)", true]], diff --git a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc index 8adbe2f29f..8355f7e1e1 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc @@ -414,9 +414,7 @@ [157, "a0", "(pointer process-drawable)"] ], - "load-game-text-info": [ - [4, "v1", "game-text-info"] - ], + "load-game-text-info": [[4, "v1", "game-text-info"]], "texture-relocate": [ [[17, 21], "t4", "dma-packet"], @@ -506,12 +504,29 @@ [22, "t1", "(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)": [ ["_stack_", 16, "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 "(method 10 shadow-control)": [[1, "v1", "int"]], @@ -1172,5 +1187,7 @@ "blackout": [[[20, 24], "v1", "dma-packet"]], + "(method 10 external-art-control)": [[18, "v1", "pointer"]], + "placeholder-do-not-add-below": [] } diff --git a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc index 306c264332..abed42d99e 100644 --- a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc @@ -1798,7 +1798,29 @@ }, "(method 15 res-lump)": { "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" + } }, diff --git a/decompiler/util/TP_Type.cpp b/decompiler/util/TP_Type.cpp index 5682efefb6..bf6048708c 100644 --- a/decompiler/util/TP_Type.cpp +++ b/decompiler/util/TP_Type.cpp @@ -67,6 +67,8 @@ std::string TP_Type::print() const { } case Kind::PCPYUD_BITFIELD: return fmt::format("", m_ts.print()); + case Kind::PCPYUD_BITFIELD_AND: + return fmt::format("", m_ts.print()); case Kind::LABEL_ADDR: return ""; 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; case Kind::PCPYUD_BITFIELD: 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: return true; case Kind::INVALID: @@ -177,6 +181,8 @@ TypeSpec TP_Type::typespec() const { return TypeSpec("int"); // ideally this is never used. case Kind::PCPYUD_BITFIELD: return TypeSpec("int"); + case Kind::PCPYUD_BITFIELD_AND: + return TypeSpec("int"); case Kind::LABEL_ADDR: return TypeSpec("pointer"); // ? case Kind::INVALID: diff --git a/decompiler/util/TP_Type.h b/decompiler/util/TP_Type.h index bde2ffa536..9d0010df38 100644 --- a/decompiler/util/TP_Type.h +++ b/decompiler/util/TP_Type.h @@ -33,6 +33,7 @@ class TP_Type { VIRTUAL_METHOD, NON_VIRTUAL_METHOD, PCPYUD_BITFIELD, + PCPYUD_BITFIELD_AND, LEFT_SHIFTED_BITFIELD, // (bitfield << some-constant) LABEL_ADDR, INVALID @@ -62,6 +63,7 @@ class TP_Type { case Kind::NON_VIRTUAL_METHOD: case Kind::LEFT_SHIFTED_BITFIELD: case Kind::PCPYUD_BITFIELD: + case Kind::PCPYUD_BITFIELD_AND: case Kind::LABEL_ADDR: return false; case Kind::UNINITIALIZED: @@ -244,6 +246,14 @@ class TP_Type { 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() { TP_Type result; result.kind = Kind::LABEL_ADDR; @@ -296,7 +306,8 @@ class TP_Type { } 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; } diff --git a/goal_src/engine/data/res-h.gc b/goal_src/engine/data/res-h.gc index 743e0d8284..bf376f85fe 100644 --- a/goal_src/engine/data/res-h.gc +++ b/goal_src/engine/data/res-h.gc @@ -47,10 +47,10 @@ (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-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) - (dummy-17 (_type_ res-tag pointer) res-lump 17) - (dummy-18 (_type_ res-tag res-tag) res-lump 18) + (add-data! (_type_ res-tag pointer) res-lump 17) + (add-32bit-data! (_type_ res-tag object) res-lump 18) (lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19) (make-property-data (_type_ float res-tag-pair pointer) pointer 20) (get-curve-data! (_type_ curve symbol symbol float) symbol 21) diff --git a/goal_src/engine/data/res.gc b/goal_src/engine/data/res.gc index 152f0f101a..f2f50cfa18 100644 --- a/goal_src/engine/data/res.gc +++ b/goal_src/engine/data/res.gc @@ -67,7 +67,7 @@ This is updated from the entity system used in Crash 2, which had most of these (the int (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)) ) @@ -685,6 +685,148 @@ This is updated from the entity system used in Crash 2, which had most of these 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)) "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 -;; method 17 res-lump -;; method 18 res-lump -;; mem-usage res-lump +(define-extern part-group-pointer? (function pointer symbol)) +(declare-type nav-mesh basic) +(declare-type collide-mesh basic) +(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)) diff --git a/goal_src/engine/sparticle/sparticle-h.gc b/goal_src/engine/sparticle/sparticle-h.gc index feff9a13ef..e140822f03 100644 --- a/goal_src/engine/sparticle/sparticle-h.gc +++ b/goal_src/engine/sparticle/sparticle-h.gc @@ -81,3 +81,5 @@ :size-assert #x34 :flag-assert #x900000034 ) + +(define-extern part-group-pointer? (function pointer symbol)) diff --git a/goal_src/kernel/gcommon.gc b/goal_src/kernel/gcommon.gc index e2e9131d6b..426bbb3987 100644 --- a/goal_src/kernel/gcommon.gc +++ b/goal_src/kernel/gcommon.gc @@ -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 + ) + ) + diff --git a/test/decompiler/reference/decompiler-macros.gc b/test/decompiler/reference/decompiler-macros.gc index ed281abd9f..09e598077b 100644 --- a/test/decompiler/reference/decompiler-macros.gc +++ b/test/decompiler/reference/decompiler-macros.gc @@ -190,3 +190,10 @@ `(* (/ 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 + ) + ) + diff --git a/test/decompiler/reference/engine/data/res-h_REF.gc b/test/decompiler/reference/engine/data/res-h_REF.gc index c816137876..2a595e5a7b 100644 --- a/test/decompiler/reference/engine/data/res-h_REF.gc +++ b/test/decompiler/reference/engine/data/res-h_REF.gc @@ -36,10 +36,10 @@ (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-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) - (dummy-17 (_type_ res-tag pointer) res-lump 17) - (dummy-18 (_type_ res-tag res-tag) res-lump 18) + (add-data! (_type_ res-tag pointer) res-lump 17) + (add-32bit-data! (_type_ res-tag object) res-lump 18) (lookup-tag-idx (_type_ symbol symbol float) res-tag-pair :no-virtual 19) (make-property-data (_type_ float res-tag-pair pointer) pointer 20) (get-curve-data! (_type_ curve symbol symbol float) symbol 21) @@ -47,6 +47,7 @@ ) ;; 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)) (format #t "[~8x] ~A~%" obj (-> obj type)) (format #t "~Tlength: ~D~%" (-> obj length)) diff --git a/test/decompiler/reference/engine/data/res_REF.gc b/test/decompiler/reference/engine/data/res_REF.gc new file mode 100644 index 0000000000..013febf6a1 --- /dev/null +++ b/test/decompiler/reference/engine/data/res_REF.gc @@ -0,0 +1,1151 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for method 2 of type res-tag +(defmethod print res-tag ((obj res-tag)) + (if (zero? (-> obj inlined?)) + (format + #t + "#" + (-> obj name) + (-> obj key-frame) + (-> obj elt-type) + (-> obj elt-count) + ) + (format + #t + "#" + (-> obj name) + (-> obj key-frame) + (-> obj elt-type) + (-> obj elt-count) + ) + ) + obj + ) + +;; definition for method 4 of type res-tag +;; INFO: Return type mismatch uint vs int. +(defmethod length res-tag ((obj res-tag)) + (the-as int (if (zero? (-> obj inlined?)) + (* (-> obj elt-count) 4) + (* (-> obj elt-count) (-> obj elt-type size)) + ) + ) + ) + +;; definition for method 13 of type res-lump +;; Used lq/sq +(defmethod get-tag-index-data res-lump ((obj res-lump) (arg0 int)) + (&+ (-> obj data-base) (-> obj tag arg0 data-offset)) + ) + +;; definition for method 14 of type res-lump +(defmethod get-tag-data res-lump ((obj res-lump) (arg0 res-tag)) + (&+ (-> obj data-base) (-> arg0 data-offset)) + ) + +;; definition for method 0 of type res-lump +(defmethod + new + res-lump + ((allocation symbol) (type-to-make type) (data-count int) (data-size int)) + (let + ((obj + (object-new + allocation + type-to-make + (the-as + int + (+ + (+ (-> type-to-make size) (the-as uint (* (+ data-count -1) 16))) + (the-as uint data-size) + ) + ) + ) + ) + ) + (set! (-> obj allocated-length) data-count) + (set! (-> obj data-size) data-size) + (set! (-> obj length) 0) + (set! (-> obj data-base) (&-> (-> obj tag) data-count)) + (set! (-> obj data-top) (&-> (-> obj tag) data-count)) + obj + ) + ) + +;; definition for method 4 of type res-lump +(defmethod length res-lump ((obj res-lump)) + (-> obj length) + ) + +;; definition for method 5 of type res-lump +;; INFO: Return type mismatch uint vs int. +(defmethod asize-of res-lump ((obj res-lump)) + (the-as + int + (+ + (+ (-> obj type psize) (the-as uint (* (-> obj allocated-length) 16))) + (the-as uint (-> obj data-size)) + ) + ) + ) + +;; definition for method 3 of type res-lump +;; INFO: this function exists in multiple non-identical object files +;; Used lq/sq +(defmethod inspect res-lump ((obj res-lump)) + (format #t "[~8x] ~A~%" obj (-> obj type)) + (format #t "~Textra: ~A~%" (-> obj extra)) + (format #t "~Tallocated-length: ~D~%" (-> obj allocated-length)) + (format #t "~Tlength: ~D~%" (-> obj length)) + (format #t "~Tdata-base: #x~X~%" (-> obj data-base)) + (format #t "~Tdata-top: #x~X~%" (-> obj data-top)) + (format #t "~Tdata-size: #x~X~%" (-> obj data-size)) + (format #t "~Ttag[~D]: @ #x~X~%" (-> obj allocated-length) (-> obj tag)) + (dotimes (i (-> obj length)) + (format #t "~T [~D] " i) + (print (-> obj tag i)) + (let ((t9-10 format) + (a0-12 #t) + (a1-9 " @ #x~X") + (a3-2 obj) + (a2-9 i) + ) + (t9-10 a0-12 a1-9 (&+ (-> a3-2 data-base) (-> a3-2 tag a2-9 data-offset))) + ) + (cond + ((zero? (-> obj tag i inlined?)) + (let ((t9-11 format) + (a0-14 #t) + (a1-10 " = ~A~%") + (a3-4 obj) + (a2-17 i) + ) + (t9-11 + a0-14 + a1-10 + (-> + (the-as + (pointer uint32) + (&+ (-> a3-4 data-base) (-> a3-4 tag a2-17 data-offset)) + ) + ) + ) + ) + ) + (else + (format #t "~%") + ) + ) + ) + obj + ) + +;; definition for method 19 of type res-lump +;; INFO: Return type mismatch int vs res-tag-pair. +;; Used lq/sq +(defmethod + lookup-tag-idx + res-lump + ((obj res-lump) (name-sym symbol) (mode symbol) (time float)) + (local-vars (tag-idx int)) + (when + (or + (= name-sym 'id) + (= name-sym 'aid) + (= name-sym 'trans) + (= name-sym 'rot) + (= name-sym 'nav-mesh) + (= name-sym 'process-type) + (= name-sym 'task) + ) + (crash!) + 0 + ) + (if (or (not obj) (zero? obj) (<= (-> obj length) 0)) + (return (new 'static 'res-tag-pair :lo #xffffffff :hi #xffffffff)) + ) + (let ((hi-tag-idx-out -1) + (lo-tag-idx-out -1) + ) + (let ((most-recent-invalid-time-idx -1) + (type-chars + (-> (the-as (pointer uint64) (-> (symbol->string name-sym) data)) 0) + ) + ) + (let ((max-search (+ (-> obj length) -1)) + (min-search 0) + ) + (while (>= max-search min-search) + (let* ((check-idx (+ min-search (/ (- max-search min-search) 2))) + (diff + (- + type-chars + (-> + (the-as + (pointer uint64) + (-> (symbol->string (-> obj tag check-idx name)) data) + ) + 0 + ) + ) + ) + ) + (cond + ((zero? diff) + (set! tag-idx check-idx) + (goto cfg-32) + ) + ((< (the-as int diff) 0) + (set! max-search (+ check-idx -1)) + ) + (else + (set! min-search (+ check-idx 1)) + ) + ) + ) + ) + ) + (set! tag-idx -1) + (label cfg-32) + (if (< tag-idx 0) + (return (the-as res-tag-pair tag-idx)) + ) + (while + (and + (> tag-idx 0) + (= + type-chars + (-> + (the-as + (pointer uint64) + (-> (symbol->string (-> obj tag (+ tag-idx -1) name)) data) + ) + 0 + ) + ) + ) + (+! tag-idx -1) + ) + (when (= mode 'base) + (set! lo-tag-idx-out tag-idx) + (set! hi-tag-idx-out tag-idx) + (goto cfg-73) + ) + (let ((interp-tag-idx tag-idx) + (tag-ptr (&-> (-> obj tag) tag-idx)) + ) + (while + (not + (or + (>= interp-tag-idx (-> obj length)) + (< + type-chars + (-> + (the-as + (pointer uint64) + (-> (symbol->string (-> tag-ptr 0 name)) data) + ) + 0 + ) + ) + ) + ) + (cond + ((!= name-sym (-> tag-ptr 0 name)) + ) + ((= (-> tag-ptr 0 key-frame) time) + (set! lo-tag-idx-out interp-tag-idx) + (set! hi-tag-idx-out interp-tag-idx) + (goto cfg-73) + ) + ((and (>= time (-> tag-ptr 0 key-frame)) (!= mode 'exact)) + (set! lo-tag-idx-out interp-tag-idx) + (set! hi-tag-idx-out interp-tag-idx) + (if (= (-> tag-ptr 0 key-frame) -1000000000.0) + (set! most-recent-invalid-time-idx interp-tag-idx) + ) + ) + ((< time (-> tag-ptr 0 key-frame)) + (if + (and (!= lo-tag-idx-out most-recent-invalid-time-idx) (= mode 'interp)) + (set! hi-tag-idx-out interp-tag-idx) + ) + (goto cfg-73) + ) + ) + (+! interp-tag-idx 1) + (set! tag-ptr (&-> tag-ptr 1)) + ) + ) + ) + (label cfg-73) + (the-as + res-tag-pair + (logior + (logand (the-as uint #xffffffff) (the-as uint lo-tag-idx-out)) + (the-as uint (shl hi-tag-idx-out 32)) + ) + ) + ) + ) + +;; definition for method 20 of type res-lump +;; Used lq/sq +(defmethod + make-property-data + res-lump + ((obj res-lump) (time float) (result res-tag-pair) (buf pointer)) + (rlet ((vf1 :class vf) + (vf2 :class vf) + (vf3 :class vf) + (vf4 :class vf) + ) + (let* ((tag-lo (-> obj tag (-> result lo))) + (tag-hi (-> obj tag (-> result hi))) + (elt-count (-> tag-lo elt-count)) + ) + (cond + ((zero? (-> tag-lo inlined?)) + (&+ (-> obj data-base) (-> tag-lo data-offset)) + ) + ((or + (not buf) + (= (-> result lo) (-> result hi)) + (!= elt-count (-> tag-hi elt-count)) + (!= (-> tag-lo elt-type) (-> tag-hi elt-type)) + ) + (let ((a0-4 tag-lo)) + (&+ (-> obj data-base) (-> a0-4 data-offset)) + ) + ) + (else + (let* + ((interp + (/ + (- time (-> tag-lo key-frame)) + (- (-> tag-hi key-frame) (-> tag-lo key-frame)) + ) + ) + (a1-4 obj) + (a2-7 tag-lo) + (src-lo (&+ (-> a1-4 data-base) (-> a2-7 data-offset))) + (src-hi (&+ (-> obj data-base) (-> tag-hi data-offset))) + ) + (case (-> tag-lo elt-type symbol) + (('float) + (dotimes (a0-8 (the-as int elt-count)) + (set! + (-> (the-as (pointer float) (&+ buf (* a0-8 4)))) + (+ + (* + (-> (the-as (pointer float) (&+ src-lo (* a0-8 4)))) + (- 1.0 interp) + ) + (* (-> (the-as (pointer float) (&+ src-hi (* a0-8 4)))) interp) + ) + ) + ) + buf + ) + (('integer 'sinteger 'uinteger 'int64 'uint64) + (let ((a0-9 (the int (* 4096.0 interp)))) + (dotimes (t0-9 (the-as int elt-count)) + (set! + (-> (the-as (pointer int64) (&+ buf (* t0-9 8)))) + (sar + (+ + (* + (the-as + int + (-> (the-as (pointer uint64) (&+ src-lo (* t0-9 8)))) + ) + (- 4096 a0-9) + ) + (* + (the-as + int + (-> (the-as (pointer uint64) (&+ src-hi (* t0-9 8)))) + ) + a0-9 + ) + ) + 12 + ) + ) + ) + ) + buf + ) + (('int8) + (let ((a0-10 (the int (* 4096.0 interp)))) + (dotimes (t0-10 (the-as int elt-count)) + (set! + (-> (the-as (pointer int8) (&+ buf t0-10))) + (sar + (+ + (* (-> (the-as (pointer int8) (&+ src-lo t0-10))) (- 4096 a0-10)) + (* (-> (the-as (pointer int8) (&+ src-hi t0-10))) a0-10) + ) + 12 + ) + ) + ) + ) + buf + ) + (('uint8) + (let ((a0-11 (the int (* 4096.0 interp)))) + (dotimes (t0-11 (the-as int elt-count)) + (set! + (-> (the-as (pointer uint8) (&+ buf t0-11))) + (shr + (+ + (* + (-> (the-as (pointer uint8) (&+ src-lo t0-11))) + (the-as uint (- 4096 a0-11)) + ) + (* + (-> (the-as (pointer uint8) (&+ src-hi t0-11))) + (the-as uint a0-11) + ) + ) + 12 + ) + ) + ) + ) + buf + ) + (('int16) + (let ((a0-12 (the int (* 4096.0 interp)))) + (dotimes (t0-12 (the-as int elt-count)) + (set! + (-> (the-as (pointer int16) (&+ buf (* t0-12 2)))) + (sar + (+ + (* + (-> (the-as (pointer int16) (&+ src-lo (* t0-12 2)))) + (- 4096 a0-12) + ) + (* (-> (the-as (pointer int16) (&+ src-hi (* t0-12 2)))) a0-12) + ) + 12 + ) + ) + ) + ) + buf + ) + (('uint16) + (let ((a0-13 (the int (* 4096.0 interp)))) + (dotimes (t0-13 (the-as int elt-count)) + (set! + (-> (the-as (pointer uint16) (&+ buf (* t0-13 2)))) + (shr + (+ + (* + (-> (the-as (pointer uint16) (&+ src-lo (* t0-13 2)))) + (the-as uint (- 4096 a0-13)) + ) + (* + (-> (the-as (pointer uint16) (&+ src-hi (* t0-13 2)))) + (the-as uint a0-13) + ) + ) + 12 + ) + ) + ) + ) + buf + ) + (('int32) + (let ((a0-14 (the int (* 4096.0 interp)))) + (dotimes (t0-14 (the-as int elt-count)) + (set! + (-> (the-as (pointer int32) (&+ buf (* t0-14 4)))) + (sar + (+ + (* + (-> (the-as (pointer int32) (&+ src-lo (* t0-14 4)))) + (- 4096 a0-14) + ) + (* (-> (the-as (pointer int32) (&+ src-hi (* t0-14 4)))) a0-14) + ) + 12 + ) + ) + ) + ) + buf + ) + (('uint32) + (let ((a0-15 (the int (* 4096.0 interp)))) + (dotimes (t0-15 (the-as int elt-count)) + (set! + (-> (the-as (pointer uint32) (&+ buf (* t0-15 4)))) + (shr + (+ + (* + (-> (the-as (pointer uint32) (&+ src-lo (* t0-15 4)))) + (the-as uint (- 4096 a0-15)) + ) + (* + (-> (the-as (pointer uint32) (&+ src-hi (* t0-15 4)))) + (the-as uint a0-15) + ) + ) + 12 + ) + ) + ) + ) + buf + ) + (('vector) + (let ((a0-16 interp)) + (.mov vf3 a0-16) + ) + (let ((a0-17 (- 1.0 interp))) + (.mov vf4 a0-17) + ) + (dotimes (a0-18 (the-as int elt-count)) + (let ((t0-17 (+ (* a0-18 16) (the-as int src-lo)))) + (.lvf vf1 (&-> (the-as (pointer int128) t0-17))) + ) + (let ((t0-19 (+ (* a0-18 16) (the-as int src-hi)))) + (.lvf vf2 (&-> (the-as (pointer int128) t0-19))) + ) + (.mul.x.vf vf1 vf1 vf4) + (.mul.x.vf vf2 vf2 vf3) + (.add.vf vf1 vf1 vf2) + (.svf (&-> (-> (the-as (inline-array vector) buf) a0-18) quad) vf1) + ) + buf + ) + (else + (let ((a0-19 tag-lo)) + (&+ (-> obj data-base) (-> a0-19 data-offset)) + ) + ) + ) + ) + ) + ) + ) + ) + ) + +;; definition for method 9 of type res-lump +;; Used lq/sq +(defmethod + get-property-data + res-lump + ((obj res-lump) + (name symbol) + (mode symbol) + (time float) + (default pointer) + (tag-addr (pointer res-tag)) + (buf-addr pointer) + ) + (let ((tag-pair (lookup-tag-idx obj name mode time))) + (cond + ((< (the-as int tag-pair) 0) + (empty) + ) + (else + (set! default (make-property-data obj time tag-pair buf-addr)) + (if tag-addr + (set! (-> tag-addr 0) (-> obj tag (-> tag-pair lo))) + ) + ) + ) + ) + default + ) + +;; definition for method 10 of type res-lump +;; INFO: Return type mismatch object vs structure. +;; Used lq/sq +(defmethod + get-property-struct + res-lump + ((obj res-lump) + (name symbol) + (mode symbol) + (time float) + (default structure) + (tag-addr (pointer res-tag)) + (buf-addr pointer) + ) + (let ((tag-pair (lookup-tag-idx obj name mode time))) + (cond + ((< (the-as int tag-pair) 0) + (empty) + ) + (else + (set! + default + (the-as structure (make-property-data obj time tag-pair buf-addr)) + ) + (let ((tag (-> obj tag (-> tag-pair lo)))) + (if tag-addr + (set! (-> tag-addr 0) tag) + ) + (if (zero? (-> tag inlined?)) + (set! default (the-as structure (-> (the-as (pointer uint32) default)))) + (empty) + ) + ) + ) + ) + ) + (the-as structure default) + ) + +;; definition for method 11 of type res-lump +;; INFO: Return type mismatch int vs uint128. +;; Used lq/sq +(defmethod + get-property-value + res-lump + ((obj res-lump) + (name symbol) + (mode symbol) + (time float) + (default uint128) + (tag-addr (pointer res-tag)) + (buf-addr pointer) + ) + (let ((tag-pair (lookup-tag-idx obj name mode time))) + (cond + ((< (the-as int tag-pair) 0) + (empty) + ) + (else + (let* ((a0-2 (-> tag-pair lo)) + (tag (-> obj tag a0-2)) + (tag-type (-> tag elt-type)) + (data (make-property-data obj time tag-pair buf-addr)) + ) + (if tag-addr + (set! (-> tag-addr 0) tag) + ) + (cond + ((type-type? tag-type uinteger) + (case (-> tag elt-type size) + ((1) + (set! default (the-as uint128 (-> (the-as (pointer uint8) data)))) + ) + ((2) + (set! default (the-as uint128 (-> (the-as (pointer uint16) data)))) + ) + ((4) + (set! default (the-as uint128 (-> (the-as (pointer uint32) data)))) + ) + ((16) + (set! default (-> (the-as (pointer uint128) data))) + ) + (else + (set! default (the-as uint128 (-> (the-as (pointer uint64) data)))) + ) + ) + ) + ((type-type? tag-type integer) + (case (-> tag elt-type size) + ((1) + (set! default (the-as uint128 (-> (the-as (pointer int8) data)))) + ) + ((2) + (set! default (the-as uint128 (-> (the-as (pointer int16) data)))) + ) + ((4) + (set! default (the-as uint128 (-> (the-as (pointer int32) data)))) + ) + ((16) + (set! default (-> (the-as (pointer uint128) data))) + ) + (else + (set! default (the-as uint128 (-> (the-as (pointer uint64) data)))) + ) + ) + ) + ((type-type? tag-type float) + (set! + default + (the-as uint128 (the int (-> (the-as (pointer float) data)))) + ) + ) + (else + (empty) + ) + ) + ) + ) + ) + ) + (the-as uint128 default) + ) + +;; definition for method 12 of type res-lump +;; Used lq/sq +(defmethod + get-property-value-float + res-lump + ((obj res-lump) + (name symbol) + (mode symbol) + (time float) + (default float) + (tag-addr (pointer res-tag)) + (buf-addr pointer) + ) + (local-vars (v1-8 uint) (v1-11 int)) + (let ((tag-pair (lookup-tag-idx obj name mode time))) + (cond + ((< (the-as int tag-pair) 0) + (empty) + ) + (else + (let* ((a0-2 (-> tag-pair lo)) + (tag (-> obj tag a0-2)) + (tag-type (-> tag elt-type)) + (data (make-property-data obj time tag-pair buf-addr)) + ) + (if tag-addr + (set! (-> tag-addr 0) tag) + ) + (cond + ((type-type? tag-type float) + (set! default (-> (the-as (pointer float) data))) + ) + ((type-type? tag-type uinteger) + (case (-> tag elt-type size) + ((1) + (set! v1-8 (-> (the-as (pointer uint8) data))) + ) + ((2) + (set! v1-8 (-> (the-as (pointer uint16) data))) + ) + ((4) + (set! v1-8 (-> (the-as (pointer uint32) data))) + ) + ((16) + (set! v1-8 (the-as uint (-> (the-as (pointer uint128) data)))) + ) + (else + (set! v1-8 (-> (the-as (pointer uint64) data))) + ) + ) + (set! default (the float v1-8)) + ) + ((type-type? tag-type integer) + (case (-> tag elt-type size) + ((1) + (set! v1-11 (-> (the-as (pointer int8) data))) + ) + ((2) + (set! v1-11 (-> (the-as (pointer int16) data))) + ) + ((4) + (set! v1-11 (-> (the-as (pointer int32) data))) + ) + ((16) + (set! v1-11 (the-as int (-> (the-as (pointer uint128) data)))) + ) + (else + (set! v1-11 (the-as int (-> (the-as (pointer uint64) data)))) + ) + ) + (set! default (the float v1-11)) + ) + (else + (empty) + ) + ) + ) + ) + ) + ) + default + ) + +;; definition for method 16 of type res-lump +;; Used lq/sq +(defmethod sort! res-lump ((obj res-lump)) + (let ((tags-sorted -1)) + (while (nonzero? tags-sorted) + (set! tags-sorted 0) + (let ((i 0) + (tag-stop (+ (-> obj length) -2)) + ) + (while (>= tag-stop i) + (let* ((tag1 (-> obj tag i)) + (tag2 (-> obj tag (+ i 1))) + (tag-name1 + (-> + (the-as + (pointer uint64) + (-> (symbol->string (-> tag1 name)) data) + ) + 0 + ) + ) + (tag-name2 + (-> + (the-as + (pointer uint64) + (-> (symbol->string (-> tag2 name)) data) + ) + 0 + ) + ) + ) + (when + (or + (< tag-name2 tag-name1) + (and + (= tag-name1 tag-name2) + (< (-> tag2 key-frame) (-> tag1 key-frame)) + ) + ) + (+! tags-sorted 1) + (set! (-> obj tag i) tag2) + (set! (-> obj tag (+ i 1)) tag1) + ) + ) + (+! i 1) + ) + ) + ) + ) + obj + ) + +;; definition for method 15 of type res-lump +;; Used lq/sq +(defmethod allocate-data-memory-for-tag! res-lump ((obj res-lump) (arg0 res-tag)) + (local-vars (resource-mem pointer)) + (let* + ((tag-pair (lookup-tag-idx obj (-> arg0 name) 'exact (-> arg0 key-frame))) + (existing-tag (-> obj tag (-> tag-pair lo))) + ) + 0 + (if + (and + (>= (the-as int tag-pair) 0) + (!= (-> arg0 key-frame) (-> arg0 key-frame)) + ) + (set! tag-pair (new 'static 'res-tag-pair :lo #xffffffff :hi #xffffffff)) + ) + (if (zero? (-> arg0 elt-count)) + (set! arg0 (copy-and-set-field arg0 elt-count 1)) + ) + (let ((data-size (length arg0))) + (cond + ((and + (>= (the-as int tag-pair) 0) + (>= (the-as uint (length existing-tag)) (the-as uint data-size)) + ) + (set! resource-mem (&+ (-> obj data-base) (-> existing-tag data-offset))) + (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 + (set! resource-mem (logand -16 (&+ (-> obj data-top) 15))) + (set! (-> obj data-top) (&+ resource-mem data-size)) + ) + ) + (let* ((a0-22 arg0) + (s4-1 + (copy-and-set-field + a0-22 + data-offset + (&- resource-mem (the-as uint (-> obj data-base))) + ) + ) + ) + (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.~%" + s4-1 + data-size + obj + ) + (return (the-as res-tag #f)) + ) + (cond + ((< (the-as int tag-pair) 0) + (cond + ((>= (-> obj length) (-> obj allocated-length)) + (format + 0 + "ERROR: attempting to a new tag ~`res-tag`P to ~A, but tag memory is full.~%" + s4-1 + obj + ) + (return (the-as res-tag #f)) + ) + (else + (set! (-> obj tag (-> obj length)) s4-1) + (set! (-> obj length) (+ (-> obj length) 1)) + (sort! obj) + ) + ) + ) + (else + (set! (-> obj tag (-> tag-pair lo)) s4-1) + ) + ) + s4-1 + ) + ) + ) + ) + +;; definition for method 17 of type res-lump +(defmethod add-data! res-lump ((obj res-lump) (arg0 res-tag) (arg1 pointer)) + (let ((new-tag (allocate-data-memory-for-tag! obj arg0))) + (when new-tag + (let* ((v1-2 obj) + (a1-1 new-tag) + (tag-mem (&+ (-> v1-2 data-base) (-> a1-1 data-offset))) + ) + (cond + ((zero? (-> new-tag inlined?)) + (length new-tag) + (set! (-> (the-as (pointer pointer) tag-mem) 0) arg1) + ) + (else + (let ((a2-1 (length new-tag))) + (mem-copy! tag-mem arg1 a2-1) + ) + ) + ) + ) + ) + ) + obj + ) + +;; definition for method 18 of type res-lump +(defmethod add-32bit-data! res-lump ((obj res-lump) (arg0 res-tag) (arg1 object)) + (local-vars (sv-16 object)) + (set! sv-16 arg1) + (let* ((v1-0 arg0) + (a1-4 (copy-and-set-field v1-0 inlined? 1)) + ) + (add-data! obj a1-4 (& sv-16)) + ) + ) + +;; definition for method 21 of type res-lump +;; Used lq/sq +(defmethod + get-curve-data! + res-lump + ((obj res-lump) (arg0 curve) (arg1 symbol) (arg2 symbol) (arg3 float)) + (local-vars (sv-16 res-tag) (sv-32 res-tag)) + (let ((s5-0 #f)) + (set! sv-16 (new 'static 'res-tag)) + (let + ((a0-2 + ((method-of-object obj get-property-data) + obj + arg1 + 'exact + arg3 + (the-as pointer #f) + (& sv-16) + *res-static-buf* + ) + ) + ) + (when a0-2 + (set! (-> arg0 cverts) a0-2) + (set! (-> arg0 num-cverts) (the-as int (-> sv-16 elt-count))) + (when (< 256 (-> arg0 num-cverts)) + (format + 0 + "ERROR: curve has ~D control points--only ~D are allowed. Increase MAX-CURVE-CONTROL-POINTS or shorten the curve.~%" + (-> arg0 num-cverts) + 256 + ) + (set! (-> arg0 num-cverts) 256) + ) + (set! sv-32 (new 'static 'res-tag)) + (let + ((a0-6 + ((method-of-object obj get-property-data) + obj + arg2 + 'exact + arg3 + (the-as pointer #f) + (& sv-32) + *res-static-buf* + ) + ) + ) + (when a0-6 + (set! (-> arg0 knots) (the-as (inline-array vector) a0-6)) + (set! (-> arg0 num-knots) (the-as int (-> sv-32 elt-count))) + (set! s5-0 #t) + ) + ) + ) + ) + s5-0 + ) + ) + +;; definition for method 8 of type res-lump +;; INFO: Return type mismatch int vs res-lump. +;; Used lq/sq +(defmethod + mem-usage + res-lump + ((obj res-lump) (block memory-usage-block) (flags int)) + (local-vars (sv-16 int)) + (let ((mem-use-id 48) + (mem-use-name "res") + ) + (cond + ((nonzero? (logand flags 256)) + (set! mem-use-id 44) + (set! mem-use-name "camera") + ) + ((nonzero? (logand flags 64)) + (set! mem-use-id 43) + (set! mem-use-name "entity") + ) + ((nonzero? (logand flags 128)) + (set! mem-use-id 49) + (set! mem-use-name "ambient") + ) + ((nonzero? (logand flags 512)) + (set! mem-use-id 73) + (set! mem-use-name "art-joint-geo") + ) + ) + (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 ((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))) + ) + ) + (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)) + ) + ) + ) + ) + ) + (when (not (part-group-pointer? (the-as pointer tag-data))) + (case (-> tag-data type) + ((symbol type) + ) + ((string) + (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) + (mem-usage (the-as collide-mesh 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))) + ) + ) + (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 + (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) + ) + +;; definition for symbol *res-static-buf*, type pointer +(define *res-static-buf* (malloc 'global 128)) diff --git a/test/decompiler/reference/engine/debug/menu_REF.gc b/test/decompiler/reference/engine/debug/menu_REF.gc index f8e07e571e..0f21cc7dcf 100644 --- a/test/decompiler/reference/engine/debug/menu_REF.gc +++ b/test/decompiler/reference/engine/debug/menu_REF.gc @@ -726,20 +726,16 @@ ;; INFO: Return type mismatch object vs function. (defun debug-menu-func-decode ((arg0 object)) (let ((v1-1 (rtype-of arg0))) - (the-as function (the-as symbol (cond - ((or (= v1-1 symbol) (= v1-1 type)) - (the-as - symbol - (-> (the-as symbol arg0) value) - ) - ) - ((= v1-1 function) - (the-as symbol arg0) - ) - (else - (the-as symbol nothing) - ) - ) + (the-as function (cond + ((or (= v1-1 symbol) (= v1-1 type)) + (the-as symbol (-> (the-as symbol arg0) value)) + ) + ((= v1-1 function) + (the-as symbol arg0) + ) + (else + (the-as symbol nothing) + ) ) ) ) diff --git a/test/decompiler/reference/engine/draw/process-drawable-h_REF.gc b/test/decompiler/reference/engine/draw/process-drawable-h_REF.gc index d0bccdab09..733511c24a 100644 --- a/test/decompiler/reference/engine/draw/process-drawable-h_REF.gc +++ b/test/decompiler/reference/engine/draw/process-drawable-h_REF.gc @@ -5,16 +5,15 @@ ;; INFO: Return type mismatch object vs cspace. (defun cspace-by-name-no-fail ((arg0 process-drawable) (arg1 string)) (let ((result (cspace-by-name arg0 arg1))) - (the-as cspace (the-as cspace (cond - (result - (empty) - (the-as cspace result) - ) - (else - (format 0 "no cspace (~A)~%" arg1) - (the-as cspace (-> arg0 node-list data)) - ) - ) + (the-as cspace (cond + (result + (empty) + (the-as cspace result) + ) + (else + (format 0 "no cspace (~A)~%" arg1) + (the-as cspace (-> arg0 node-list data)) + ) ) ) ) diff --git a/test/decompiler/reference/engine/entity/entity-table_REF.gc b/test/decompiler/reference/engine/entity/entity-table_REF.gc index f982fce174..d0b0e7cb3e 100644 --- a/test/decompiler/reference/engine/entity/entity-table_REF.gc +++ b/test/decompiler/reference/engine/entity/entity-table_REF.gc @@ -166,7 +166,7 @@ (-> arg0 method-table 13) (the-as function (-> v1-1 a1-0)) ) - (return (-> v1-1 a1-0)) + (return (the-as entity-info (-> v1-1 a1-0))) ) ) ) diff --git a/test/decompiler/reference/engine/game/task/task-control_REF.gc b/test/decompiler/reference/engine/game/task/task-control_REF.gc index 324fd81489..90e8bacfbf 100644 --- a/test/decompiler/reference/engine/game/task/task-control_REF.gc +++ b/test/decompiler/reference/engine/game/task/task-control_REF.gc @@ -5417,7 +5417,7 @@ (task-available? (-> gp-0 stage s5-0) gp-0) ) (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))) ) ) )