diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index 837b0b135d..62d5351fab 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -62,7 +62,8 @@ FormElement* SetVarOp::get_as_form(FormPool& pool, const Env& env) const { m_dst, pool.alloc_single_element_form( nullptr, GenericOperator::make_fixed(FixedOperatorKind::ADDRESS_OF), - pool.alloc_single_element_form(nullptr, -1, offset, false)), + pool.alloc_single_element_form( + nullptr, -1, offset, make_stack_slot_access(offset), false)), true, env.stack_slot_entries.at(offset).typespec); } } else { @@ -847,10 +848,12 @@ FormElement* StackSpillLoadOp::get_as_form(FormPool& pool, const Env& env) const if (env.has_type_analysis()) { read_type = env.get_types_before_op(m_my_idx).get_slot(m_offset).typespec(); } - return pool.alloc_element(m_dst, - pool.alloc_single_element_form( - nullptr, m_size, m_offset, m_is_signed, read_type), - true, type); + return pool.alloc_element( + m_dst, + pool.alloc_single_element_form( + nullptr, m_size, m_offset, env.get_stack_slot_access_for_op(m_my_idx, m_offset), + m_is_signed, read_type), + true, type); } FormElement* StackSpillStoreOp::get_as_form(FormPool& pool, const Env& env) const { @@ -870,6 +873,7 @@ FormElement* StackSpillStoreOp::get_as_form(FormPool& pool, const Env& env) cons } } - return pool.alloc_element(m_value, m_size, m_offset, cast_type); + return pool.alloc_element( + m_value, m_size, m_offset, env.get_stack_slot_access_for_op(m_my_idx, m_offset), cast_type); } } // namespace decompiler diff --git a/decompiler/IR2/Env.cpp b/decompiler/IR2/Env.cpp index 55f95610f7..ce60f6fe35 100644 --- a/decompiler/IR2/Env.cpp +++ b/decompiler/IR2/Env.cpp @@ -623,7 +623,7 @@ std::unordered_set Env::get_ssa_var(const RegAccessSet& vars RegId Env::get_program_var_id(const RegisterAccess& var) const { if (is_stack_slot_access(var)) { - return RegId(Register(Reg::GPR, Reg::SP), get_stack_slot_offset_from_access(var)); + return RegId(Register(Reg::GPR, Reg::SP), get_stack_slot_var_id_from_access(var)); } return m_var_names.lookup(var.reg(), var.idx(), var.mode()).reg_id; } @@ -637,17 +637,20 @@ const UseDefInfo& Env::get_use_def_info(const RegisterAccess& ra) const { return m_var_names.use_def_info.at(var_id); } +RegisterAccess Env::get_stack_slot_access_for_op(int op_id, int offset) const { + auto it = m_stack_slot_var_by_op.find(op_id); + if (it == m_stack_slot_var_by_op.end()) { + return make_stack_slot_access(offset); + } + return make_stack_slot_access(offset, it->second); +} + void Env::disable_def(const RegisterAccess& access, DecompWarnings& warnings) { if (is_stack_slot_access(access)) { - auto& info = m_stack_slot_use_def_info.at(get_program_var_id(access)); - for (auto& def : info.defs) { - if (!def.disabled) { - def.disabled = true; - return; - } - } - warnings.warning("disable stack def twice: {}", - get_spill_slot_var_name(get_stack_slot_offset_from_access(access))); + // Stack-slot use/def info is intentionally immutable during expression building. + // Unlike registers, the stack-slot analysis models value lifetimes through merged control flow + // with synthetic phi-like vars, and mutating counts here would desynchronize later accesses + // from that analysis. return; } if (has_local_vars()) { @@ -657,16 +660,7 @@ void Env::disable_def(const RegisterAccess& access, DecompWarnings& warnings) { void Env::disable_use(const RegisterAccess& access) { if (is_stack_slot_access(access)) { - auto& info = m_stack_slot_use_def_info.at(get_program_var_id(access)); - for (auto& use : info.uses) { - if (!use.disabled) { - use.disabled = true; - return; - } - } - throw std::runtime_error( - fmt::format("Invalid disable use on stack slot {}", - get_spill_slot_var_name(get_stack_slot_offset_from_access(access)))); + // See disable_def above. return; } if (has_local_vars()) { @@ -676,33 +670,134 @@ void Env::disable_use(const RegisterAccess& access) { void Env::rebuild_stack_slot_use_def_info() { m_stack_slot_use_def_info.clear(); + m_stack_slot_var_by_op.clear(); if (!func || !func->ir2.atomic_ops) { return; } const auto& ops = *func->ir2.atomic_ops; + const int block_count = (int)ops.block_id_to_first_atomic_op.size(); std::vector op_to_block(ops.ops.size(), -1); - for (int block_id = 0; block_id < (int)ops.block_id_to_first_atomic_op.size(); block_id++) { + for (int block_id = 0; block_id < block_count; block_id++) { for (int op_id = ops.block_id_to_first_atomic_op.at(block_id); op_id < ops.block_id_to_end_atomic_op.at(block_id); op_id++) { op_to_block.at(op_id) = block_id; } } + std::unordered_set offsets; for (int op_id = 0; op_id < (int)ops.ops.size(); op_id++) { - const auto* op = ops.ops.at(op_id).get(); - if (auto* store = dynamic_cast(op)) { - auto var_id = RegId(Register(Reg::GPR, Reg::SP), store->offset()); - auto& info = m_stack_slot_use_def_info[var_id]; - info.defs.push_back({op_id, op_to_block.at(op_id), AccessMode::WRITE, false}); - info.ssa_vars.insert(store->offset()); + if (auto* store = dynamic_cast(ops.ops.at(op_id).get())) { + offsets.insert(store->offset()); + } else if (auto* load = dynamic_cast(ops.ops.at(op_id).get())) { + offsets.insert(load->offset()); } - if (auto* load = dynamic_cast(op)) { - auto var_id = RegId(Register(Reg::GPR, Reg::SP), load->offset()); - auto& info = m_stack_slot_use_def_info[var_id]; - info.uses.push_back({op_id, op_to_block.at(op_id), AccessMode::READ, false}); - info.ssa_vars.insert(load->offset()); + } + + int next_var_id = 1; + for (int offset : offsets) { + std::vector reads_before_write(block_count, false); + std::vector writes(block_count, false); + + for (int block_id = 0; block_id < block_count; block_id++) { + bool seen_write = false; + for (int op_id = ops.block_id_to_first_atomic_op.at(block_id); + op_id < ops.block_id_to_end_atomic_op.at(block_id); op_id++) { + const auto* op = ops.ops.at(op_id).get(); + if (auto* load = dynamic_cast(op)) { + if (load->offset() == offset && !seen_write) { + reads_before_write.at(block_id) = true; + } + } else if (auto* store = dynamic_cast(op)) { + if (store->offset() == offset) { + writes.at(block_id) = true; + seen_write = true; + } + } + } + } + + std::vector live_in(block_count, false); + std::vector live_out(block_count, false); + bool changed = true; + while (changed) { + changed = false; + for (int block_id = block_count - 1; block_id >= 0; block_id--) { + bool new_live_out = false; + for (int succ : {func->basic_blocks.at(block_id).succ_branch, + func->basic_blocks.at(block_id).succ_ft}) { + if (succ != -1 && live_in.at(succ)) { + new_live_out = true; + } + } + + bool new_live_in = + reads_before_write.at(block_id) || (new_live_out && !writes.at(block_id)); + if (new_live_in != live_in.at(block_id) || new_live_out != live_out.at(block_id)) { + live_in.at(block_id) = new_live_in; + live_out.at(block_id) = new_live_out; + changed = true; + } + } + } + + std::vector phi_var(block_count, -1); + std::vector> phi_sources(block_count); + for (int block_id = 0; block_id < block_count; block_id++) { + if (live_in.at(block_id)) { + phi_var.at(block_id) = next_var_id++; + } + } + + for (int block_id = 0; block_id < block_count; block_id++) { + int current_var = live_in.at(block_id) ? phi_var.at(block_id) : -1; + for (int op_id = ops.block_id_to_first_atomic_op.at(block_id); + op_id < ops.block_id_to_end_atomic_op.at(block_id); op_id++) { + const auto* op = ops.ops.at(op_id).get(); + if (auto* load = dynamic_cast(op)) { + if (load->offset() != offset) { + continue; + } + ASSERT(current_var != -1); + m_stack_slot_var_by_op[op_id] = current_var; + auto& info = m_stack_slot_use_def_info[RegId(Register(Reg::GPR, Reg::SP), current_var)]; + info.uses.push_back({op_id, block_id, AccessMode::READ, false}); + info.ssa_vars.insert(current_var); + } else if (auto* store = dynamic_cast(op)) { + if (store->offset() != offset) { + continue; + } + current_var = next_var_id++; + m_stack_slot_var_by_op[op_id] = current_var; + auto& info = m_stack_slot_use_def_info[RegId(Register(Reg::GPR, Reg::SP), current_var)]; + info.defs.push_back({op_id, block_id, AccessMode::WRITE, false}); + info.ssa_vars.insert(current_var); + } + } + + if (!live_out.at(block_id)) { + continue; + } + + ASSERT(current_var != -1); + for (int succ : + {func->basic_blocks.at(block_id).succ_branch, func->basic_blocks.at(block_id).succ_ft}) { + if (succ != -1 && live_in.at(succ)) { + phi_sources.at(succ).push_back(current_var); + } + } + } + + for (int block_id = 0; block_id < block_count; block_id++) { + if (phi_var.at(block_id) == -1) { + continue; + } + int first_op = ops.block_id_to_first_atomic_op.at(block_id); + for (int src_var : phi_sources.at(block_id)) { + auto& info = m_stack_slot_use_def_info[RegId(Register(Reg::GPR, Reg::SP), src_var)]; + info.uses.push_back({first_op, block_id, AccessMode::READ, false}); + } } } } diff --git a/decompiler/IR2/Env.h b/decompiler/IR2/Env.h index 2dcb75ca73..d8a6230fab 100644 --- a/decompiler/IR2/Env.h +++ b/decompiler/IR2/Env.h @@ -44,17 +44,27 @@ struct StackSpillEntry { } }; +constexpr int STACK_SLOT_VAR_STRIDE = 1 << 16; + inline bool is_stack_slot_access(const RegisterAccess& access) { return access.reg() == Register(Reg::GPR, Reg::SP) && access.idx() < 0; } inline int get_stack_slot_offset_from_access(const RegisterAccess& access) { ASSERT(is_stack_slot_access(access)); - return -access.idx() - 1; + return (-access.idx() - 1) / STACK_SLOT_VAR_STRIDE; } -inline RegisterAccess make_stack_slot_access(int offset) { - return RegisterAccess(AccessMode::READ, Register(Reg::GPR, Reg::SP), -offset - 1, true); +inline int get_stack_slot_var_id_from_access(const RegisterAccess& access) { + ASSERT(is_stack_slot_access(access)); + return (-access.idx() - 1) % STACK_SLOT_VAR_STRIDE; +} + +inline RegisterAccess make_stack_slot_access(int offset, int var_id = 0) { + ASSERT(var_id >= 0); + ASSERT(var_id < STACK_SLOT_VAR_STRIDE); + return RegisterAccess(AccessMode::READ, Register(Reg::GPR, Reg::SP), + -1 - (offset * STACK_SLOT_VAR_STRIDE + var_id), true); } inline bool same_expression_var(const RegisterAccess& a, const RegisterAccess& b) { @@ -214,6 +224,7 @@ class Env { } const UseDefInfo& get_use_def_info(const RegisterAccess& ra) const; + RegisterAccess get_stack_slot_access_for_op(int op_id, int offset) const; void disable_use(const RegisterAccess& access); void disable_def(const RegisterAccess& access, DecompWarnings& warnings); @@ -259,6 +270,7 @@ class Env { bool m_has_local_vars = false; VariableNames m_var_names; std::unordered_map m_stack_slot_use_def_info; + std::unordered_map m_stack_slot_var_by_op; bool m_has_types = false; bool m_pp_mapped_by_behavior = false; diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index cb879ed3cc..d14d23a130 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -2776,8 +2776,13 @@ void VectorFloatLoadStoreElement::collect_vf_regs(RegSet& regs) const { StackSpillStoreElement::StackSpillStoreElement(SimpleAtom value, int size, int stack_offset, + RegisterAccess access, const std::optional& cast_type) - : m_value(value), m_size(size), m_stack_offset(stack_offset), m_cast_type(cast_type) {} + : m_value(value), + m_size(size), + m_stack_offset(stack_offset), + m_access(access), + m_cast_type(cast_type) {} goos::Object StackSpillStoreElement::to_form_internal(const Env& env) const { return pretty_print::build_list( @@ -2804,15 +2809,17 @@ void StackSpillStoreElement::get_modified_regs(RegSet&) const {} StackSpillValueElement::StackSpillValueElement(int size, int stack_offset, + RegisterAccess access, bool is_signed, std::optional read_type) : m_size(size), m_stack_offset(stack_offset), + m_access(access), m_is_signed(is_signed), m_read_type(std::move(read_type)) {} goos::Object StackSpillValueElement::to_form_internal(const Env& env) const { - auto var = make_stack_slot_access(m_stack_offset); + auto var = m_access; auto base = pretty_print::to_symbol(env.get_spill_slot_var_name(m_stack_offset)); if (m_read_type && env.get_variable_type(var, true) != *m_read_type) { return pretty_print::build_list("the-as", m_read_type->print(), base); @@ -2826,7 +2833,7 @@ void StackSpillValueElement::apply(const std::function& f) { void StackSpillValueElement::apply_form(const std::function&) {} void StackSpillValueElement::collect_vars(RegAccessSet& vars, bool) const { - vars.insert(make_stack_slot_access(m_stack_offset)); + vars.insert(m_access); } void StackSpillValueElement::get_modified_regs(RegSet&) const {} diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index af6cca590d..b7d004a1d5 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -1545,6 +1545,7 @@ class StackSpillStoreElement : public FormElement { StackSpillStoreElement(SimpleAtom value, int size, int stack_offset, + RegisterAccess access, const std::optional& cast_type); goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; @@ -1553,11 +1554,14 @@ class StackSpillStoreElement : public FormElement { void get_modified_regs(RegSet& regs) const override; void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; const std::optional& cast_type() const { return m_cast_type; } + const RegisterAccess& access() const { return m_access; } + int stack_offset() const { return m_stack_offset; } private: SimpleAtom m_value; int m_size = -1; int m_stack_offset = -1; + RegisterAccess m_access; std::optional m_cast_type; }; @@ -1566,9 +1570,11 @@ class StackSpillValueElement : public FormElement { public: StackSpillValueElement(int size, int stack_offset, + RegisterAccess access, bool is_signed, std::optional read_type = std::nullopt); int stack_offset() const { return m_stack_offset; } + const RegisterAccess& access() const { return m_access; } goos::Object to_form_internal(const Env& env) const override; void apply(const std::function& f) override; void apply_form(const std::function& f) override; @@ -1583,6 +1589,7 @@ class StackSpillValueElement : public FormElement { private: int m_size = -1; int m_stack_offset = -1; + RegisterAccess m_access; bool m_is_signed = false; std::optional m_read_type; }; diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index f9ceaf9e14..e36b7135ec 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -2738,8 +2738,7 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta if (m_src->is_single_element()) { auto spill_value = dynamic_cast(m_src->back()); if (spill_value) { - stack.push_non_seq_reg_to_reg(m_dst, make_stack_slot_access(spill_value->stack_offset()), - m_src, m_src_type, m_var_info); + stack.push_non_seq_reg_to_reg(m_dst, spill_value->access(), m_src, m_src_type, m_var_info); return; } @@ -7076,7 +7075,7 @@ void StackSpillStoreElement::push_to_stack(const Env& env, FormPool& pool, FormS InplaceOpInfo{FixedOperatorKind::LOGXOR, FixedOperatorKind::LOGXOR_IN_PLACE}, }; - auto dst_var = make_stack_slot_access(m_stack_offset); + auto dst_var = m_access; auto dst_form = pool.form(SimpleAtom::make_var(dst_var))->to_form(env); for (const auto& [kind, inplace_kind] : in_place_ops) { if (!src_as_generic->op().is_fixed(kind)) { @@ -7098,7 +7097,7 @@ void StackSpillStoreElement::push_to_stack(const Env& env, FormPool& pool, FormS } } - stack.push_value_to_reg(make_stack_slot_access(m_stack_offset), src, true, stack_type); + stack.push_value_to_reg(m_access, src, true, stack_type); } namespace { @@ -7358,7 +7357,7 @@ void StackSpillValueElement::update_from_stack(const Env& env, std::vector* result, bool) { mark_popped(); - auto var = make_stack_slot_access(m_stack_offset); + auto var = m_access; Form* form = pool.alloc_single_element_form(nullptr, SimpleAtom::make_var(var)); if (m_read_type && env.get_variable_type(var, true) != *m_read_type) { diff --git a/decompiler/IR2/FormStack.cpp b/decompiler/IR2/FormStack.cpp index cb5e1c1ab3..4c714cab43 100644 --- a/decompiler/IR2/FormStack.cpp +++ b/decompiler/IR2/FormStack.cpp @@ -18,6 +18,15 @@ bool nonempty_intersection(const RegSet& a, const RegSet& b) { } return false; } + +bool can_inline_non_seq_source(const RegisterAccess& src, const Env& env) { + if (!is_stack_slot_access(src)) { + return true; + } + + const auto& use_def = env.get_use_def_info(src); + return use_def.use_count() == 1 && use_def.def_count() == 1; +} } // namespace std::string FormStack::StackEntry::print(const Env& env) const { @@ -147,9 +156,11 @@ Form* FormStack::pop_reg(const RegisterAccess& var, ASSERT(entry.source); if (entry.non_seq_source.has_value()) { ASSERT(entry.sequence_point == false); - auto result = pop_reg(*entry.non_seq_source, barrier, env, allow_side_effects, i); - if (result) { - return result; + if (can_inline_non_seq_source(*entry.non_seq_source, env)) { + auto result = pop_reg(*entry.non_seq_source, barrier, env, allow_side_effects, i); + if (result) { + return result; + } } } @@ -215,13 +226,15 @@ Form* FormStack::pop_reg(Register reg, ASSERT(entry.source); if (entry.non_seq_source.has_value()) { ASSERT(entry.sequence_point == false); - auto result = pop_reg(entry.non_seq_source->reg(), barrier, env, allow_side_effects, i); - if (result) { - if (found_orig_out) { - *found_orig_out = true; - *orig_out = *entry.destination; + if (can_inline_non_seq_source(*entry.non_seq_source, env)) { + auto result = pop_reg(entry.non_seq_source->reg(), barrier, env, allow_side_effects, i); + if (result) { + if (found_orig_out) { + *found_orig_out = true; + *orig_out = *entry.destination; + } + return result; } - return result; } } diff --git a/decompiler/IR2/GenericElementMatcher.cpp b/decompiler/IR2/GenericElementMatcher.cpp index 685d4e1d0a..b40031da54 100644 --- a/decompiler/IR2/GenericElementMatcher.cpp +++ b/decompiler/IR2/GenericElementMatcher.cpp @@ -309,7 +309,7 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out, const Env* cons dynamic_cast(input->try_as_single_active_element()); if (as_stack_spill) { got = true; - result = make_stack_slot_access(as_stack_spill->stack_offset()); + result = as_stack_spill->access(); } if (got) { diff --git a/scripts/gsrc/update-from-decomp.py b/scripts/gsrc/update-from-decomp.py index c728ce089e..086b7a6e1f 100644 --- a/scripts/gsrc/update-from-decomp.py +++ b/scripts/gsrc/update-from-decomp.py @@ -153,6 +153,8 @@ with open(decomp_file_path) as f: decomp_form_paren_stack = [] i = i + 1 break + if i + 1 == len(lines): + break else: decomp_lines.append(line) i = i + 1 diff --git a/test/decompiler/reference/jak1/decompiler-macros.gc b/test/decompiler/reference/jak1/decompiler-macros.gc index 2e55a9bd5c..ad4eb792a2 100644 --- a/test/decompiler/reference/jak1/decompiler-macros.gc +++ b/test/decompiler/reference/jak1/decompiler-macros.gc @@ -1729,6 +1729,10 @@ ) ) +(defmacro square (x) + `(* ,x ,x) + ) + (import "goal_src/jak1/engine/data/tpages.gc") (import "goal_src/jak1/engine/data/textures.gc") \ No newline at end of file diff --git a/test/decompiler/reference/jak1/engine/draw/process-drawable_REF.gc b/test/decompiler/reference/jak1/engine/common-obs/process-drawable_REF.gc similarity index 87% rename from test/decompiler/reference/jak1/engine/draw/process-drawable_REF.gc rename to test/decompiler/reference/jak1/engine/common-obs/process-drawable_REF.gc index e950895df3..b734475b29 100644 --- a/test/decompiler/reference/jak1/engine/draw/process-drawable_REF.gc +++ b/test/decompiler/reference/jak1/engine/common-obs/process-drawable_REF.gc @@ -114,7 +114,6 @@ ;; definition for method 9 of type lod-set ;; INFO: Used lq/sq (defmethod setup-lods! ((this lod-set) (arg0 skeleton-group) (arg1 art-group) (arg2 entity)) - (local-vars (sv-16 res-tag)) (let ((s4-0 arg0) (s5-0 arg1) ) @@ -138,13 +137,13 @@ (set! (-> this lod s3-0 dist) (res-lump-float arg2 'vis-dist :default 4095996000.0)) ) ) - (let ((v1-13 (-> s5-0 data (-> s4-0 jgeo)))) - (set! sv-16 (new 'static 'res-tag)) - (let ((v1-14 (res-lump-data (-> v1-13 extra) 'lod-dist pointer :tag-ptr (& sv-16)))) - (when v1-14 - (dotimes (a0-6 (the-as int (-> sv-16 elt-count))) - (set! (-> this lod a0-6 dist) (-> (the-as (pointer float) (&+ v1-14 (* a0-6 4))))) - ) + (let* ((v1-13 (-> s5-0 data (-> s4-0 jgeo))) + (sv-16 (new 'static 'res-tag)) + (v1-14 (res-lump-data (-> v1-13 extra) 'lod-dist pointer :tag-ptr (& sv-16))) + ) + (when v1-14 + (dotimes (a0-6 (the-as int (-> sv-16 elt-count))) + (set! (-> this lod a0-6 dist) (-> (the-as (pointer float) (&+ v1-14 (* a0-6 4))))) ) ) ) @@ -428,7 +427,7 @@ ;; WARN: Stack slot offset 20 signed mismatch ;; INFO: Return type mismatch draw-control vs none. (defmethod initialize-skeleton ((this process-drawable) (arg0 skeleton-group) (arg1 pair)) - (local-vars (s3-0 draw-control) (sv-16 art-element) (sv-20 int)) + (local-vars (s3-0 draw-control)) (let ((s1-0 (cond ((= (-> arg0 texture-level) 2) (-> *level* level-default) @@ -448,122 +447,124 @@ (set! s3-0 (the-as draw-control #f)) (goto cfg-59) ) - (set! sv-16 (-> s4-0 data (-> arg0 jgeo))) - (set! sv-20 (-> s4-0 length)) - (when (or (>= (-> arg0 jgeo) sv-20) (!= (-> sv-16 type) art-joint-geo)) - (go process-drawable-art-error "joint-geo") - (set! s3-0 (the-as draw-control #f)) - (goto cfg-59) - ) - (let ((v0-3 (new 'process 'draw-control this (the-as art-joint-geo sv-16)))) - (set! (-> this draw) v0-3) - (set! s3-0 v0-3) - ) - (let ((v1-26 s3-0)) - (set! (-> v1-26 status) (draw-status no-skeleton-update)) - (set! (-> v1-26 art-group) s4-0) - (set! (-> v1-26 jgeo) (the-as art-joint-geo sv-16)) - (set! (-> v1-26 force-lod) -1) - (set! (-> v1-26 cur-lod) -1) - (set! (-> v1-26 shadow) #f) - (set! (-> v1-26 shadow-ctrl) #f) - (set! (-> v1-26 data-format) (the-as uint 1)) - (set! (-> v1-26 color-mult quad) (-> (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0) quad)) - (set! (-> v1-26 color-emissive quad) (-> (new 'static 'vector) quad)) - (set! (-> v1-26 level-index) (the-as uint (-> (if (-> this entity) - (-> this entity extra level) - (-> *level* level-default) - ) - index - ) - ) + (let ((sv-16 (-> s4-0 data (-> arg0 jgeo))) + (sv-20 (-> s4-0 length)) + ) + (when (or (>= (-> arg0 jgeo) sv-20) (!= (-> sv-16 type) art-joint-geo)) + (go process-drawable-art-error "joint-geo") + (set! s3-0 (the-as draw-control #f)) + (goto cfg-59) + ) + (let ((v0-3 (new 'process 'draw-control this (the-as art-joint-geo sv-16)))) + (set! (-> this draw) v0-3) + (set! s3-0 v0-3) + ) + (let ((v1-26 s3-0)) + (set! (-> v1-26 status) (draw-status no-skeleton-update)) + (set! (-> v1-26 art-group) s4-0) + (set! (-> v1-26 jgeo) (the-as art-joint-geo sv-16)) + (set! (-> v1-26 force-lod) -1) + (set! (-> v1-26 cur-lod) -1) + (set! (-> v1-26 shadow) #f) + (set! (-> v1-26 shadow-ctrl) #f) + (set! (-> v1-26 data-format) (the-as uint 1)) + (set! (-> v1-26 color-mult quad) (-> (new 'static 'vector :x 1.0 :y 1.0 :z 1.0 :w 1.0) quad)) + (set! (-> v1-26 color-emissive quad) (-> (new 'static 'vector) quad)) + (set! (-> v1-26 level-index) (the-as uint (-> (if (-> this entity) + (-> this entity extra level) + (-> *level* level-default) + ) + index + ) + ) + ) + (set! (-> v1-26 longest-edge) (-> arg0 longest-edge)) + (set! (-> v1-26 ripple) #f) + ) + (set! (-> s3-0 bounds quad) (-> arg0 bounds quad)) + (let ((v1-28 (-> arg0 shadow))) + (when (and (> v1-28 0) (< v1-28 sv-20)) + (let ((s0-0 (-> s4-0 data v1-28)) + (v1-32 (res-lump-value (-> this entity) 'options uint128)) + ) + (if (and (not (logtest? #x20000 v1-32)) (= (-> s0-0 type) shadow-geo)) + (set! (-> s3-0 shadow) (the-as shadow-geo s0-0)) + ) ) - (set! (-> v1-26 longest-edge) (-> arg0 longest-edge)) - (set! (-> v1-26 ripple) #f) - ) - (set! (-> s3-0 bounds quad) (-> arg0 bounds quad)) - (let ((v1-28 (-> arg0 shadow))) - (when (and (> v1-28 0) (< v1-28 sv-20)) - (let ((s0-0 (-> s4-0 data v1-28)) - (v1-32 (res-lump-value (-> this entity) 'options uint128)) - ) - (if (and (not (logtest? #x20000 v1-32)) (= (-> s0-0 type) shadow-geo)) - (set! (-> s3-0 shadow) (the-as shadow-geo s0-0)) - ) ) ) - ) - (if (not (setup-lods! (-> s3-0 lod-set) arg0 s4-0 (-> this entity))) - (go process-drawable-art-error "mesh") + (if (not (setup-lods! (-> s3-0 lod-set) arg0 s4-0 (-> this entity))) + (go process-drawable-art-error "mesh") + ) + (let ((v1-43 (res-lump-value (-> sv-16 extra) 'texture-bucket int :default (the-as uint128 1)))) + (let ((a0-39 (if (= (-> arg0 texture-level) 2) + 2 + (-> s1-0 index) + ) + ) + ) + (if (= (the-as uint v1-43) 4) + (set! v1-43 2) + ) + (if (= a0-39 2) + (set! v1-43 (-> arg0 sort)) + ) + ) + (set! (-> s3-0 sink-group) (-> s1-0 foreground-sink-group v1-43)) ) - (let ((v1-43 (res-lump-value (-> sv-16 extra) 'texture-bucket int :default (the-as uint128 1)))) - (let ((a0-39 (if (= (-> arg0 texture-level) 2) - 2 - (-> s1-0 index) - ) - ) - ) - (if (= (the-as uint v1-43) 4) - (set! v1-43 2) - ) - (if (= a0-39 2) - (set! v1-43 (-> arg0 sort)) - ) - ) - (set! (-> s3-0 sink-group) (-> s1-0 foreground-sink-group v1-43)) - ) - (set! (-> s3-0 dma-add-func) (the-as (function process-drawable draw-control symbol object none) nothing)) - (set! (-> this node-list) (make-nodes-from-jg (the-as art-joint-geo sv-16) arg1 'process)) - (set! (-> s3-0 dma-add-func) dma-add-process-drawable) - (set! (-> s3-0 shadow-mask) (res-lump-value (-> this entity) 'shadow-mask uint)) - (set! (-> s3-0 light-index) (res-lump-value (-> this entity) 'light-index uint)) - (lod-set! s3-0 0) - (let ((a2-10 (res-lump-value (-> sv-16 extra) 'joint-channel int :default (the-as uint128 6)))) - (cond - ((> a2-10 0) - (logior! (-> s3-0 status) (draw-status has-joint-channels)) - (let ((v0-13 (new 'process 'joint-control a2-10))) - (set! (-> this skel) v0-13) - (let ((s2-1 v0-13)) - (cond - ((>= (-> arg0 janim) 0) - (when (or (>= (-> arg0 janim) sv-20) (!= (-> s4-0 data (-> arg0 janim) type) art-joint-anim)) - (go process-drawable-art-error "initial joint-anim") - (set! s3-0 (the-as draw-control #f)) - (goto cfg-59) - ) - (ja-channel-set! 1) - (let ((s1-1 (-> this skel root-channel 0))) - (joint-control-channel-group-eval! - s1-1 - (the-as art-joint-anim (-> s4-0 data (-> arg0 janim))) - num-func-identity + (set! (-> s3-0 dma-add-func) (the-as (function process-drawable draw-control symbol object none) nothing)) + (set! (-> this node-list) (make-nodes-from-jg (the-as art-joint-geo sv-16) arg1 'process)) + (set! (-> s3-0 dma-add-func) dma-add-process-drawable) + (set! (-> s3-0 shadow-mask) (res-lump-value (-> this entity) 'shadow-mask uint)) + (set! (-> s3-0 light-index) (res-lump-value (-> this entity) 'light-index uint)) + (lod-set! s3-0 0) + (let ((a2-10 (res-lump-value (-> sv-16 extra) 'joint-channel int :default (the-as uint128 6)))) + (cond + ((> a2-10 0) + (logior! (-> s3-0 status) (draw-status has-joint-channels)) + (let ((v0-13 (new 'process 'joint-control a2-10))) + (set! (-> this skel) v0-13) + (let ((s2-1 v0-13)) + (cond + ((>= (-> arg0 janim) 0) + (when (or (>= (-> arg0 janim) sv-20) (!= (-> s4-0 data (-> arg0 janim) type) art-joint-anim)) + (go process-drawable-art-error "initial joint-anim") + (set! s3-0 (the-as draw-control #f)) + (goto cfg-59) + ) + (ja-channel-set! 1) + (let ((s1-1 (-> this skel root-channel 0))) + (joint-control-channel-group-eval! + s1-1 + (the-as art-joint-anim (-> s4-0 data (-> arg0 janim))) + num-func-identity + ) + (set! (-> s1-1 frame-num) 0.0) ) - (set! (-> s1-1 frame-num) 0.0) ) - ) - (else - (ja-channel-set! 0) + (else + (ja-channel-set! 0) + ) ) + (set! (-> s2-1 effect) (new 'process 'effect-control this)) ) - (set! (-> s2-1 effect) (new 'process 'effect-control this)) ) ) - ) - (else - (set! (-> s3-0 skeleton bones 0 transform vector 3 quad) (-> (the-as vector (get-property-struct - (-> sv-16 extra) - 'trans-offset - 'interp - -1000000000.0 - *null-vector* - (the-as (pointer res-tag) #f) - *res-static-buf* - ) - ) - quad - ) - ) + (else + (set! (-> s3-0 skeleton bones 0 transform vector 3 quad) (-> (the-as vector (get-property-struct + (-> sv-16 extra) + 'trans-offset + 'interp + -1000000000.0 + *null-vector* + (the-as (pointer res-tag) #f) + *res-static-buf* + ) + ) + quad + ) + ) + ) ) ) ) diff --git a/test/decompiler/reference/jak1/engine/gfx/eye_REF.gc b/test/decompiler/reference/jak1/engine/gfx/foreground/eye_REF.gc similarity index 99% rename from test/decompiler/reference/jak1/engine/gfx/eye_REF.gc rename to test/decompiler/reference/jak1/engine/gfx/foreground/eye_REF.gc index 0c81c8a48d..d9561e9dfc 100644 --- a/test/decompiler/reference/jak1/engine/gfx/eye_REF.gc +++ b/test/decompiler/reference/jak1/engine/gfx/foreground/eye_REF.gc @@ -63,7 +63,6 @@ ;; WARN: Stack slot offset 16 signed mismatch ;; INFO: Return type mismatch vector4w vs pointer. (defun render-eyes ((arg0 dma-buffer) (arg1 eye-control) (arg2 int)) - (local-vars (sv-16 float)) (let ((s4-0 32) (s3-0 (+ (* arg2 32) 32)) (s2-0 (* arg2 32)) @@ -71,8 +70,8 @@ (let ((f28-0 (* 16.0 (+ (the float (+ s4-0 16)) (* 32.0 (-> arg1 left data 0 x))))) (f26-0 (* 16.0 (+ (the float (+ s3-0 16)) (* 32.0 (-> arg1 left data 0 y))))) (f30-0 (* 16.0 (+ (the float (+ s4-0 48)) (* 32.0 (-> arg1 right data 0 x))))) + (sv-16 (* 16.0 (+ (the float (+ s3-0 16)) (* 32.0 (-> arg1 right data 0 y))))) ) - (set! sv-16 (* 16.0 (+ (the float (+ s3-0 16)) (* 32.0 (-> arg1 right data 0 y))))) (let ((s1-0 (-> arg1 shaders 0))) (let ((v1-6 (the-as object (-> arg0 base)))) (set! (-> (the-as dma-gif-packet v1-6) dma-vif quad) (-> *eye-work* adgif-tmpl dma-vif quad))