From 91fa0122d8203dcaa534decdfe117c8c2ffed24e Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Sat, 25 Jun 2022 21:26:15 -0400 Subject: [PATCH] [decompiler] Jak 2 modifications, new all-types code (#1553) * temp * look at old game types * clean up --- decompiler/CMakeLists.txt | 1 + decompiler/Function/CfgVtx.cpp | 29 +- decompiler/Function/CfgVtx.h | 3 +- decompiler/Function/Function.cpp | 4 +- decompiler/Function/Function.h | 2 +- decompiler/IR2/AtomicOp.cpp | 40 + decompiler/IR2/AtomicOp.h | 8 + decompiler/IR2/AtomicOpTypeAnalysis.cpp | 8 + decompiler/IR2/Env.h | 1 + decompiler/IR2/Form.h | 1 + decompiler/IR2/FormExpressionAnalysis.cpp | 42 +- decompiler/ObjectFile/LinkedObjectFile.cpp | 4 +- decompiler/ObjectFile/LinkedObjectFile.h | 2 +- decompiler/ObjectFile/ObjectFileDB.cpp | 2 +- decompiler/ObjectFile/ObjectFileDB.h | 4 +- decompiler/ObjectFile/ObjectFileDB_IR2.cpp | 92 +- .../analysis/analyze_inspect_method.cpp | 988 ++++++++++++++++++ decompiler/analysis/analyze_inspect_method.h | 23 + decompiler/analysis/atomic_op_builder.cpp | 18 +- decompiler/analysis/cfg_builder.cpp | 47 +- decompiler/config.cpp | 5 +- decompiler/config.h | 3 + decompiler/config/all-types2.gc | 5 +- decompiler/config/jak1_ntsc_black_label.jsonc | 3 + decompiler/config/jak2/hacks.jsonc | 7 +- decompiler/config/jak2/inputs.jsonc | 306 +++--- decompiler/config/jak2_ntsc_v1.jsonc | 7 + decompiler/main.cpp | 7 + decompiler/util/DecompilerTypeSystem.cpp | 4 +- scripts/shell/decomp2.sh | 6 + test/decompiler/FormRegressionTest.cpp | 20 +- test/decompiler/FormRegressionTest.h | 63 +- test/decompiler/test_DisasmVifDecompile.cpp | 26 +- .../decompiler/test_FormBeforeExpressions.cpp | 36 +- test/decompiler/test_FormExpressionBuild.cpp | 166 +-- test/decompiler/test_FormExpressionBuild2.cpp | 119 +-- test/decompiler/test_FormExpressionBuild3.cpp | 6 +- .../test_FormExpressionBuildLong.cpp | 114 +- test/decompiler/test_gkernel_decomp.cpp | 118 ++- test/decompiler/test_math_decomp.cpp | 8 +- 40 files changed, 1762 insertions(+), 586 deletions(-) create mode 100644 decompiler/analysis/analyze_inspect_method.cpp create mode 100644 decompiler/analysis/analyze_inspect_method.h create mode 100755 scripts/shell/decomp2.sh diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index 9badadbdf2..d28c1b9a51 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -1,6 +1,7 @@ add_library( decomp + analysis/analyze_inspect_method.cpp analysis/atomic_op_builder.cpp analysis/cfg_builder.cpp analysis/expression_build.cpp diff --git a/decompiler/Function/CfgVtx.cpp b/decompiler/Function/CfgVtx.cpp index ac2426f1db..220ffae125 100644 --- a/decompiler/Function/CfgVtx.cpp +++ b/decompiler/Function/CfgVtx.cpp @@ -3,6 +3,7 @@ #include "Function.h" #include "common/goos/PrettyPrinter.h" +#include "common/symbols.h" #include "common/util/Assert.h" #include "decompiler/Disasm/InstructionMatching.h" @@ -2559,13 +2560,14 @@ void ControlFlowGraph::flag_early_exit(const std::vector& blocks) { } } -CfgVtx::DelaySlotKind get_delay_slot(const Instruction& i) { +CfgVtx::DelaySlotKind get_delay_slot(const Instruction& i, GameVersion version) { if (is_nop(i)) { return CfgVtx::DelaySlotKind::NOP; } else if (is_gpr_3(i, InstructionKind::OR, {}, Register(Reg::GPR, Reg::S7), Register(Reg::GPR, Reg::R0))) { return CfgVtx::DelaySlotKind::SET_REG_FALSE; - } else if (is_gpr_2_imm_int(i, InstructionKind::DADDIU, {}, Register(Reg::GPR, Reg::S7), 8)) { + } else if (is_gpr_2_imm_int(i, InstructionKind::DADDIU, {}, Register(Reg::GPR, Reg::S7), + true_symbol_offset(version))) { return CfgVtx::DelaySlotKind::SET_REG_TRUE; } else { return CfgVtx::DelaySlotKind::OTHER; @@ -2576,7 +2578,7 @@ namespace { /*! * Is this instruction possible in the delay slot, without using inline assembly? */ -bool branch_delay_asm(const Instruction& i) { +bool branch_delay_asm(const Instruction& i, GameVersion version) { if (is_nop(i)) { // nop can be used as a delay return false; @@ -2584,7 +2586,8 @@ bool branch_delay_asm(const Instruction& i) { Register(Reg::GPR, Reg::R0))) { // set false is used in ifs, etc return false; - } else if (is_gpr_2_imm_int(i, InstructionKind::DADDIU, {}, Register(Reg::GPR, Reg::S7), 8)) { + } else if (is_gpr_2_imm_int(i, InstructionKind::DADDIU, {}, Register(Reg::GPR, Reg::S7), + true_symbol_offset(version))) { // set true is used in sc return false; } else if (is_gpr_3(i, InstructionKind::OR, {}, {}, Register(Reg::GPR, Reg::R0))) { @@ -2609,12 +2612,12 @@ bool branch_delay_asm(const Instruction& i) { /*! * Build and resolve a Control Flow Graph as much as possible. */ -std::shared_ptr build_cfg( - const LinkedObjectFile& file, - int seg, - Function& func, - const CondWithElseLengthHack& cond_with_else_hack, - const std::unordered_set& blocks_ending_in_asm_br) { +std::shared_ptr build_cfg(const LinkedObjectFile& file, + int seg, + Function& func, + const CondWithElseLengthHack& cond_with_else_hack, + const std::unordered_set& blocks_ending_in_asm_br, + GameVersion version) { // fmt::print("START {}\n", func.guessed_name.to_string()); auto cfg = std::make_shared(); @@ -2708,7 +2711,7 @@ std::shared_ptr build_cfg( if (is_branch(branch_candidate, false)) { blocks.at(i)->end_branch.has_branch = true; blocks.at(i)->end_branch.branch_likely = false; - blocks.at(i)->end_branch.kind = get_delay_slot(delay_slot_candidate); + blocks.at(i)->end_branch.kind = get_delay_slot(delay_slot_candidate, version); bool branch_always = is_always_branch(branch_candidate); // need to find block target @@ -2779,7 +2782,7 @@ std::shared_ptr build_cfg( if (is_branch(likely_branch_candidate, true)) { // likely branch! auto following = func.instructions.at(likely_branch_idx + 1); - if (branch_delay_asm(following)) { + if (branch_delay_asm(following, version)) { b->end_branch.asm_branch = true; if (debug_asm_branch) { fmt::print("LIKELY ASM BRANCH: {} and {}\n", @@ -2795,7 +2798,7 @@ std::shared_ptr build_cfg( auto& branch_candidate = func.instructions.at(idx); auto& delay_slot_candidate = func.instructions.at(idx + 1); if (is_branch(branch_candidate, false)) { - if (branch_delay_asm(delay_slot_candidate)) { + if (branch_delay_asm(delay_slot_candidate, version)) { b->end_branch.asm_branch = true; if (debug_asm_branch) { fmt::print("NORMAL ASM BRANCH: {} and {}\n", branch_candidate.to_string(file.labels), diff --git a/decompiler/Function/CfgVtx.h b/decompiler/Function/CfgVtx.h index 9bd9205346..6649255f6f 100644 --- a/decompiler/Function/CfgVtx.h +++ b/decompiler/Function/CfgVtx.h @@ -393,5 +393,6 @@ std::shared_ptr build_cfg(const LinkedObjectFile& file, int seg, Function& func, const CondWithElseLengthHack& cond_with_else_hack, - const std::unordered_set& blocks_ending_in_asm_br); + const std::unordered_set& blocks_ending_in_asm_br, + GameVersion version); } // namespace decompiler diff --git a/decompiler/Function/Function.cpp b/decompiler/Function/Function.cpp index e7d700f9ad..f2f4f4f5db 100644 --- a/decompiler/Function/Function.cpp +++ b/decompiler/Function/Function.cpp @@ -34,8 +34,10 @@ Register get_expected_fpr_backup(int n, int total) { } // namespace -Function::Function(int _start_word, int _end_word) : start_word(_start_word), end_word(_end_word) { +Function::Function(int _start_word, int _end_word, GameVersion version) + : start_word(_start_word), end_word(_end_word) { ir2.form_pool.reset(new FormPool()); + ir2.env.version = version; } Function::~Function() {} diff --git a/decompiler/Function/Function.h b/decompiler/Function/Function.h index 80f4348875..d32f5a95d1 100644 --- a/decompiler/Function/Function.h +++ b/decompiler/Function/Function.h @@ -99,7 +99,7 @@ struct FunctionName { class Function { public: - Function(int _start_word, int _end_word); + Function(int _start_word, int _end_word, GameVersion version); ~Function(); void analyze_prologue(const LinkedObjectFile& file); void find_global_function_defs(LinkedObjectFile& file, DecompilerTypeSystem& dts); diff --git a/decompiler/IR2/AtomicOp.cpp b/decompiler/IR2/AtomicOp.cpp index a8bd27ebe3..72f19106df 100644 --- a/decompiler/IR2/AtomicOp.cpp +++ b/decompiler/IR2/AtomicOp.cpp @@ -1842,4 +1842,44 @@ RegisterAccess StackSpillLoadOp::get_set_destination() const { throw std::runtime_error("StackSpillLoadOp cannot be treated as a set! operation"); } +bool is_op_2(AtomicOp* op, + MatchParam kind, + MatchParam dst, + MatchParam src0, + Register* dst_out, + Register* src0_out) { + // should be a set reg to int math 2 ir + auto set = dynamic_cast(op); + if (!set) { + return false; + } + + // destination should be a register + auto dest = set->dst(); + if (dst != dest.reg()) { + return false; + } + + auto math = set->src(); + if (kind != math.kind()) { + return false; + } + + auto arg = math.get_arg(0); + + if (!arg.is_var() || src0 != arg.var().reg()) { + return false; + } + + // it's a match! + if (dst_out) { + *dst_out = dest.reg(); + } + + if (src0_out) { + *src0_out = arg.var().reg(); + } + + return true; +} } // namespace decompiler diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index d2d9353a5b..7b84193768 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -12,6 +12,7 @@ #include "decompiler/Disasm/Instruction.h" #include "decompiler/Disasm/Register.h" #include "decompiler/IR2/IR2_common.h" +#include "decompiler/util/MatchParam.h" namespace decompiler { class FormElement; @@ -807,4 +808,11 @@ class StackSpillLoadOp : public AtomicOp { }; bool get_as_reg_offset(const SimpleExpression& expr, IR2_RegOffset* out); + +bool is_op_2(AtomicOp* op, + MatchParam kind, + MatchParam dst, + MatchParam src0, + Register* dst_out = nullptr, + Register* src0_out = nullptr); } // namespace decompiler diff --git a/decompiler/IR2/AtomicOpTypeAnalysis.cpp b/decompiler/IR2/AtomicOpTypeAnalysis.cpp index 4e39e10c01..3cf35adaa7 100644 --- a/decompiler/IR2/AtomicOpTypeAnalysis.cpp +++ b/decompiler/IR2/AtomicOpTypeAnalysis.cpp @@ -188,6 +188,11 @@ TP_Type SimpleExpression::get_type(const TypeState& input, // GOAL is smart enough to use binary 0b0 as floating point 0. return TP_Type::make_from_ts("float"); } + // new for jak 2: + if (env.version == GameVersion::Jak2 && in_type.is_integer_constant() && + in_type.get_integer_constant() <= UINT32_MAX) { + return TP_Type::make_from_ts("float"); + } return in_type; } case Kind::FPR_TO_GPR: @@ -398,6 +403,9 @@ TP_Type SimpleExpression::get_type_int2(const TypeState& input, } if (m_kind == Kind::RIGHT_SHIFT_ARITH) { + if (env.version == GameVersion::Jak2 && arg0_type.typespec().base_type() == "float") { + return TP_Type::make_from_ts(TypeSpec("float")); + } return TP_Type::make_from_ts(TypeSpec("int")); } } break; diff --git a/decompiler/IR2/Env.h b/decompiler/IR2/Env.h index cc23852053..c577d44d06 100644 --- a/decompiler/IR2/Env.h +++ b/decompiler/IR2/Env.h @@ -58,6 +58,7 @@ struct FunctionVariableDefinitions { */ class Env { public: + GameVersion version = GameVersion::Jak1; bool types_succeeded = false; bool has_local_vars() const { return m_has_local_vars; } bool has_type_analysis() const { return m_has_types; } diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index af812262cd..e8d52a0f89 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -801,6 +801,7 @@ class UntilElement : public FormElement { bool allow_in_if() const override { return false; } Form* condition = nullptr; Form* body = nullptr; + std::optional false_destination; // used in jak 2, sometimes. }; /*! diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 80b49185cb..153222d6aa 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -708,10 +708,28 @@ void SimpleExpressionElement::update_from_stack_gpr_to_fpr(const Env& env, result->push_back(x); } } else { - // converting something else to an FPR, put an expression around it. - result->push_back(pool.alloc_element( - GenericOperator::make_fixed(FixedOperatorKind::GPR_TO_FPR), - pool.alloc_sequence_form(nullptr, src_fes))); + if (env.version != GameVersion::Jak1) { + auto frm = pool.alloc_sequence_form(nullptr, src_fes); + if (src_fes.size() == 1) { + auto int_constant = get_goal_integer_constant(frm, env); + + if (int_constant && (*int_constant <= UINT32_MAX)) { + float flt; + + memcpy(&flt, &int_constant.value(), sizeof(float)); + + result->push_back(pool.alloc_element(flt)); + return; + } + } + // converting something else to an FPR, put an expression around it. + result->push_back(pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::GPR_TO_FPR), frm)); + } else { + result->push_back(pool.alloc_element( + GenericOperator::make_fixed(FixedOperatorKind::GPR_TO_FPR), + pool.alloc_sequence_form(nullptr, src_fes))); + } } } @@ -3538,6 +3556,22 @@ void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac } stack.push_form_element(this, true); + if (false_destination) { + env.func->warnings.general_warning("new jak 2 until loop case, check carefully"); + stack.push_value_to_reg(*false_destination, + pool.form(SimpleAtom::make_sym_val("#f")), true, + TypeSpec("symbol")); + RegAccessSet accessed_regs; + body->collect_vars(accessed_regs, true); + condition->collect_vars(accessed_regs, true); + auto check_name = env.get_variable_name(*false_destination); + for (auto& reg : accessed_regs) { + if (env.get_variable_name(reg) == check_name) { + ASSERT_MSG(false, fmt::format("Jak 2 loop uses delay slot variable improperly: {} {}\n", + env.func->name(), check_name)); + } + } + } } void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { diff --git a/decompiler/ObjectFile/LinkedObjectFile.cpp b/decompiler/ObjectFile/LinkedObjectFile.cpp index d76a1da966..12c6771534 100644 --- a/decompiler/ObjectFile/LinkedObjectFile.cpp +++ b/decompiler/ObjectFile/LinkedObjectFile.cpp @@ -400,7 +400,7 @@ void LinkedObjectFile::find_code() { /*! * Find all the functions in each segment. */ -void LinkedObjectFile::find_functions() { +void LinkedObjectFile::find_functions(GameVersion version) { if (segments == 1) { // it's a v2 file, shouldn't have any functions ASSERT(offset_of_data_zone_by_seg.at(0) == 0); @@ -427,7 +427,7 @@ void LinkedObjectFile::find_functions() { // mark this as a function, and try again from the current function start ASSERT(found_function_tag_loc); stats.function_count++; - functions_by_seg.at(seg).emplace_back(function_tag_loc, function_end); + functions_by_seg.at(seg).emplace_back(function_tag_loc, function_end, version); function_end = function_tag_loc; } diff --git a/decompiler/ObjectFile/LinkedObjectFile.h b/decompiler/ObjectFile/LinkedObjectFile.h index d94c2839a6..d33b30f4e3 100644 --- a/decompiler/ObjectFile/LinkedObjectFile.h +++ b/decompiler/ObjectFile/LinkedObjectFile.h @@ -52,7 +52,7 @@ class LinkedObjectFile { uint32_t set_ordered_label_names(); void find_code(); std::string print_words(); - void find_functions(); + void find_functions(GameVersion version); void disassemble_functions(); void process_fp_relative_links(); std::string print_scripts(); diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index 0172e313a2..03dfd53fb6 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -589,7 +589,7 @@ void ObjectFileDB::find_code(const Config& config) { for_each_obj([&](ObjectFileData& obj) { // printf("fc %s\n", obj.record.to_unique_name().c_str()); obj.linked_data.find_code(); - obj.linked_data.find_functions(); + obj.linked_data.find_functions(config.game_version); obj.linked_data.disassemble_functions(); if (config.game_version == GameVersion::Jak1 || obj.to_unique_name() != "effect-control-v0") { diff --git a/decompiler/ObjectFile/ObjectFileDB.h b/decompiler/ObjectFile/ObjectFileDB.h index 2e640f18c8..70e5007ca3 100644 --- a/decompiler/ObjectFile/ObjectFileDB.h +++ b/decompiler/ObjectFile/ObjectFileDB.h @@ -158,7 +158,6 @@ class ObjectFileDB { void extract_art_info(); void dump_art_info(const std::string& output_dir); void dump_raw_objects(const std::string& output_dir); - void write_object_file_words(const std::string& output_dir, bool dump_data, bool dump_code); void write_disassembly(const std::string& output_dir, bool disassemble_data, @@ -192,6 +191,9 @@ class ObjectFileDB { void ir2_do_segment_analysis_phase2(int seg, const Config& config, ObjectFileData& data); void ir2_setup_labels(const Config& config, ObjectFileData& data); void ir2_run_mips2c(const Config& config, ObjectFileData& data); + void ir2_analyze_all_types(const std::string& output_file, + const std::optional& previous_game_types, + const std::unordered_set& bad_types); std::string ir2_to_file(ObjectFileData& data, const Config& config); std::string ir2_function_to_string(ObjectFileData& data, Function& function, int seg); std::string ir2_final_out(ObjectFileData& data, diff --git a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp index 2331f6c016..6b72c9d00e 100644 --- a/decompiler/ObjectFile/ObjectFileDB_IR2.cpp +++ b/decompiler/ObjectFile/ObjectFileDB_IR2.cpp @@ -12,6 +12,7 @@ #include "common/util/Timer.h" #include "decompiler/IR2/Form.h" +#include "decompiler/analysis/analyze_inspect_method.h" #include "decompiler/analysis/cfg_builder.h" #include "decompiler/analysis/expression_build.h" #include "decompiler/analysis/final_output.h" @@ -103,7 +104,22 @@ void ObjectFileDB::analyze_functions_ir2( data.full_output = ir2_final_out(data, imports, {}); } - for_each_function_def_order_in_obj(data, [&](Function& f, int) { f.ir2 = {}; }); + if (!config.generate_all_types) { + // this frees ir2 memory, but means future passes can't look back on this function. + for_each_function_def_order_in_obj(data, [&](Function& f, int) { f.ir2 = {}; }); + } else { + for_each_function_def_order_in_obj(data, [&](Function& f, int seg) { + if (seg == 0) { + return; // keep top-levels + } + if (f.guessed_name.kind == FunctionName::FunctionKind::METHOD && + f.guessed_name.method_id == GOAL_INSPECT_METHOD) { + return; // keep inspects + } + // otherwise free memory + f.ir2 = {}; + }); + } fmt::print("Done in {:.2f}ms\n", file_timer.getMs()); }); @@ -280,6 +296,61 @@ void ObjectFileDB::ir2_top_level_pass(const Config& config) { lg::info("{:4d} logins {:.2f}%\n", total_top_levels, 100.f * total_top_levels / total_functions); } +void ObjectFileDB::ir2_analyze_all_types(const std::string& output_file, + const std::optional& previous_game_types, + const std::unordered_set& bad_types) { + struct PerObject { + std::string object_name; + std::vector type_defs; + std::string symbol_defs; + }; + + std::vector per_object; + + DecompilerTypeSystem previous_game_ts; + if (previous_game_types) { + previous_game_ts.parse_type_defs({*previous_game_types}); + } + + std::unordered_set already_seen; + for_each_obj([&](ObjectFileData& data) { + if (data.obj_version != 3) { + return; + } + auto& object_result = per_object.emplace_back(); + object_result.object_name = data.to_unique_name(); + + for_each_function_def_order_in_obj(data, [&](Function& f, int seg) { + if (seg == TOP_LEVEL_SEGMENT) { + object_result.symbol_defs += inspect_top_level_symbol_defines( + already_seen, f, data.linked_data, dts, previous_game_ts); + } else { + if (f.is_inspect_method && bad_types.find(f.guessed_name.type_name) == bad_types.end()) { + object_result.type_defs.push_back(inspect_inspect_method( + f, f.guessed_name.type_name, dts, data.linked_data, previous_game_ts.ts)); + } + } + }); + }); + + std::string result; + result += ";; All Types\n\n"; + + for (auto& obj : per_object) { + result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n"); + result += fmt::format(";; {:30s} ;;\n", obj.object_name); + result += fmt::format(";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\n\n"); + for (auto& t : obj.type_defs) { + result += t; + result += "\n"; + } + result += obj.symbol_defs; + result += "\n"; + } + + file_util::write_text_file(output_file, result); +} + /*! * Initial Function Analysis Pass to build the control flow graph. * - Find basic blocks @@ -322,7 +393,7 @@ void ObjectFileDB::ir2_basic_block_pass(int seg, const Config& config, ObjectFil asm_br_blocks = asm_lookup->second; } - func.cfg = build_cfg(data.linked_data, seg, func, hack, asm_br_blocks); + func.cfg = build_cfg(data.linked_data, seg, func, hack, asm_br_blocks, config.game_version); if (!func.cfg->is_fully_resolved()) { lg::warn("Function {} from {} failed to build control flow graph!", func.name(), data.to_unique_name()); @@ -548,23 +619,6 @@ void ObjectFileDB::ir2_cfg_build_pass(int seg, ObjectFileData& data) { }); } -// void ObjectFileDB::ir2_store_current_forms(int seg) { -// Timer timer; -// int total = 0; -// -// for_each_function_in_seg(seg, [&](Function& func, ObjectFileData& data) { -// (void)data; -// -// if (func.ir2.top_form) { -// total++; -// func.ir2.debug_form_string = -// pretty_print::to_string(func.ir2.top_form->to_form(func.ir2.env)); -// } -// }); -// -// lg::info("Stored debug forms for {} functions in {:.2f} ms\n", total, timer.getMs()); -//} -// void ObjectFileDB::ir2_build_expressions(int seg, const Config& config, ObjectFileData& data) { for_each_function_in_seg_in_obj(seg, data, [&](Function& func) { (void)data; diff --git a/decompiler/analysis/analyze_inspect_method.cpp b/decompiler/analysis/analyze_inspect_method.cpp new file mode 100644 index 0000000000..ed44d90e37 --- /dev/null +++ b/decompiler/analysis/analyze_inspect_method.cpp @@ -0,0 +1,988 @@ +#include "analyze_inspect_method.h" +#include "decompiler/Disasm/InstructionMatching.h" +#include "decompiler/ObjectFile/LinkedObjectFile.h" + +namespace decompiler { + +struct TypeInspectorResult { + bool success = false; + int type_size = -1; + int type_method_count = -1; + int parent_method_count = 9; + int type_heap_base = -1; + + std::string warnings; + std::vector fields_of_type; + bool is_basic = false; + bool found_flags = false; + + std::string type_name; + std::string parent_type_name; + u64 flags = 0; + + std::string print_as_deftype(StructureType* old_game_type); +}; + +bool is_set_reg_to_int(AtomicOp* op, Register dst, s64 value) { + // should be a set reg to int math 2 ir + auto set = dynamic_cast(op); + if (!set) { + return false; + } + + // destination should be a register + auto dest = set->dst(); + if (dst != dest.reg()) { + return false; + } + + auto math = set->src(); + if (SimpleExpression::Kind::IDENTITY != math.kind()) { + return false; + } + + auto arg = math.get_arg(0); + + if (!arg.is_int() || value != arg.get_int()) { + return false; + } + + return true; +} + +bool is_set_reg_to_symbol_value(AtomicOp* op, Register dst, const std::string& value) { + // should be a set reg to int math 2 ir + auto set = dynamic_cast(op); + if (!set) { + return false; + } + + // destination should be a register + auto dest = set->dst(); + if (dst != dest.reg()) { + return false; + } + + auto math = set->src(); + if (SimpleExpression::Kind::IDENTITY != math.kind()) { + return false; + } + + auto arg = math.get_arg(0); + + if (!arg.is_sym_val(value)) { + return false; + } + + return true; +} + +bool is_set_reg_to_symbol_ptr(AtomicOp* op, Register dst, const std::string& value) { + // should be a set reg to int math 2 ir + auto set = dynamic_cast(op); + if (!set) { + return false; + } + + // destination should be a register + auto dest = set->dst(); + if (dst != dest.reg()) { + return false; + } + + auto math = set->src(); + if (SimpleExpression::Kind::IDENTITY != math.kind()) { + return false; + } + + auto arg = math.get_arg(0); + + if (!arg.is_sym_ptr(value)) { + return false; + } + + return true; +} + +std::optional get_string_loaded_to_reg(AtomicOp* op, + Register reg, + LinkedObjectFile& file) { + // should be a set reg to int math 2 ir + auto set = dynamic_cast(op); + if (!set) { + return {}; + } + + // destination should be a register + auto dest = set->dst(); + if (reg != dest.reg()) { + return {}; + } + + auto math = set->src(); + if (SimpleExpression::Kind::IDENTITY != math.kind()) { + return {}; + } + + auto& src_atom = set->src().get_arg(0); + if (!src_atom.is_label()) { + return {}; + } + + return file.get_goal_string_by_label(src_atom.label()); +} + +struct FieldPrint { + char format = '\0'; + std::string field_name; + std::string field_type_name; + bool has_array = false; + int array_size = -1; +}; + +FieldPrint get_field_print(const std::string& str) { + int idx = 0; + auto next = [&]() { return str.at(idx++); }; + + auto peek = [&](int off) { return str.at(idx + off); }; + + FieldPrint field_print; + + // first is ~T + char c0 = next(); + ASSERT(c0 == '~'); + char c1 = next(); + if (c1 == '1') { + c1 = next(); + } + ASSERT(c1 == 'T'); + + // next the name: + char name_char = next(); + while (name_char != ':' && name_char != '[') { + field_print.field_name.push_back(name_char); + name_char = next(); + } + + // possibly array thing + if (name_char == '[') { + int size = 0; + char num_char = next(); + while (num_char >= '0' && num_char <= '9') { + size = size * 10 + (num_char - '0'); + num_char = next(); + } + field_print.has_array = true; + field_print.array_size = size; + + ASSERT(num_char == ']'); + char c = next(); + ASSERT(c == ' '); + c = next(); + ASSERT(c == '@'); + c = next(); + ASSERT(c == ' '); + c = next(); + ASSERT(c == '#'); + c = next(); + ASSERT(c == 'x'); + } else { + // next a space + char space_char = next(); + ASSERT(space_char == ' '); + } + + // next the format + char fmt1 = next(); + if (fmt1 == '~' && peek(0) != '`') { // normal ~_~% + char fmt_code = next(); + field_print.format = fmt_code; + char end1 = next(); + ASSERT(end1 == '~'); + char end2 = next(); + ASSERT(end2 == '%'); + ASSERT(idx == (int)str.size()); + } else if (fmt1 == '#' && peek(0) == '<') { // struct #~% + next(); + char type_name_c = next(); + while (type_name_c != ' ') { + field_print.field_type_name += type_name_c; + type_name_c = next(); + } + + std::string expect_end = "@ #x~X>~%"; + for (char i : expect_end) { + char c = next(); + ASSERT(i == c); + } + field_print.format = 'X'; + + ASSERT(idx == (int)str.size()); + } else if (fmt1 == '#' && peek(0) == 'x') { // #x~X~% + next(); + std::string expect_end = "~X~%"; + for (char i : expect_end) { + char c = next(); + ASSERT(i == c); + } + field_print.format = 'X'; + } else if (fmt1 == '~' && peek(0) == '`') { // ~`my-type-with-overriden-print`P~% + next(); + char type_name_c = next(); + while (type_name_c != '`') { + field_print.field_type_name += type_name_c; + type_name_c = next(); + } + + std::string expect_end = "P~%"; + for (char i : expect_end) { + char c = next(); + ASSERT(i == c); + } + field_print.format = 'P'; + + ASSERT(idx == (int)str.size()); + } else if (str.substr(idx - 1) == "(meters ~m)~%") { + field_print.format = 'm'; + } else if (str.substr(idx - 1) == "(deg ~r)~%") { + field_print.format = 'r'; + } else if (str.substr(idx - 1) == "(seconds ~e)~%") { + field_print.format = 'e'; + } + + else { + throw std::runtime_error("other format nyi in get_field_print " + str.substr(idx)); + } + + return field_print; +} + +int get_start_idx(Function& function, + LinkedObjectFile& file, + TypeInspectorResult* result, + const std::string& parent_type, + const std::string& type_name, + Env& env) { + if (function.basic_blocks.size() != 5) { + fmt::print("[iim] inspect {} had {} basic blocks, expected 5\n", function.name(), + function.basic_blocks.size()); + return -1; + } + + if (!function.ir2.atomic_ops) { + fmt::print("[iim] no atomic ops in {}\n", function.name()); + return -1; + } + auto& aos = *function.ir2.atomic_ops; + + int op_idx = 0; + // block 0: + /* + * (set! gp a0) + * (b! (truthy gp) L370 (set! v1 #f)) + */ + + if (aos.block_id_to_end_atomic_op.at(0) != 2) { + fmt::print("[iim] block 0 had the wrong number of ops: {} for {}\n", + aos.block_id_to_end_atomic_op.at(0), function.name()); + return -1; + } + + if (!is_op_2(aos.ops.at(op_idx).get(), SimpleExpression::Kind::IDENTITY, + Register(Reg::GPR, Reg::GP), Register(Reg::GPR, Reg::A0))) { + fmt::print("[iim] block 0 op 0 bad in {}: {}\n", aos.ops.at(op_idx)->to_string(env), + function.name()); + return -1; + } + op_idx++; + + auto br = dynamic_cast(aos.ops.at(op_idx).get()); + if (!br) { + fmt::print("[iim] block 0 op 1 bad in {}: {} (not branch)\n", aos.ops.at(1)->to_string(env), + function.name()); + return -1; + } + + if (br->likely() || br->condition().kind() != IR2_Condition::Kind::TRUTHY || + !br->condition().src(0).is_var() || + br->condition().src(0).var().reg() != Register(Reg::GPR, Reg::GP) || + br->branch_delay().kind() != IR2_BranchDelay::Kind::SET_REG_FALSE || + br->branch_delay().var(0).reg() != Register(Reg::GPR, Reg::V1)) { + fmt::print("[iim] block 0 op 1 bad in {}: {} (bad branch)\n", aos.ops.at(1)->to_string(env), + function.name()); + return -1; + } + op_idx++; + + // block 1: + /* + * (set! gp gp) + * (b! #t L371 (nop!)) + */ + if (aos.block_id_to_end_atomic_op.at(1) != 4) { + fmt::print("[iim] block 1 had the wrong number of ops: {} for {}\n", + aos.block_id_to_end_atomic_op.at(1), function.name()); + return -1; + } + + if (!is_op_2(aos.ops.at(op_idx).get(), SimpleExpression::Kind ::IDENTITY, + Register(Reg::GPR, Reg::GP), Register(Reg::GPR, Reg::GP))) { + fmt::print("[iim] op 2 bad in {}: {}\n", aos.ops.at(op_idx)->to_string(env), function.name()); + return -1; + } + op_idx++; + + auto br2 = dynamic_cast(aos.ops.at(op_idx).get()); + if (!br2) { + fmt::print("[iim] op 3 bad in {}: {} (not branch)\n", aos.ops.at(op_idx)->to_string(env), + function.name()); + return -1; + } + + if (br2->likely() || br2->condition().kind() != IR2_Condition::Kind::ALWAYS || + br2->branch_delay().kind() != IR2_BranchDelay::Kind::NOP) { + fmt::print("[iim] op3 bad in {}: {} (bad branch)\n", aos.ops.at(op_idx)->to_string(env), + function.name()); + return -1; + } + op_idx++; + + // setup + /* + (set! v1 0) + (set! t9 format) + (set! a0 #t) + (set! a1 L386) + (set! a2 gp) + (set! a3 'vector) (also can be (set! a3 (l.wu (+ gp -4)))) + (call!) + */ + + if (!is_set_reg_to_int(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::V1), 0)) { + fmt::print("[iim] op4 bad in {}: {} (bad set 0)\n", aos.ops.at(op_idx)->to_string(env), + function.name()); + } + op_idx++; + + if (!is_set_reg_to_symbol_value(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::T9), + "format")) { + fmt::print("[iim] op5 bad in {}: {} (bad set format)\n", aos.ops.at(op_idx)->to_string(env), + function.name()); + } + op_idx++; + + if (!is_set_reg_to_symbol_ptr(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::A0), "#t")) { + fmt::print("[iim] op6 bad in {}: {} (bad set #t)\n", aos.ops.at(op_idx)->to_string(env), + function.name()); + } + op_idx++; + + auto type_name_str = + get_string_loaded_to_reg(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::A1), file); + if (!type_name_str) { + fmt::print("[iim] op7 bad in {}: {} (bad string)\n", aos.ops.at(op_idx)->to_string(env), + function.name()); + } + if (type_name_str != "[~8x] ~A~%") { + fmt::print("[iim] op7 bad in {}: {} (bad string: {})\n", aos.ops.at(op_idx)->to_string(env), + function.name(), *type_name_str); + } + op_idx++; + + if (!is_op_2(aos.ops.at(op_idx).get(), SimpleExpression::Kind ::IDENTITY, + Register(Reg::GPR, Reg::A2), Register(Reg::GPR, Reg::GP))) { + fmt::print("[iim] op 8 bad in {}: {}\n", aos.ops.at(op_idx)->to_string(env), function.name()); + return -1; + } + op_idx++; + + if (is_set_reg_to_symbol_ptr(aos.ops.at(op_idx).get(), Register(Reg::GPR, Reg::A3), type_name)) { + result->is_basic = false; + } else if (aos.ops.at(op_idx)->to_string(env) == "(set! a3 (l.wu (+ gp -4)))") { + result->is_basic = true; + } else { + fmt::print("[iim] op 9 bad in {}: {}\n", aos.ops.at(op_idx)->to_string(env), function.name()); + return -1; + } + op_idx++; + + if (!dynamic_cast(aos.ops.at(op_idx).get())) { + fmt::print("[iim] op 10 bad in {}: {}\n", aos.ops.at(op_idx)->to_string(env), function.name()); + return -1; + } + op_idx++; + + return op_idx; +} + +std::pair get_base_of_load(const SimpleExpression& load_addr) { + if (load_addr.kind() == SimpleExpression::Kind::IDENTITY) { + const auto& src = load_addr.get_arg(0); + if (src.is_var()) { + return {src.var().reg(), 0}; + } + } + + if (load_addr.kind() == SimpleExpression::Kind::ADD) { + const auto& src0 = load_addr.get_arg(0); + const auto& src1 = load_addr.get_arg(1); + if (src1.get_kind() == SimpleAtom::Kind::INTEGER_CONSTANT && + src0.get_kind() == SimpleAtom::Kind::VARIABLE) { + return {src0.var().reg(), src1.get_int()}; + } + } + ASSERT(false); +} + +bool is_load_with_base(const SimpleExpression& expr, Register base) { + return get_base_of_load(expr).first == base; +} + +bool is_get_load(AtomicOp* ir, Register dst, Register base) { + auto as_set = dynamic_cast(ir); + return as_set && as_set->get_set_destination().reg() == dst && + is_load_with_base(as_set->src(), base); +} + +struct LoadInfo { + int offset = 0; + int size = 0; + LoadVarOp::Kind kind; +}; + +LoadInfo get_load_info_from_set(AtomicOp* load) { + auto as_load = dynamic_cast(load); + ASSERT(as_load); + LoadInfo info; + info.kind = as_load->kind(); + info.size = as_load->size(); + auto base = get_base_of_load(as_load->src()); + info.offset = base.second; + return info; +} + +int identify_int_field(int idx, + Function& function, + TypeInspectorResult* result, + FieldPrint& print_info) { + auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get()); + + std::string field_type_name; + if (load_info.kind == LoadVarOp::Kind::UNSIGNED) { + field_type_name += "u"; + } else if (load_info.kind == LoadVarOp::Kind::FLOAT) { + ASSERT(false); // ... + } + field_type_name += "int"; + + switch (load_info.size) { + case 1: + field_type_name += "8"; + break; + case 2: + field_type_name += "16"; + break; + case 4: + field_type_name += "32"; + break; + case 8: + field_type_name += "64"; + break; + case 16: + field_type_name += "128"; + break; + default: + throw std::runtime_error("unknown load op size in identify int field " + + std::to_string((int)load_info.size)); + } + + if (print_info.format == 'e') { + field_type_name = "seconds"; + ASSERT(load_info.size == 8); + } + + int offset = load_info.offset; + if (result->is_basic) { + offset += BASIC_OFFSET; + } + + Field field(print_info.field_name, TypeSpec(field_type_name), offset); + result->fields_of_type.push_back(field); + + return idx; +} +int identify_float_field(int idx, + Function& function, + TypeInspectorResult* result, + FieldPrint& print_info) { + auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get()); + ASSERT(load_info.size == 4); + ASSERT(load_info.kind == LoadVarOp::Kind::FLOAT); + + auto& float_move = function.ir2.atomic_ops->ops.at(idx++); + if (!is_op_2(float_move.get(), SimpleExpression::Kind::FPR_TO_GPR, make_gpr(Reg::A2), + make_fpr(0))) { + printf("bad float move: %s\n", float_move->to_string(function.ir2.env).c_str()); + ASSERT(false); + } + + std::string type; + switch (print_info.format) { + case 'f': + type = "float"; + break; + case 'm': + type = "meters"; + break; + case 'r': + type = "deg"; + break; + case 'X': + type = "float"; + result->warnings += "field " + print_info.field_name + " is a float printed as hex? "; + break; + default: + ASSERT(false); + } + int offset = load_info.offset; + if (result->is_basic) { + offset += BASIC_OFFSET; + } + + Field field(print_info.field_name, TypeSpec(type), offset); + result->fields_of_type.push_back(field); + return idx; +} + +int identify_pointer_field(int idx, + Function& function, + TypeInspectorResult* result, + FieldPrint& print_info) { + auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get()); + ASSERT(load_info.size == 4); + ASSERT(load_info.kind == LoadVarOp::Kind::UNSIGNED); + + int offset = load_info.offset; + if (result->is_basic) { + offset += BASIC_OFFSET; + } + + Field field(print_info.field_name, TypeSpec("pointer"), offset); + result->fields_of_type.push_back(field); + return idx; +} + +bool get_ptr_offset_constant_nonzero(const SimpleExpression& math, Register base, int* result) { + // if (!is_reg(math->arg0.get(), base)) { + if (!math.get_arg(0).is_var() || math.get_arg(0).var().reg() != base) { + return false; + } + + if (!math.get_arg(1).is_int()) { + return false; + } + + *result = math.get_arg(1).get_int(); + return true; +} + +bool get_ptr_offset(AtomicOp* ir, Register dst, Register base, int* result) { + auto as_set = dynamic_cast(ir); + if (!as_set) { + return false; + } + if (as_set->dst().reg() != dst) { + return false; + } + + return get_ptr_offset_constant_nonzero(as_set->src(), base, result); +} + +int identify_array_field(int idx, + Function& function, + TypeInspectorResult* result, + FieldPrint& print_info) { + auto& get_op = function.ir2.atomic_ops->ops.at(idx++); + int offset = 0; + if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) { + printf("bad get ptr offset %s\n", get_op->to_string(function.ir2.env).c_str()); + ASSERT(false); + } + if (result->is_basic) { + offset += BASIC_OFFSET; + } + + Field field(print_info.field_name, TypeSpec("UNKNOWN"), offset); + if (print_info.array_size) { + field.set_array(print_info.array_size); + } else { + field.set_dynamic(); + } + result->fields_of_type.push_back(field); + return idx; +} + +int identify_struct_not_inline_field(int idx, + Function& function, + TypeInspectorResult* result, + FieldPrint& print_info) { + auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get()); + + if (!(load_info.size == 4 && load_info.kind == LoadVarOp::Kind::UNSIGNED)) { + result->warnings += "field " + print_info.field_type_name + " is likely a value type"; + } + int offset = load_info.offset; + if (result->is_basic) { + offset += BASIC_OFFSET; + } + + Field field(print_info.field_name, TypeSpec(print_info.field_type_name), offset); + result->fields_of_type.push_back(field); + return idx; +} + +int identify_struct_inline_field(int idx, + Function& function, + TypeInspectorResult* result, + FieldPrint& print_info) { + auto& get_op = function.ir2.atomic_ops->ops.at(idx++); + int offset = 0; + if (!get_ptr_offset(get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP), &offset)) { + printf("bad get ptr offset %s\n", get_op->to_string(function.ir2.env).c_str()); + ASSERT(false); + } + if (result->is_basic) { + offset += BASIC_OFFSET; + } + + Field field(print_info.field_name, TypeSpec(print_info.field_type_name), offset); + field.set_inline(); + result->fields_of_type.push_back(field); + return idx; +} + +int identify_basic_field(int idx, + Function& function, + LinkedObjectFile& file, + TypeInspectorResult* result, + FieldPrint& print_info) { + (void)file; + auto load_info = get_load_info_from_set(function.ir2.atomic_ops->ops.at(idx++).get()); + ASSERT(load_info.size == 4); + ASSERT(load_info.kind == LoadVarOp::Kind::UNSIGNED || load_info.kind == LoadVarOp::Kind::SIGNED); + + if (load_info.kind == LoadVarOp::Kind::SIGNED) { + result->warnings += "field " + print_info.field_name + " is a basic loaded with a signed load "; + } + + int offset = load_info.offset; + if (result->is_basic) { + offset += BASIC_OFFSET; + } + + Field field(print_info.field_name, TypeSpec("basic"), offset); + result->fields_of_type.push_back(field); + return idx; +} + +int detect(int idx, Function& function, LinkedObjectFile& file, TypeInspectorResult* result) { + auto& get_format_op = function.ir2.atomic_ops->ops.at(idx++); + if (!is_set_reg_to_symbol_value(get_format_op.get(), make_gpr(Reg::T9), "format")) { + ASSERT_MSG(false, + fmt::format("bad get format: {}\n", get_format_op->to_string(function.ir2.env))); + } + + auto& get_true = function.ir2.atomic_ops->ops.at(idx++); + if (!is_set_reg_to_symbol_ptr(get_true.get(), make_gpr(Reg::A0), "#t")) { + ASSERT_MSG(false, "bad get true"); + } + + auto sstr = get_string_loaded_to_reg(function.ir2.atomic_ops->ops.at(idx++).get(), + make_gpr(Reg::A1), file); + if (!sstr) { + ASSERT_MSG(false, "bad sstr"); + } + + auto info = get_field_print(*sstr); + + auto& first_get_op = function.ir2.atomic_ops->ops.at(idx); + + if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && + (info.format == 'D' || info.format == 'X' || info.format == 'e') && !info.has_array && + info.field_type_name.empty()) { + idx = identify_int_field(idx, function, result, info); + // it's a load! + } else if (is_get_load(first_get_op.get(), make_fpr(0), make_gpr(Reg::GP)) && + (info.format == 'f' || info.format == 'm' || info.format == 'r' || + info.format == 'X') && + !info.has_array && info.field_type_name.empty()) { + idx = identify_float_field(idx, function, result, info); + } else if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && + info.format == 'A' && !info.has_array && info.field_type_name.empty()) { + idx = identify_basic_field(idx, function, file, result, info); + } else if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP)) && + info.format == 'X' && !info.has_array && info.field_type_name.empty()) { + idx = identify_pointer_field(idx, function, result, info); + } else if (info.has_array && (info.format == 'X' || info.format == 'P') && + info.field_type_name.empty()) { + idx = identify_array_field(idx, function, result, info); + } else if (!info.has_array && (info.format == 'X' || info.format == 'P') && + !info.field_type_name.empty()) { + // structure. + if (is_get_load(first_get_op.get(), make_gpr(Reg::A2), make_gpr(Reg::GP))) { + // not inline + idx = identify_struct_not_inline_field(idx, function, result, info); + } else { + idx = identify_struct_inline_field(idx, function, result, info); + } + } + + else { + printf("couldn't do %s, %s\n", sstr->c_str(), + first_get_op->to_string(function.ir2.env).c_str()); + return -1; + } + + if (!dynamic_cast(function.ir2.atomic_ops->ops.at(idx++).get())) { + printf("bad call\n"); + ASSERT(false); + return -1; + } + + return idx; +} + +std::string inspect_inspect_method(Function& inspect_method, + const std::string& type_name, + DecompilerTypeSystem& dts, + LinkedObjectFile& file, + TypeSystem& previous_game_ts) { + fmt::print(" iim: {}\n", inspect_method.name()); + TypeInspectorResult result; + ASSERT(type_name == inspect_method.guessed_name.type_name); + TypeFlags flags; + flags.flag = 0; + result.found_flags = dts.lookup_flags(type_name, &flags.flag); + result.type_name = type_name; + result.parent_type_name = dts.lookup_parent_from_inspects(type_name); + result.flags = flags.flag; + result.type_size = flags.size; + result.type_method_count = flags.methods; + result.type_heap_base = flags.heap_base; + + { + TypeFlags parent_flags; + parent_flags.flag = 0; + if (result.parent_type_name != "UNKNOWN" && + dts.lookup_flags(result.parent_type_name, &parent_flags.flag)) { + result.parent_method_count = parent_flags.methods; + } + } + if (!result.found_flags) { + fmt::print("[iim] no flags found for {}, maybe defined in the kernel\n", type_name); + } + + result.parent_type_name = dts.lookup_parent_from_inspects(type_name); + int idx = get_start_idx(inspect_method, file, &result, result.parent_type_name, type_name, + inspect_method.ir2.env); + StructureType* old_game_type = nullptr; + if (previous_game_ts.fully_defined_type_exists(type_name)) { + old_game_type = dynamic_cast(previous_game_ts.lookup_type(type_name)); + } + if (idx <= 0) { + // can't get any field... + result.warnings += "Failed to read fields. "; + idx = -2; + return result.print_as_deftype(old_game_type); + } + while (idx < int(inspect_method.ir2.atomic_ops->ops.size()) - 2 && idx != -1) { + idx = detect(idx, inspect_method, file, &result); + } + + if (idx == -1) { + result.warnings += "Failed to read some fields. "; + } + + return result.print_as_deftype(old_game_type); +} + +std::string old_method_string(const MethodInfo& info) { + if (info.type.arg_count() > 0) { + if (info.type.base_type() == "function" || info.type.base_type() == "state") { + std::string result = fmt::format(" ;; ({} (", info.name); + bool add = false; + for (int i = 0; i < (int)info.type.arg_count() - 1; i++) { + result += info.type.get_arg(i).print(); + result += ' '; + add = true; + } + if (add) { + result.pop_back(); + } + result += ") "; + result += info.type.get_arg(info.type.arg_count() - 1).print(); + if (info.type.base_type() == "state") { + result += " :state"; + } + result += fmt::format(" {})", info.id); + return result; + } + } + + return fmt::format(" ;; ({} {}) weird method", info.name, info.type.print()); +} + +/* + * old_game_type may be null + */ +std::string TypeInspectorResult::print_as_deftype(StructureType* old_game_type) { + std::string result; + + result += fmt::format("(deftype {} ({})\n (", type_name, parent_type_name); + + int longest_field_name = 0; + int longest_type_name = 0; + int longest_mods = 0; + + std::string inline_string = ":inline"; + std::string dynamic_string = ":dynamic"; + + for (auto& field : fields_of_type) { + longest_field_name = std::max(longest_field_name, int(field.name().size())); + longest_type_name = std::max(longest_type_name, int(field.type().print().size())); + + int mods = 0; + // mods are array size, :inline, :dynamic + if (field.is_array() && !field.is_dynamic()) { + mods += std::to_string(field.array_size()).size(); + } + + if (field.is_inline()) { + if (mods) { + mods++; // space + } + mods += inline_string.size(); + } + + if (field.is_dynamic()) { + if (mods) { + mods++; // space + } + mods += dynamic_string.size(); + } + longest_mods = std::max(longest_mods, mods); + } + + for (auto& field : fields_of_type) { + result += "("; + result += field.name(); + result.append(1 + (longest_field_name - int(field.name().size())), ' '); + result += field.type().print(); + result.append(1 + (longest_type_name - int(field.type().print().size())), ' '); + + std::string mods; + if (field.is_array() && !field.is_dynamic()) { + mods += std::to_string(field.array_size()); + mods += " "; + } + + if (field.is_inline()) { + mods += inline_string; + mods += " "; + } + + if (field.is_dynamic()) { + mods += dynamic_string; + mods += " "; + } + result.append(mods); + result.append(longest_mods - int(mods.size() - 1), ' '); + + result.append(":offset-assert "); + result.append(std::to_string(field.offset())); + result.append(")"); + if (old_game_type) { + Field old_field; + if (old_game_type->lookup_field(field.name(), &old_field)) { + if (old_field.type() != field.type()) { + result += fmt::format(" ;; {}", old_field.type().print()); + if (old_field.is_array() && !old_field.is_dynamic()) { + result += fmt::format(" {}", old_field.array_size()); + } + if (old_field.is_inline()) { + result += " :inline"; + } + if (old_field.is_dynamic()) { + result += " :dynamic"; + } + } + } + } + result.append("\n "); + } + result.append(")\n"); + + result.append(fmt::format(" :method-count-assert {}\n", type_method_count)); + result.append(fmt::format(" :size-assert #x{:x}\n", type_size)); + result.append(fmt::format(" :flag-assert #x{:x}\n ", flags)); + if (!warnings.empty()) { + result.append(";; "); + result.append(warnings); + result.append("\n "); + } + + if (type_method_count > 9) { + result.append("(:methods\n "); + MethodInfo old_new_method; + if (old_game_type && old_game_type->get_my_new_method(&old_new_method)) { + result.append(old_method_string(old_new_method)); + result.append("\n "); + } + for (int i = parent_method_count; i < type_method_count; i++) { + result.append(fmt::format("(dummy-{} () none {})", i, i)); + if (old_game_type) { + MethodInfo info; + if (old_game_type->get_my_method(i, &info)) { + result += old_method_string(info); + } + } + result.append("\n "); + } + result.append(")\n "); + } + result.append(")\n"); + + return result; +} + +std::string inspect_top_level_symbol_defines(std::unordered_set& already_seen, + Function& top_level, + LinkedObjectFile& file, + DecompilerTypeSystem& dts, + DecompilerTypeSystem& previous_game_ts) { + if (!top_level.ir2.atomic_ops) { + return {}; + } + std::string result; + for (auto& aop : top_level.ir2.atomic_ops->ops) { + auto* as_store = dynamic_cast(aop.get()); + if (as_store && as_store->addr().kind() == SimpleExpression::Kind::IDENTITY && + as_store->addr().get_arg(0).is_sym_val()) { + auto& sym_name = as_store->addr().get_arg(0).get_str(); + if (already_seen.find(sym_name) == already_seen.end()) { + already_seen.insert(sym_name); + if (dts.ts.partially_defined_type_exists(sym_name)) { + continue; + } + result += fmt::format(";; (define-extern {} object)", sym_name); + auto it = previous_game_ts.symbol_types.find(sym_name); + if (it != previous_game_ts.symbol_types.end()) { + result += fmt::format(" ;; {}", it->second.print()); + } + result += '\n'; + } + } + } + return result; +} +} // namespace decompiler diff --git a/decompiler/analysis/analyze_inspect_method.h b/decompiler/analysis/analyze_inspect_method.h new file mode 100644 index 0000000000..ed2dfa222e --- /dev/null +++ b/decompiler/analysis/analyze_inspect_method.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "decompiler/Function/Function.h" +#include "decompiler/util/DecompilerTypeSystem.h" + +namespace decompiler { + +std::string inspect_inspect_method(Function& inspect_method, + const std::string& type_name, + DecompilerTypeSystem& dts, + LinkedObjectFile& file, + TypeSystem& previous_game_ts); + +std::string inspect_top_level_symbol_defines(std::unordered_set& already_seen, + Function& top_level, + LinkedObjectFile& file, + DecompilerTypeSystem& dts, + DecompilerTypeSystem& previous_game_ts); + +} // namespace decompiler \ No newline at end of file diff --git a/decompiler/analysis/atomic_op_builder.cpp b/decompiler/analysis/atomic_op_builder.cpp index 9a67cdbbb7..b78af1c05c 100644 --- a/decompiler/analysis/atomic_op_builder.cpp +++ b/decompiler/analysis/atomic_op_builder.cpp @@ -1746,11 +1746,23 @@ std::unique_ptr convert_5(const Instruction& i0, const Instruction& i2, const Instruction& i3, const Instruction& i4, - int idx) { + int idx, + GameVersion version) { auto s6 = make_gpr(Reg::S6); + int process_offset = -1; + switch (version) { + case GameVersion::Jak1: + process_offset = 44; + break; + case GameVersion::Jak2: + process_offset = 48; + break; + default: + ASSERT(false); + } if (i0.kind == InstructionKind::LWU && i0.get_dst(0).is_reg(s6) && - i0.get_src(0).get_imm() == 44 && i0.get_src(1).is_reg(s6) && + i0.get_src(0).get_imm() == process_offset && i0.get_src(1).is_reg(s6) && i1.kind == InstructionKind::MTLO1 && i1.get_src(0).is_reg(s6) && i2.kind == InstructionKind::LWU && i2.get_dst(0).is_reg(s6) && i2.get_src(0).get_imm() == 12 && i2.get_src(1).is_reg(s6) && @@ -2111,7 +2123,7 @@ int convert_block_to_atomic_ops(int begin_idx, if (!converted && n_instr >= 5) { // try 5 instructions - op = convert_5(instr[0], instr[1], instr[2], instr[3], instr[4], op_idx); + op = convert_5(instr[0], instr[1], instr[2], instr[3], instr[4], op_idx, version); if (op) { converted = true; length = 5; diff --git a/decompiler/analysis/cfg_builder.cpp b/decompiler/analysis/cfg_builder.cpp index 5f28a87947..c4c64b87ec 100644 --- a/decompiler/analysis/cfg_builder.cpp +++ b/decompiler/analysis/cfg_builder.cpp @@ -110,12 +110,12 @@ void clean_up_until_loop(FormPool& pool, UntilElement* ir, const Env& env) { ASSERT(condition_branch.first); if (condition_branch.first->op()->branch_delay().kind() != IR2_BranchDelay::Kind::NOP) { ASSERT_MSG( - false, + condition_branch.first->op()->branch_delay().kind() == IR2_BranchDelay::Kind::SET_REG_FALSE, fmt::format( "bad delay slot in until loop: {} in {}\n", env.func->name(), condition_branch.first->op()->branch_delay().to_form(env.file->labels, env).print())); + ir->false_destination = condition_branch.first->op()->branch_delay().var(0); } - ASSERT(condition_branch.first->op()->branch_delay().kind() == IR2_BranchDelay::Kind::NOP); auto replacement = condition_branch.first->op()->get_condition_as_form(pool, env); replacement->invert(); *(condition_branch.second) = replacement; @@ -573,7 +573,7 @@ bool try_splitting_nested_sc(FormPool& pool, Function& func, ShortCircuitElement ASSERT(ir->entries.at(i).branch_delay.has_value()); bool is_and = delay_slot_sets_false(branch.first, *ir->entries.at(i).branch_delay); bool is_or = delay_slot_sets_truthy(branch.first, *ir->entries.at(i).branch_delay); - ASSERT(is_and != is_or); + ASSERT_MSG(is_and != is_or, fmt::format("bad nested sc in {}", func.name())); if (first_different == -1) { // haven't seen a change yet. @@ -925,47 +925,6 @@ bool is_op_3(AtomicOp* op, return true; } -bool is_op_2(AtomicOp* op, - MatchParam kind, - MatchParam dst, - MatchParam src0, - Register* dst_out = nullptr, - Register* src0_out = nullptr) { - // should be a set reg to int math 2 ir - auto set = dynamic_cast(op); - if (!set) { - return false; - } - - // destination should be a register - auto dest = set->dst(); - if (dst != dest.reg()) { - return false; - } - - auto math = set->src(); - if (kind != math.kind()) { - return false; - } - - auto arg = math.get_arg(0); - - if (!arg.is_var() || src0 != arg.var().reg()) { - return false; - } - - // it's a match! - if (dst_out) { - *dst_out = dest.reg(); - } - - if (src0_out) { - *src0_out = arg.var().reg(); - } - - return true; -} - bool is_op_2(FormElement* ir, MatchParam kind, MatchParam dst, diff --git a/decompiler/config.cpp b/decompiler/config.cpp index a855103321..05d20e7989 100644 --- a/decompiler/config.cpp +++ b/decompiler/config.cpp @@ -76,7 +76,10 @@ Config read_config_file(const std::string& path_to_config_file, config.is_pal = cfg.at("is_pal").get(); config.rip_levels = cfg.at("levels_convert_to_obj").get(); config.extract_collision = cfg.at("extract_collision").get(); - + config.generate_all_types = cfg.at("generate_all_types").get(); + if (cfg.contains("old_all_types_file")) { + config.old_all_types_file = cfg.at("old_all_types_file").get(); + } auto allowed = cfg.at("allowed_objects").get>(); for (const auto& x : allowed) { config.allowed_objects.insert(x); diff --git a/decompiler/config.h b/decompiler/config.h index 2c5da26435..13f41bf39c 100644 --- a/decompiler/config.h +++ b/decompiler/config.h @@ -123,6 +123,9 @@ struct Config { bool generate_symbol_definition_map = false; + bool generate_all_types = false; + std::optional old_all_types_file; + bool is_pal = false; bool write_patches = false; diff --git a/decompiler/config/all-types2.gc b/decompiler/config/all-types2.gc index 8031702032..f1fead6ce9 100644 --- a/decompiler/config/all-types2.gc +++ b/decompiler/config/all-types2.gc @@ -13,4 +13,7 @@ (declare-type sparticle-launch-group basic) (declare-type lightning-spec basic) (declare-type sparticle-launcher basic) -(declare-type state basic) \ No newline at end of file +(declare-type state basic) + +;; debug +(define-extern looping-code (function symbol)) diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index 54687de809..3b47568866 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -51,6 +51,9 @@ // this is a guess at where each symbol is first defined/used. "generate_symbol_definition_map": false, + // genreate the all-types file + "generate_all_types" : false, + // debug option for instruction decoder "write_hex_near_instructions": false, diff --git a/decompiler/config/jak2/hacks.jsonc b/decompiler/config/jak2/hacks.jsonc index c7c97c3ef7..be07fe5d5c 100644 --- a/decompiler/config/jak2/hacks.jsonc +++ b/decompiler/config/jak2/hacks.jsonc @@ -4,7 +4,9 @@ //////////////////////////// "types_with_bad_inspect_methods": [ - + "game-task-event", + "game-task-control", + "predator-edge" ], "no_type_analysis_functions_by_name": [], @@ -55,7 +57,8 @@ "(anon-function 2 scene)", "progress-trans", "(method 10 bigmap)", "(method 9 editable-region)", "(method 57 enemy)", "(anon-function 10 meet-brutter)", "(method 154 vehicle-racer)", "(method 188 predator)", "(anon-function 13 sig0-course)", "(method 228 hal-sewer)", "(method 154 vehicle-city-racer)", "(method 53 squid)", "(anon-function 11 fort-floor-spike)", - "(method 29 gun-dummy)", "vehicle-explode-post", "(method 158 vehicle-guard)", "(method 207 metalhead-predator)" + "(method 29 gun-dummy)", "vehicle-explode-post", "(method 158 vehicle-guard)", "(method 207 metalhead-predator)", + "(anon-function 4 gun-states)", "(anon-function 28 grenadier)", "(anon-function 24 grenadier)" ], // these functions use pairs and the decompiler diff --git a/decompiler/config/jak2/inputs.jsonc b/decompiler/config/jak2/inputs.jsonc index 432e6311c5..f7e28d62cd 100644 --- a/decompiler/config/jak2/inputs.jsonc +++ b/decompiler/config/jak2/inputs.jsonc @@ -8,159 +8,159 @@ // the DGOs will be processed in this order. Usually it's best to have KERNEL, ENGINE, then the levels when // you want to run on the entire game. "dgo_names": [ - "./CGO/ART.CGO", - "./CGO/KERNEL.CGO", - "./CGO/ENGINE.CGO", - "./CGO/GAME.CGO", - "./CGO/COMMON.CGO", - "./DGO/LWIDEB.DGO", - "./DGO/LMEETBRT.DGO", - "./DGO/CTA.DGO", - "./DGO/PALOUT.DGO", - "./DGO/STD.DGO", - "./DGO/FOR.DGO", - "./DGO/CASEXT.DGO", - "./DGO/HIDEOUT.DGO", - "./DGO/LWIDESTA.DGO", - "./DGO/LRACELIT.DGO", - "./DGO/CTB.DGO", - "./DGO/KIOSK.DGO", - "./DGO/DG1.DGO", - "./DGO/FEB.DGO", - "./DGO/DMI.DGO", - "./DGO/ORACLE.DGO", - "./DGO/LERLTESS.DGO", - "./DGO/DRI.DGO", - "./DGO/LBRNERMK.DGO", - "./DGO/LRACECF.DGO", - "./DGO/CTC.DGO", - "./DGO/LTHRNOUT.DGO", - "./DGO/FRA.DGO", - "./DGO/LGARCSTA.DGO", - "./DGO/MTN.DGO", - "./DGO/INTROCST.DGO", - "./DGO/DRB.DGO", - "./DGO/ATE.DGO", - "./DGO/LERROL.DGO", - "./DGO/LTRNYSAM.DGO", - "./DGO/LOUTCSTB.DGO", - "./DGO/LASHTHRN.DGO", - "./DGO/TOC.DGO", - "./DGO/CFB.DGO", - "./DGO/CAB.DGO", - "./DGO/STC.DGO", - "./DGO/STR.DGO", - "./DGO/ATO.DGO", - "./DGO/SEB.DGO", - "./DGO/LPRSNCST.DGO", - "./DGO/SWB.DGO", - "./DGO/LPOWER.DGO", - "./DGO/FOB.DGO", - "./DGO/CIB.DGO", - "./DGO/LSHUTTLE.DGO", - "./DGO/LJAKDAX.DGO", - "./DGO/FORDUMPC.DGO", - "./DGO/LTRNTESS.DGO", - "./DGO/TBO.DGO", - "./DGO/THR.DGO", - "./DGO/PRI.DGO", - "./DGO/LKIDDOGE.DGO", - "./DGO/NESTT.DGO", - "./DGO/LWIDEC.DGO", - "./DGO/SAG.DGO", - "./DGO/NEB.DGO", - "./DGO/COB.DGO", - "./DGO/LBOMBBOT.DGO", - "./DGO/DEMO.DGO", - "./DGO/LRACEDF.DGO", - "./DGO/LERLCHAL.DGO", - "./DGO/LHIPOUT.DGO", - "./DGO/OUTROCST.DGO", - "./DGO/NES.DGO", - "./DGO/PAR.DGO", - "./DGO/LERBRNGD.DGO", - "./DGO/MTX.DGO", - "./DGO/FDA.DGO", - "./DGO/LKEIRIFT.DGO", - "./DGO/LWHACK.DGO", - "./DGO/LJKDXASH.DGO", - "./DGO/CAS.DGO", - "./DGO/COA.DGO", - "./DGO/LTESS.DGO", - "./DGO/CFA.DGO", - "./DGO/TOMBEXT.DGO", - "./DGO/LCGUARD.DGO", - "./DGO/TOE.DGO", - "./DGO/PALBOSS.DGO", - "./DGO/FRB.DGO", - "./DGO/PAE.DGO", - "./DGO/TITLE.DGO", - "./DGO/FORDUMPD.DGO", - "./DGO/D3A.DGO", - "./DGO/DRILLMTN.DGO", - "./DGO/PAC.DGO", - "./DGO/LTENTOB.DGO", - "./DGO/LRACEBF.DGO", - "./DGO/LPROTECT.DGO", - "./DGO/FEA.DGO", - "./DGO/ONINTENT.DGO", - "./DGO/STA.DGO", - "./DGO/CGC.DGO", - "./DGO/CMA.DGO", - "./DGO/FDB.DGO", - "./DGO/SKA.DGO", - "./DGO/LTRNKRKD.DGO", - "./DGO/CIA.DGO", - "./DGO/TOB.DGO", - "./DGO/LRACEDB.DGO", - "./DGO/LDJAKBRN.DGO", - "./DGO/TOA.DGO", - "./DGO/STADBLMP.DGO", - "./DGO/UND.DGO", - "./DGO/LYSKDCD.DGO", - "./DGO/HALFPIPE.DGO", - "./DGO/LSAMERGD.DGO", - "./DGO/PAS.DGO", - "./DGO/LBBUSH.DGO", - "./DGO/LPACKAGE.DGO", - "./DGO/LINTCSTB.DGO", - "./DGO/LPORTRUN.DGO", - "./DGO/LASHGRD.DGO", - "./DGO/CGB.DGO", - "./DGO/D3B.DGO", - "./DGO/STB.DGO", - "./DGO/GARAGE.DGO", - "./DGO/PORTWALL.DGO", - "./DGO/LHELLDOG.DGO", - "./DGO/SWE.DGO", - "./DGO/LRACECB.DGO", - "./DGO/GGA.DGO", - "./DGO/TOD.DGO", - "./DGO/MCN.DGO", - "./DGO/SEW.DGO", - "./DGO/VIN.DGO", - "./DGO/CGA.DGO", - "./DGO/CMB.DGO", - "./DGO/LGUARD.DGO", - "./DGO/CPA.DGO", - "./DGO/LCITYLOW.DGO", - "./DGO/LTENTOUT.DGO", - "./DGO/UNB.DGO", - "./DGO/CPO.DGO", - "./DGO/CAP.DGO", - "./DGO/CWI.DGO", - "./DGO/CTYKORA.DGO", - "./DGO/RUI.DGO", - "./DGO/LSACK.DGO", - "./DGO/CTYASHA.DGO", - "./DGO/LPRTRACE.DGO", - "./DGO/LWIDEA.DGO", - "./DGO/HIPHOG.DGO", - "./DGO/LSMYSBRT.DGO", - "./DGO/LRACEBB.DGO", - "./DGO/CASCITY.DGO", - "./DGO/LYSAMSAM.DGO", - "./DGO/VI1.DGO" + "CGO/ART.CGO", + "CGO/KERNEL.CGO", + "CGO/ENGINE.CGO", + "CGO/GAME.CGO", + "CGO/COMMON.CGO", + "DGO/LWIDEB.DGO", + "DGO/LMEETBRT.DGO", + "DGO/CTA.DGO", + "DGO/PALOUT.DGO", + "DGO/STD.DGO", + "DGO/FOR.DGO", + "DGO/CASEXT.DGO", + "DGO/HIDEOUT.DGO", + "DGO/LWIDESTA.DGO", + "DGO/LRACELIT.DGO", + "DGO/CTB.DGO", + "DGO/KIOSK.DGO", + "DGO/DG1.DGO", + "DGO/FEB.DGO", + "DGO/DMI.DGO", + "DGO/ORACLE.DGO", + "DGO/LERLTESS.DGO", + "DGO/DRI.DGO", + "DGO/LBRNERMK.DGO", + "DGO/LRACECF.DGO", + "DGO/CTC.DGO", + "DGO/LTHRNOUT.DGO", + "DGO/FRA.DGO", + "DGO/LGARCSTA.DGO", + "DGO/MTN.DGO", + "DGO/INTROCST.DGO", + "DGO/DRB.DGO", + "DGO/ATE.DGO", + "DGO/LERROL.DGO", + "DGO/LTRNYSAM.DGO", + "DGO/LOUTCSTB.DGO", + "DGO/LASHTHRN.DGO", + "DGO/TOC.DGO", + "DGO/CFB.DGO", + "DGO/CAB.DGO", + "DGO/STC.DGO", + "DGO/STR.DGO", + "DGO/ATO.DGO", + "DGO/SEB.DGO", + "DGO/LPRSNCST.DGO", + "DGO/SWB.DGO", + "DGO/LPOWER.DGO", + "DGO/FOB.DGO", + "DGO/CIB.DGO", + "DGO/LSHUTTLE.DGO", + "DGO/LJAKDAX.DGO", + "DGO/FORDUMPC.DGO", + "DGO/LTRNTESS.DGO", + "DGO/TBO.DGO", + "DGO/THR.DGO", + "DGO/PRI.DGO", + "DGO/LKIDDOGE.DGO", + "DGO/NESTT.DGO", + "DGO/LWIDEC.DGO", + "DGO/SAG.DGO", + "DGO/NEB.DGO", + "DGO/COB.DGO", + "DGO/LBOMBBOT.DGO", + "DGO/DEMO.DGO", + "DGO/LRACEDF.DGO", + "DGO/LERLCHAL.DGO", + "DGO/LHIPOUT.DGO", + "DGO/OUTROCST.DGO", + "DGO/NES.DGO", + "DGO/PAR.DGO", + "DGO/LERBRNGD.DGO", + "DGO/MTX.DGO", + "DGO/FDA.DGO", + "DGO/LKEIRIFT.DGO", + "DGO/LWHACK.DGO", + "DGO/LJKDXASH.DGO", + "DGO/CAS.DGO", + "DGO/COA.DGO", + "DGO/LTESS.DGO", + "DGO/CFA.DGO", + "DGO/TOMBEXT.DGO", + "DGO/LCGUARD.DGO", + "DGO/TOE.DGO", + "DGO/PALBOSS.DGO", + "DGO/FRB.DGO", + "DGO/PAE.DGO", + "DGO/TITLE.DGO", + "DGO/FORDUMPD.DGO", + "DGO/D3A.DGO", + "DGO/DRILLMTN.DGO", + "DGO/PAC.DGO", + "DGO/LTENTOB.DGO", + "DGO/LRACEBF.DGO", + "DGO/LPROTECT.DGO", + "DGO/FEA.DGO", + "DGO/ONINTENT.DGO", + "DGO/STA.DGO", + "DGO/CGC.DGO", + "DGO/CMA.DGO", + "DGO/FDB.DGO", + "DGO/SKA.DGO", + "DGO/LTRNKRKD.DGO", + "DGO/CIA.DGO", + "DGO/TOB.DGO", + "DGO/LRACEDB.DGO", + "DGO/LDJAKBRN.DGO", + "DGO/TOA.DGO", + "DGO/STADBLMP.DGO", + "DGO/UND.DGO", + "DGO/LYSKDCD.DGO", + "DGO/HALFPIPE.DGO", + "DGO/LSAMERGD.DGO", + "DGO/PAS.DGO", + "DGO/LBBUSH.DGO", + "DGO/LPACKAGE.DGO", + "DGO/LINTCSTB.DGO", + "DGO/LPORTRUN.DGO", + "DGO/LASHGRD.DGO", + "DGO/CGB.DGO", + "DGO/D3B.DGO", + "DGO/STB.DGO", + "DGO/GARAGE.DGO", + "DGO/PORTWALL.DGO", + "DGO/LHELLDOG.DGO", + "DGO/SWE.DGO", + "DGO/LRACECB.DGO", + "DGO/GGA.DGO", + "DGO/TOD.DGO", + "DGO/MCN.DGO", + "DGO/SEW.DGO", + "DGO/VIN.DGO", + "DGO/CGA.DGO", + "DGO/CMB.DGO", + "DGO/LGUARD.DGO", + "DGO/CPA.DGO", + "DGO/LCITYLOW.DGO", + "DGO/LTENTOUT.DGO", + "DGO/UNB.DGO", + "DGO/CPO.DGO", + "DGO/CAP.DGO", + "DGO/CWI.DGO", + "DGO/CTYKORA.DGO", + "DGO/RUI.DGO", + "DGO/LSACK.DGO", + "DGO/CTYASHA.DGO", + "DGO/LPRTRACE.DGO", + "DGO/LWIDEA.DGO", + "DGO/HIPHOG.DGO", + "DGO/LSMYSBRT.DGO", + "DGO/LRACEBB.DGO", + "DGO/CASCITY.DGO", + "DGO/LYSAMSAM.DGO", + "DGO/VI1.DGO" ], // some objects are part of STR files (streaming data). diff --git a/decompiler/config/jak2_ntsc_v1.jsonc b/decompiler/config/jak2_ntsc_v1.jsonc index b560ef7aea..a1d2f121bc 100644 --- a/decompiler/config/jak2_ntsc_v1.jsonc +++ b/decompiler/config/jak2_ntsc_v1.jsonc @@ -68,6 +68,13 @@ // set to true for PAL versions. this will forcefully skip files that have some data missing at the end. "is_pal": false, + "generate_all_types": true, + "write_patches": false, + "apply_patches": false, + "object_patches": [], + // jak 1's all-types, used to generate "hints" + "old_all_types_file": "decompiler/config/all-types.gc", + //////////////////////////// // CONFIG FILES //////////////////////////// diff --git a/decompiler/main.cpp b/decompiler/main.cpp index 1cddd23820..cf4e02d69f 100644 --- a/decompiler/main.cpp +++ b/decompiler/main.cpp @@ -174,6 +174,13 @@ int main(int argc, char** argv) { db.analyze_functions_ir2(out_folder, config, {}); } + if (config.generate_all_types) { + ASSERT_MSG(config.decompile_code, "Must decompile code to generate all-types"); + db.ir2_analyze_all_types(file_util::combine_path(out_folder, "new-all-types.gc"), + config.old_all_types_file, + config.hacks.types_with_bad_inspect_methods); + } + fmt::print("[Mem] After decomp: {} MB\n", get_peak_rss() / (1024 * 1024)); // write out all symbols diff --git a/decompiler/util/DecompilerTypeSystem.cpp b/decompiler/util/DecompilerTypeSystem.cpp index 75c21609c4..23e766bf7f 100644 --- a/decompiler/util/DecompilerTypeSystem.cpp +++ b/decompiler/util/DecompilerTypeSystem.cpp @@ -403,8 +403,8 @@ int DecompilerTypeSystem::get_format_arg_count(const std::string& str) const { } static const std::vector single_char_ignore_list = {'%', 'T'}; - static const std::vector multi_char_ignore_list = {"0L", "1L", "3L", "1K", - "2j", "0k", "30L"}; + static const std::vector multi_char_ignore_list = {"0L", "1L", "3L", "1K", + "2j", "0k", "30L", "1T"}; int arg_count = 0; for (size_t i = 0; i < str.length(); i++) { diff --git a/scripts/shell/decomp2.sh b/scripts/shell/decomp2.sh new file mode 100755 index 0000000000..4761152dd3 --- /dev/null +++ b/scripts/shell/decomp2.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# Directory of this script +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +"${DIR}"/../../build/decompiler/decompiler "${DIR}"/../../decompiler/config/jak2_ntsc_v1.jsonc "${DIR}"/../../iso_data/ "${DIR}"/../../decompiler_out diff --git a/test/decompiler/FormRegressionTest.cpp b/test/decompiler/FormRegressionTest.cpp index 5f4d9a7484..8a695ece7a 100644 --- a/test/decompiler/FormRegressionTest.cpp +++ b/test/decompiler/FormRegressionTest.cpp @@ -128,7 +128,7 @@ std::unique_ptr FormRegressionTest::make_function( auto program = parser->parse_program(code, string_label_names); // create the test data collection - auto test = std::make_unique(program.instructions.size()); + auto test = std::make_unique(program.instructions.size(), settings.version); // populate the LinkedObjectFile test->file.words_by_seg.resize(3); test->file.labels = program.labels; @@ -160,7 +160,7 @@ std::unique_ptr FormRegressionTest::make_function( // analyze function prologue/epilogue test->func.analyze_prologue(test->file); // build control flow graph - test->func.cfg = build_cfg(test->file, 0, test->func, {}, {}); + test->func.cfg = build_cfg(test->file, 0, test->func, {}, {}, settings.version); EXPECT_TRUE(test->func.cfg->is_fully_resolved()); if (!test->func.cfg->is_fully_resolved()) { fmt::print("CFG:\n{}\n", test->func.cfg->to_dot()); @@ -176,7 +176,7 @@ std::unique_ptr FormRegressionTest::make_function( // convert instruction to atomic ops DecompWarnings warnings; auto ops = convert_function_to_atomic_ops(test->func, program.labels, warnings, false, {}, - GameVersion::Jak1); + settings.version); test->func.ir2.atomic_ops = std::make_shared(std::move(ops)); test->func.ir2.atomic_ops_succeeded = true; test->func.ir2.env.set_end_var(test->func.ir2.atomic_ops->end_op().return_var()); @@ -280,7 +280,7 @@ void FormRegressionTest::test(const std::string& code, EXPECT_TRUE(expected_form == actual_form); } -void FormRegressionTest::test_final_function( +void FormRegressionTest::test_final_function_jak1( const std::string& code, const std::string& type, const std::string& expected, @@ -311,12 +311,12 @@ void FormRegressionTest::test_final_function( EXPECT_TRUE(expected_form == actual_form); } -void FormRegressionTest::test_with_stack_structures(const std::string& code, - const std::string& type, - const std::string& expected, - const std::string& stack_map_json, - const std::string& cast_json, - const std::string& var_map_json) { +void FormRegressionTest::test_with_stack_structures_jak1(const std::string& code, + const std::string& type, + const std::string& expected, + const std::string& stack_map_json, + const std::string& cast_json, + const std::string& var_map_json) { TestSettings settings; settings.do_expressions = true; settings.stack_structure_json = stack_map_json; diff --git a/test/decompiler/FormRegressionTest.h b/test/decompiler/FormRegressionTest.h index 1690b41465..28f07a79c0 100644 --- a/test/decompiler/FormRegressionTest.h +++ b/test/decompiler/FormRegressionTest.h @@ -20,6 +20,7 @@ struct TestSettings { std::string casts_json; std::string var_map_json; std::string stack_structure_json; + GameVersion version = GameVersion::Jak1; }; class FormRegressionTest : public ::testing::Test { @@ -31,7 +32,7 @@ class FormRegressionTest : public ::testing::Test { static void TearDownTestCase(); struct TestData { - explicit TestData(int instrs) : func(0, instrs) {} + explicit TestData(int instrs, GameVersion version) : func(0, instrs, version) {} decompiler::Function func; decompiler::LinkedObjectFile file; @@ -41,28 +42,28 @@ class FormRegressionTest : public ::testing::Test { std::unique_ptr make_function(const std::string& code, const TypeSpec& function_type, const TestSettings& settings); - void test(const std::string& code, const std::string& type, const std::string& expected, const TestSettings& settings); - void test_final_function(const std::string& code, - const std::string& type, - const std::string& expected, - bool allow_pairs = false, - const std::vector>& strings = {}, - const std::string& cast_json = "", - const std::string& var_map_json = ""); + void test_final_function_jak1( + const std::string& code, + const std::string& type, + const std::string& expected, + bool allow_pairs = false, + const std::vector>& strings = {}, + const std::string& cast_json = "", + const std::string& var_map_json = ""); - void test_no_expr(const std::string& code, - const std::string& type, - const std::string& expected, - bool allow_pairs = false, - const std::string& method_name = "", - const std::vector>& strings = {}, - const std::string& cast_json = "", - const std::string& var_map_json = "") { + void test_no_expr_jak1(const std::string& code, + const std::string& type, + const std::string& expected, + bool allow_pairs = false, + const std::string& method_name = "", + const std::vector>& strings = {}, + const std::string& cast_json = "", + const std::string& var_map_json = "") { TestSettings settings; settings.allow_pairs = allow_pairs; settings.method_name = method_name; @@ -73,14 +74,14 @@ class FormRegressionTest : public ::testing::Test { test(code, type, expected, settings); } - void test_with_expr(const std::string& code, - const std::string& type, - const std::string& expected, - bool allow_pairs = false, - const std::string& method_name = "", - const std::vector>& strings = {}, - const std::string& cast_json = "", - const std::string& var_map_json = "") { + void test_with_expr_jak1(const std::string& code, + const std::string& type, + const std::string& expected, + bool allow_pairs = false, + const std::string& method_name = "", + const std::vector>& strings = {}, + const std::string& cast_json = "", + const std::string& var_map_json = "") { TestSettings settings; settings.allow_pairs = allow_pairs; settings.method_name = method_name; @@ -91,10 +92,10 @@ class FormRegressionTest : public ::testing::Test { test(code, type, expected, settings); } - void test_with_stack_structures(const std::string& code, - const std::string& type, - const std::string& expected, - const std::string& stack_map_json, - const std::string& cast_json = "", - const std::string& var_map_json = ""); + void test_with_stack_structures_jak1(const std::string& code, + const std::string& type, + const std::string& expected, + const std::string& stack_map_json, + const std::string& cast_json = "", + const std::string& var_map_json = ""); }; \ No newline at end of file diff --git a/test/decompiler/test_DisasmVifDecompile.cpp b/test/decompiler/test_DisasmVifDecompile.cpp index f7f1371b29..d375f82854 100644 --- a/test/decompiler/test_DisasmVifDecompile.cpp +++ b/test/decompiler/test_DisasmVifDecompile.cpp @@ -681,17 +681,17 @@ TEST_F(FormRegressionTest, ExprDisasmVif) { " )\n" " (- gp-0 (* arg1 4))\n" " )"; - test_with_expr(func, type, expected, false, "", - {{"L139", " #x~X:"}, - {"L138", " (~s :irq ~D)~%"}, - {"L137", " (~s :irq ~D :~s #x~X)~%"}, - {"L136", " (~s :irq ~D :wl ~D :cl ~D)~%"}, - {"L135", " (~s :irq ~D :~s "}, - {"L134", "#x~X #x~X #x~X #x~X)~%"}, - {"L133", " (~s :irq ~D :instructions #x~D :addr #x~X)~%"}, - {"L132", " (~s :irq ~D :qwc #x~D)~%"}, - {"L145", " #x~X: #x~8x #x~8x #x~8x #x~8x~%"}, - {"L131", " (~s :irq ~D :num ~D :addr #x~X "}, - {"L130", ":msk ~D :flg ~D :usn ~D [skip ~d])~%"}, - {"L129", " (*unknown* vif-tag #x~X)~%"}}); + test_with_expr_jak1(func, type, expected, false, "", + {{"L139", " #x~X:"}, + {"L138", " (~s :irq ~D)~%"}, + {"L137", " (~s :irq ~D :~s #x~X)~%"}, + {"L136", " (~s :irq ~D :wl ~D :cl ~D)~%"}, + {"L135", " (~s :irq ~D :~s "}, + {"L134", "#x~X #x~X #x~X #x~X)~%"}, + {"L133", " (~s :irq ~D :instructions #x~D :addr #x~X)~%"}, + {"L132", " (~s :irq ~D :qwc #x~D)~%"}, + {"L145", " #x~X: #x~8x #x~8x #x~8x #x~8x~%"}, + {"L131", " (~s :irq ~D :num ~D :addr #x~X "}, + {"L130", ":msk ~D :flg ~D :usn ~D [skip ~d])~%"}, + {"L129", " (*unknown* vif-tag #x~X)~%"}}); } \ No newline at end of file diff --git a/test/decompiler/test_FormBeforeExpressions.cpp b/test/decompiler/test_FormBeforeExpressions.cpp index 46f5bc0227..0ad4b69fcb 100644 --- a/test/decompiler/test_FormBeforeExpressions.cpp +++ b/test/decompiler/test_FormBeforeExpressions.cpp @@ -28,7 +28,7 @@ TEST_F(FormRegressionTest, SimplestTest) { " daddu sp, sp, r0"; std::string type = "(function object object)"; std::string expected = "(begin (set! v0-0 a0-0) (ret-value v0-0))"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, Op3) { @@ -40,7 +40,7 @@ TEST_F(FormRegressionTest, Op3) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(begin (set! v0-0 (*.si a0-0 a1-0)) (ret-value v0-0))"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, Division) { @@ -53,7 +53,7 @@ TEST_F(FormRegressionTest, Division) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(begin (set! v0-0 (/.si a0-0 a1-0)) (ret-value v0-0))"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, Ash) { @@ -73,7 +73,7 @@ TEST_F(FormRegressionTest, Ash) { " sll r0, r0, 0"; std::string type = "(function int int int)"; std::string expected = "(begin (set! v1-0 a0-0) (set! v0-0 (ash.si v1-0 a1-0)) (ret-value v0-0))"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, Abs) { @@ -89,7 +89,7 @@ TEST_F(FormRegressionTest, Abs) { " daddu sp, sp, r0"; std::string type = "(function int int)"; std::string expected = "(begin (set! v0-0 a0-0) (set! v0-0 (abs v0-0)) (ret-value v0-0))"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, Min) { @@ -109,7 +109,7 @@ TEST_F(FormRegressionTest, Min) { " (set! v0-1 (min.si v0-0 v1-0))\n" " (ret-value v0-1)\n" " )"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, Max) { @@ -130,7 +130,7 @@ TEST_F(FormRegressionTest, Max) { " (set! v0-1 (max.si v0-0 v1-0))\n" " (ret-value v0-1)\n" " )"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, FormatString) { @@ -169,7 +169,7 @@ TEST_F(FormRegressionTest, FormatString) { " (set! v0-1 a0-0)\n" " (ret-value v0-1)\n" " )"; - test_no_expr(func, type, expected, false, "", {{"L343", "~f"}}); + test_no_expr_jak1(func, type, expected, false, "", {{"L343", "~f"}}); } TEST_F(FormRegressionTest, WhileLoop) { @@ -212,7 +212,7 @@ TEST_F(FormRegressionTest, WhileLoop) { " (set! v0-0 #f)\n" " (ret-value v0-0)\n" " )"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } // Note - this test looks weird because or's aren't fully processed at this point. @@ -278,7 +278,7 @@ TEST_F(FormRegressionTest, Or) { " (set! v0-0 #f)\n" " (ret-value v0-0)\n" " )"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, DynamicMethodAccess) { @@ -355,7 +355,7 @@ TEST_F(FormRegressionTest, DynamicMethodAccess) { " )\n" " (ret-value v0-0)\n" " )"; - test_no_expr(func, type, expected); + test_no_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, SimpleLoopMergeCheck) { @@ -397,7 +397,7 @@ TEST_F(FormRegressionTest, SimpleLoopMergeCheck) { " (set! v0-0 (car a0-0))\n" " (ret-value v0-0)\n" " )"; - test_no_expr(func, type, expected, true); + test_no_expr_jak1(func, type, expected, true); } TEST_F(FormRegressionTest, And) { @@ -467,7 +467,7 @@ TEST_F(FormRegressionTest, And) { " )\n" " )" "(ret-value v0-0))\n"; - test_no_expr(func, type, expected, true); + test_no_expr_jak1(func, type, expected, true); } TEST_F(FormRegressionTest, FunctionCall) { @@ -548,7 +548,7 @@ TEST_F(FormRegressionTest, FunctionCall) { " (set! v0-1 a1-0)\n" // not empty, so return the result " )" // the (set! v0 #f) from the if is added later. " (ret-value v0-1))\n"; - test_no_expr(func, type, expected, true); + test_no_expr_jak1(func, type, expected, true); } TEST_F(FormRegressionTest, NestedAndOr) { @@ -715,7 +715,7 @@ TEST_F(FormRegressionTest, NestedAndOr) { " (set! v0-1 a0-0)\n" " (ret-value v0-1)\n" " )"; - test_no_expr(func, type, expected, true); + test_no_expr_jak1(func, type, expected, true); } TEST_F(FormRegressionTest, NewMethod) { @@ -770,7 +770,7 @@ TEST_F(FormRegressionTest, NewMethod) { " (set! (-> v0-0 allocated-length) a2-0)\n" " )" " (ret-value v0-0))\n"; - test_no_expr(func, type, expected, false, "inline-array-class"); + test_no_expr_jak1(func, type, expected, false, "inline-array-class"); } TEST_F(FormRegressionTest, Recursive) { @@ -815,7 +815,7 @@ TEST_F(FormRegressionTest, Recursive) { " )\n" " )" " (ret-value v0-0))\n"; - test_no_expr(func, type, expected, false); + test_no_expr_jak1(func, type, expected, false); } TEST_F(FormRegressionTest, TypeOf) { @@ -851,5 +851,5 @@ TEST_F(FormRegressionTest, TypeOf) { " (set! v0-0 (call! a0-0))\n" " (ret-value v0-0)\n" " )"; - test_no_expr(func, type, expected, false); + test_no_expr_jak1(func, type, expected, false); } diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp index af322a0664..13b404dd5f 100644 --- a/test/decompiler/test_FormExpressionBuild.cpp +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -12,7 +12,7 @@ TEST_F(FormRegressionTest, ExprIdentity) { " daddu sp, sp, r0"; std::string type = "(function object object)"; std::string expected = "arg0"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprFloatingPoint) { @@ -31,7 +31,7 @@ TEST_F(FormRegressionTest, ExprFloatingPoint) { " daddiu sp, sp, 16"; std::string type = "(function float float)"; std::string expected = "(/ 0.0 arg0)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionSigned) { @@ -42,7 +42,7 @@ TEST_F(FormRegressionTest, ExprAdditionSigned) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(+ arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionUnSigned) { @@ -53,7 +53,7 @@ TEST_F(FormRegressionTest, ExprAdditionUnSigned) { " daddu sp, sp, r0"; std::string type = "(function uint uint uint)"; std::string expected = "(+ arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionMixed1) { @@ -64,7 +64,7 @@ TEST_F(FormRegressionTest, ExprAdditionMixed1) { " daddu sp, sp, r0"; std::string type = "(function int uint int)"; std::string expected = "(+ arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionMixed2) { @@ -75,7 +75,7 @@ TEST_F(FormRegressionTest, ExprAdditionMixed2) { " daddu sp, sp, r0"; std::string type = "(function uint int uint)"; std::string expected = "(+ arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionSignedWrongReturn) { @@ -86,7 +86,7 @@ TEST_F(FormRegressionTest, ExprAdditionSignedWrongReturn) { " daddu sp, sp, r0"; std::string type = "(function int int uint)"; std::string expected = "(the-as uint (+ arg0 arg1))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionUnSignedWrongReturn) { @@ -97,7 +97,7 @@ TEST_F(FormRegressionTest, ExprAdditionUnSignedWrongReturn) { " daddu sp, sp, r0"; std::string type = "(function uint uint int)"; std::string expected = "(the-as int (+ arg0 arg1))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionMixed1WrongReturn) { @@ -108,7 +108,7 @@ TEST_F(FormRegressionTest, ExprAdditionMixed1WrongReturn) { " daddu sp, sp, r0"; std::string type = "(function int uint uint)"; std::string expected = "(the-as uint (+ arg0 arg1))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAdditionMixed2WrongReturn) { @@ -119,7 +119,7 @@ TEST_F(FormRegressionTest, ExprAdditionMixed2WrongReturn) { " daddu sp, sp, r0"; std::string type = "(function uint int int)"; std::string expected = "(the-as int (+ arg0 arg1))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprSubtraction) { @@ -130,7 +130,7 @@ TEST_F(FormRegressionTest, ExprSubtraction) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(- arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMultiplication) { @@ -141,7 +141,7 @@ TEST_F(FormRegressionTest, ExprMultiplication) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(* arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMultiplicationWrong1) { @@ -152,7 +152,7 @@ TEST_F(FormRegressionTest, ExprMultiplicationWrong1) { " daddu sp, sp, r0"; std::string type = "(function int uint int)"; std::string expected = "(* arg0 (the-as int arg1))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMultiplicationWrong2) { @@ -163,7 +163,7 @@ TEST_F(FormRegressionTest, ExprMultiplicationWrong2) { " daddu sp, sp, r0"; std::string type = "(function uint int int)"; std::string expected = "(* (the-as int arg0) arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMultiplicationWrong3) { @@ -174,7 +174,7 @@ TEST_F(FormRegressionTest, ExprMultiplicationWrong3) { " daddu sp, sp, r0"; std::string type = "(function uint uint uint)"; std::string expected = "(the-as uint (* (the-as int arg0) (the-as int arg1)))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprDivision1) { @@ -186,7 +186,7 @@ TEST_F(FormRegressionTest, ExprDivision1) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(/ arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprDivision2) { @@ -198,7 +198,7 @@ TEST_F(FormRegressionTest, ExprDivision2) { " daddu sp, sp, r0"; std::string type = "(function uint int int)"; std::string expected = "(/ (the-as int arg0) arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprDivision3) { @@ -210,7 +210,7 @@ TEST_F(FormRegressionTest, ExprDivision3) { " daddu sp, sp, r0"; std::string type = "(function int uint int)"; std::string expected = "(/ arg0 (the-as int arg1))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprDivision4) { @@ -222,7 +222,7 @@ TEST_F(FormRegressionTest, ExprDivision4) { " daddu sp, sp, r0"; std::string type = "(function uint uint uint)"; std::string expected = "(the-as uint (/ (the-as int arg0) (the-as int arg1)))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAsh) { @@ -240,7 +240,7 @@ TEST_F(FormRegressionTest, ExprAsh) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(ash arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMod) { @@ -252,7 +252,7 @@ TEST_F(FormRegressionTest, ExprMod) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(mod arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprAbs) { @@ -268,7 +268,7 @@ TEST_F(FormRegressionTest, ExprAbs) { " daddu sp, sp, r0"; std::string type = "(function int int)"; std::string expected = "(abs arg0)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMin) { @@ -282,7 +282,7 @@ TEST_F(FormRegressionTest, ExprMin) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(min arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMax) { @@ -296,7 +296,7 @@ TEST_F(FormRegressionTest, ExprMax) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(max arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprLogior) { @@ -307,7 +307,7 @@ TEST_F(FormRegressionTest, ExprLogior) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(logior arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprLogxor) { @@ -318,7 +318,7 @@ TEST_F(FormRegressionTest, ExprLogxor) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(logxor arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprLognor) { @@ -329,7 +329,7 @@ TEST_F(FormRegressionTest, ExprLognor) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(lognor arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprLogand) { @@ -340,7 +340,7 @@ TEST_F(FormRegressionTest, ExprLogand) { " daddu sp, sp, r0"; std::string type = "(function int int int)"; std::string expected = "(logand arg0 arg1)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprLognot) { @@ -351,7 +351,7 @@ TEST_F(FormRegressionTest, ExprLognot) { " daddu sp, sp, r0"; std::string type = "(function int int)"; std::string expected = "(lognot arg0)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprFalse) { @@ -362,7 +362,7 @@ TEST_F(FormRegressionTest, ExprFalse) { " daddu sp, sp, r0"; std::string type = "(function symbol)"; std::string expected = "#f"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprTrue) { @@ -373,7 +373,7 @@ TEST_F(FormRegressionTest, ExprTrue) { " daddu sp, sp, r0"; std::string type = "(function symbol)"; std::string expected = "#t"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprPrintBfloat) { @@ -403,7 +403,7 @@ TEST_F(FormRegressionTest, ExprPrintBfloat) { std::string type = "(function bfloat bfloat)"; std::string expected = "(begin (format #t \"~f\" (-> arg0 data)) arg0)"; - test_with_expr(func, type, expected, false, "", {{"L343", "~f"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L343", "~f"}}); } TEST_F(FormRegressionTest, ExprSizeOfType) { @@ -425,7 +425,7 @@ TEST_F(FormRegressionTest, ExprSizeOfType) { std::string type = "(function type uint)"; std::string expected = "(logand 3 (+ (* (-> arg0 allocated-length) 4) 43))"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, ExprBasicTypeP) { @@ -468,7 +468,7 @@ TEST_F(FormRegressionTest, ExprBasicTypeP) { " )\n" " #f\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, FinalBasicTypeP) { @@ -511,7 +511,7 @@ TEST_F(FormRegressionTest, FinalBasicTypeP) { " )\n" " #f\n" " )"; - test_final_function(func, type, expected); + test_final_function_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprTypeTypep) { @@ -565,7 +565,7 @@ TEST_F(FormRegressionTest, ExprTypeTypep) { " )\n" " #f\n" " )"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, ExprFindParentMethod) { @@ -629,7 +629,7 @@ TEST_F(FormRegressionTest, ExprFindParentMethod) { " )\n" " v0-0\n" " )"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, ExprRef) { @@ -660,7 +660,7 @@ TEST_F(FormRegressionTest, ExprRef) { std::string expected = "(begin (dotimes (v1-0 arg1) (nop!) (nop!) (set! arg0 (cdr arg0))) (car arg0))"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprPairMethod4) { @@ -728,7 +728,7 @@ TEST_F(FormRegressionTest, ExprPairMethod4) { " )\n" " v0-0\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprPairMethod5) { @@ -741,7 +741,7 @@ TEST_F(FormRegressionTest, ExprPairMethod5) { std::string type = "(function pair uint)"; std::string expected = "(-> pair size)"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, ExprLast) { @@ -774,7 +774,7 @@ TEST_F(FormRegressionTest, ExprLast) { " (while (not (null? (cdr v0-0))) (nop!) (nop!) (set! v0-0 (cdr v0-0)))\n" " v0-0\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprMember) { @@ -826,7 +826,7 @@ TEST_F(FormRegressionTest, ExprMember) { " )\n" " (if (not (null? v1-0)) v1-0)\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprNmember) { @@ -888,7 +888,7 @@ TEST_F(FormRegressionTest, ExprNmember) { " )\n" " (if (not (null? arg1)) arg1)\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprAssoc) { @@ -939,7 +939,7 @@ TEST_F(FormRegressionTest, ExprAssoc) { " )\n" " (if (not (null? v1-0)) (car v1-0))\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprAssoce) { @@ -1007,7 +1007,7 @@ TEST_F(FormRegressionTest, ExprAssoce) { " )\n" " (if (not (null? v1-0)) (car v1-0))\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprNassoc) { @@ -1098,7 +1098,7 @@ TEST_F(FormRegressionTest, ExprNassoc) { " )\n" " (if (not (null? arg1)) (car arg1))\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprNassoce) { @@ -1203,7 +1203,7 @@ TEST_F(FormRegressionTest, ExprNassoce) { " )\n" " (if (not (null? arg1)) (car arg1))\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprAppend) { @@ -1262,7 +1262,7 @@ TEST_F(FormRegressionTest, ExprAppend) { " arg0\n" " )\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprDelete) { @@ -1339,7 +1339,7 @@ TEST_F(FormRegressionTest, ExprDelete) { " )\n" " )\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprDeleteCar) { @@ -1418,7 +1418,7 @@ TEST_F(FormRegressionTest, ExprDeleteCar) { " )\n" " )\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprInsertCons) { @@ -1451,7 +1451,7 @@ TEST_F(FormRegressionTest, ExprInsertCons) { // NOTE - this appears to _not_ be a nested call. std::string expected = "(let ((a3-0 (delete-car! (car arg0) arg1))) (cons arg0 a3-0))"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprSort) { @@ -1587,7 +1587,7 @@ TEST_F(FormRegressionTest, ExprSort) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected, true, ""); + test_with_expr_jak1(func, type, expected, true, ""); } TEST_F(FormRegressionTest, ExprInlineArrayMethod0) { @@ -1639,7 +1639,7 @@ TEST_F(FormRegressionTest, ExprInlineArrayMethod0) { " )\n" " v0-0\n" " )"; - test_with_expr(func, type, expected, true, "inline-array-class"); + test_with_expr_jak1(func, type, expected, true, "inline-array-class"); } TEST_F(FormRegressionTest, ExprInlineArrayMethod4) { @@ -1651,7 +1651,7 @@ TEST_F(FormRegressionTest, ExprInlineArrayMethod4) { std::string type = "(function inline-array-class int)"; std::string expected = "(-> arg0 length)"; - test_with_expr(func, type, expected, true, "inline-array-class"); + test_with_expr_jak1(func, type, expected, true, "inline-array-class"); } TEST_F(FormRegressionTest, ExprInlineArrayMethod5) { @@ -1676,7 +1676,7 @@ TEST_F(FormRegressionTest, ExprInlineArrayMethod5) { " (* (-> arg0 allocated-length) (the-as int (-> arg0 type heap-base)))\n" " )\n" " )"; - test_with_expr(func, type, expected, true, "inline-array-class"); + test_with_expr_jak1(func, type, expected, true, "inline-array-class"); } TEST_F(FormRegressionTest, ExprArrayMethod0) { @@ -1758,7 +1758,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod0) { " (set! (-> v0-1 content-type) arg2)\n" " v0-1\n" " )"; - test_with_expr(func, type, expected, true, "array"); + test_with_expr_jak1(func, type, expected, true, "array"); } TEST_F(FormRegressionTest, ExprArrayMethod4) { @@ -1771,7 +1771,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod4) { std::string type = "(function array int)"; std::string expected = "(-> arg0 length)"; - test_with_expr(func, type, expected, true, "array"); + test_with_expr_jak1(func, type, expected, true, "array"); } TEST_F(FormRegressionTest, ExprArrayMethod5) { @@ -1826,7 +1826,7 @@ TEST_F(FormRegressionTest, ExprArrayMethod5) { " )\n" " )\n" " )"; - test_with_expr(func, type, expected, true, "array"); + test_with_expr_jak1(func, type, expected, true, "array"); } TEST_F(FormRegressionTest, ExprMemCopy) { @@ -1866,7 +1866,7 @@ TEST_F(FormRegressionTest, ExprMemCopy) { " )\n" " v0-0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMemSet32) { @@ -1905,7 +1905,7 @@ TEST_F(FormRegressionTest, ExprMemSet32) { " )\n" " v0-0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMemOr) { @@ -1948,7 +1948,7 @@ TEST_F(FormRegressionTest, ExprMemOr) { " )\n" " v0-0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprFact) { @@ -1982,7 +1982,7 @@ TEST_F(FormRegressionTest, ExprFact) { std::string type = "(function int int)"; std::string expected = "(if (= arg0 1) 1 (* arg0 (fact (+ arg0 -1))))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprPrint) { @@ -2010,7 +2010,7 @@ TEST_F(FormRegressionTest, ExprPrint) { std::string type = "(function object object)"; std::string expected = "((method-of-type (rtype-of arg0) print) arg0)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprPrintl) { @@ -2058,7 +2058,7 @@ TEST_F(FormRegressionTest, ExprPrintl) { " (format #t \"~%\")\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", {{"L324", "~%"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L324", "~%"}}); } TEST_F(FormRegressionTest, ExprInspect) { @@ -2086,7 +2086,7 @@ TEST_F(FormRegressionTest, ExprInspect) { std::string type = "(function object object)"; std::string expected = "((method-of-type (rtype-of arg0) inspect) arg0)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprPrintTreeBitmask) { @@ -2157,7 +2157,7 @@ TEST_F(FormRegressionTest, ExprPrintTreeBitmask) { " )\n" " #f\n" " )"; - test_with_expr(func, type, expected, false, "", {{"L323", " "}, {"L322", "| "}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L323", " "}, {"L322", "| "}}); } TEST_F(FormRegressionTest, ExprPrintName) { @@ -2278,9 +2278,9 @@ TEST_F(FormRegressionTest, ExprPrintName) { "(the-as int arg0))))))\n" " )\n" " )"; - test_with_expr(func, type, expected, false, "", {}, - "[\t\t[24, \"a1\", \"symbol\"],\n" - "\t\t[39, \"a0\", \"symbol\"]]"); + test_with_expr_jak1(func, type, expected, false, "", {}, + "[\t\t[24, \"a1\", \"symbol\"],\n" + "\t\t[39, \"a0\", \"symbol\"]]"); } TEST_F(FormRegressionTest, ExprProfileBarMethod9) { @@ -2296,7 +2296,7 @@ TEST_F(FormRegressionTest, ExprProfileBarMethod9) { std::string type = "(function profile-bar int uint)"; std::string expected = "(-> arg0 data (+ (-> arg0 profile-frame-count) -2) time-stamp)"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, ExprStopwatchElapsedSeconds) { @@ -2326,7 +2326,7 @@ TEST_F(FormRegressionTest, ExprStopwatchElapsedSeconds) { std::string type = "(function int float)"; std::string expected = "(let ((v1-0 (abs arg0))) (* 0.0 (the float v1-0)))"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, ExprCopyStringString) { @@ -2374,7 +2374,7 @@ TEST_F(FormRegressionTest, ExprCopyStringString) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, StringLt) { @@ -2479,7 +2479,7 @@ TEST_F(FormRegressionTest, StringLt) { " )\n" " #f\n" " )"; - test_with_expr(func, type, expected, false, ""); + test_with_expr_jak1(func, type, expected, false, ""); } TEST_F(FormRegressionTest, ExprAssert) { @@ -2510,7 +2510,7 @@ TEST_F(FormRegressionTest, ExprAssert) { std::string type = "(function symbol string int)"; std::string expected = "(begin (if (not arg0) (format #t \"A ~A\" arg1)) 0)"; - test_with_expr(func, type, expected, false, "", {{"L17", "A ~A"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L17", "A ~A"}}); } TEST_F(FormRegressionTest, ExprTerminal2) { @@ -2547,7 +2547,7 @@ TEST_F(FormRegressionTest, ExprTerminal2) { " ((f0-4 (sqrtf (/ (- (* 0.0 arg0) arg1) arg2))))\n" " (- f0-4 (+ arg1 (* arg2 (* f0-4 f0-4))))\n" " )"; - test_with_expr(func, type, expected, false, "", {{"L17", "A ~A"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L17", "A ~A"}}); } TEST_F(FormRegressionTest, MoveFalse) { @@ -2568,7 +2568,7 @@ TEST_F(FormRegressionTest, MoveFalse) { std::string type = "(function int symbol)"; std::string expected = "(logtest? (+ arg0 12) 1)"; - test_with_expr(func, type, expected, false, "", {{"L17", "A ~A"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L17", "A ~A"}}); } // Good for testing that in-place ops (+!) check the _variable_ is the same. @@ -2620,7 +2620,7 @@ TEST_F(FormRegressionTest, QMemCpy) { " )\n" " v0-0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, StripStripTrailingWhitespace) { @@ -2728,7 +2728,7 @@ TEST_F(FormRegressionTest, StripStripTrailingWhitespace) { " )\n" " #f\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } // Let bug (github #328) @@ -2782,7 +2782,7 @@ TEST_F(FormRegressionTest, TimeToGround) { " )\n" " (the-as float v0-0)\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } // Infinite loop bug (github #196) @@ -2815,7 +2815,7 @@ TEST_F(FormRegressionTest, LoopingCode) { " )\n" " (the-as symbol #f)\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, AbsAsSideEffect) { @@ -2869,7 +2869,7 @@ TEST_F(FormRegressionTest, AbsAsSideEffect) { " )\n" " )\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } // for github https://github.com/water111/jak-project/issues/332 @@ -2905,7 +2905,7 @@ TEST_F(FormRegressionTest, AshPropagation) { " (logior! (-> arg0 bytes (/ arg1 8)) (ash 1 (logand arg1 7)))\n" " 0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } // for github https://github.com/water111/jak-project/issues/332 @@ -2939,5 +2939,5 @@ TEST_F(FormRegressionTest, AshPropagation2) { "(let ((v1-2 (-> arg0 bytes (/ arg1 8))))\n" " (logtest? v1-2 (ash 1 (logand arg1 7)))\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } \ No newline at end of file diff --git a/test/decompiler/test_FormExpressionBuild2.cpp b/test/decompiler/test_FormExpressionBuild2.cpp index 05c332e2e2..3eb73d2bd5 100644 --- a/test/decompiler/test_FormExpressionBuild2.cpp +++ b/test/decompiler/test_FormExpressionBuild2.cpp @@ -50,10 +50,10 @@ TEST_F(FormRegressionTest, MatrixPMult) { " )\n" " arg0\n" " )"; - test_with_stack_structures(func, type, expected, - "[\n" - " [16, \"matrix\"]\n" - " ]"); + test_with_stack_structures_jak1(func, type, expected, + "[\n" + " [16, \"matrix\"]\n" + " ]"); } // TODO- this should also work without the cast, but be uglier. @@ -96,11 +96,11 @@ TEST_F(FormRegressionTest, VectorXQuaternionWithCast) { " )\n" " arg0\n" " )"; - test_with_stack_structures(func, type, expected, - "[\n" - " [16, \"matrix\"]\n" - " ]", - "[[10, \"v1\", \"(pointer uint128)\"]]"); + test_with_stack_structures_jak1(func, type, expected, + "[\n" + " [16, \"matrix\"]\n" + " ]", + "[[10, \"v1\", \"(pointer uint128)\"]]"); } TEST_F(FormRegressionTest, EliminateFloatDeadSet) { @@ -227,7 +227,7 @@ TEST_F(FormRegressionTest, EliminateFloatDeadSet) { " )\n" " )\n" " )"; - test_with_stack_structures(func, type, expected, "[]"); + test_with_stack_structures_jak1(func, type, expected, "[]"); } TEST_F(FormRegressionTest, IterateProcessTree) { @@ -319,7 +319,7 @@ TEST_F(FormRegressionTest, IterateProcessTree) { " )\n" " s4-0\n" " )"; - test_with_stack_structures(func, type, expected, "[]"); + test_with_stack_structures_jak1(func, type, expected, "[]"); } TEST_F(FormRegressionTest, InspectVifStatBitfield) { @@ -451,18 +451,18 @@ TEST_F(FormRegressionTest, InspectVifStatBitfield) { " (format #t \"~T ~D~%\" (-> arg0 fqc))\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", - {{"L37", "[~8x] ~A~%"}, - {"L36", "~T ~D~%"}, - {"L35", "~T ~D~%"}, - {"L34", "~T ~D~%"}, - {"L33", "~T ~D~%"}, - {"L32", "~T ~D~%"}, - {"L31", "~T ~D~%"}, - {"L30", "~T ~D~%"}, - {"L29", "~T ~D~%"}, - {"L28", "~T ~D~%"}, - {"L27", "~T ~D~%"}}); + test_with_expr_jak1(func, type, expected, false, "", + {{"L37", "[~8x] ~A~%"}, + {"L36", "~T ~D~%"}, + {"L35", "~T ~D~%"}, + {"L34", "~T ~D~%"}, + {"L33", "~T ~D~%"}, + {"L32", "~T ~D~%"}, + {"L31", "~T ~D~%"}, + {"L30", "~T ~D~%"}, + {"L29", "~T ~D~%"}, + {"L28", "~T ~D~%"}, + {"L27", "~T ~D~%"}}); } TEST_F(FormRegressionTest, InspectHandleBitfield) { @@ -512,8 +512,9 @@ TEST_F(FormRegressionTest, InspectHandleBitfield) { " (format #t \"~Tpid: ~D~%\" (-> arg0 pid))\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", - {{"L79", "[~8x] ~A~%"}, {"L32", "~Tprocess: #x~X~%"}, {"L31", "~Tpid: ~D~%"}}); + test_with_expr_jak1( + func, type, expected, false, "", + {{"L79", "[~8x] ~A~%"}, {"L32", "~Tprocess: #x~X~%"}, {"L31", "~Tpid: ~D~%"}}); } TEST_F(FormRegressionTest, InspectDmaTagBitfield) { @@ -598,16 +599,16 @@ TEST_F(FormRegressionTest, InspectDmaTagBitfield) { " (format #t \"~Ta: ~D~%\" (-> arg0 spr))\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", - { - {"L65", "[~8x] ~A~%"}, - {"L37", "~Ta: ~D~%"}, - {"L36", "~Ta: ~D~%"}, - {"L35", "~Ta: ~D~%"}, - {"L34", "~Ta: ~D~%"}, - {"L33", "~Ta: ~D~%"}, - {"L32", "~Ta: ~D~%"}, - }); + test_with_expr_jak1(func, type, expected, false, "", + { + {"L65", "[~8x] ~A~%"}, + {"L37", "~Ta: ~D~%"}, + {"L36", "~Ta: ~D~%"}, + {"L35", "~Ta: ~D~%"}, + {"L34", "~Ta: ~D~%"}, + {"L33", "~Ta: ~D~%"}, + {"L32", "~Ta: ~D~%"}, + }); } // Tests nonzero-check on bitfield @@ -661,7 +662,7 @@ TEST_F(FormRegressionTest, DmaSyncCrash) { " )\n" " 0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, DmaSend) { @@ -742,7 +743,7 @@ TEST_F(FormRegressionTest, DmaSend) { " (.sync.l)\n" " 0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, DmaInitialize) { @@ -776,9 +777,9 @@ TEST_F(FormRegressionTest, DmaInitialize) { " (set! (-> (the-as vif-bank #x10003c00) err me0) 1)\n" " 0\n" " )"; - test_with_expr(func, type, expected, false, "", {}, - "[[1, \"v1\", \"vif-bank\"], [8, \"v1\", \"vif-bank\"], [6, \"a0\", " - "\"vif-bank\"], [13, \"a0\", \"vif-bank\"]]"); + test_with_expr_jak1(func, type, expected, false, "", {}, + "[[1, \"v1\", \"vif-bank\"], [8, \"v1\", \"vif-bank\"], [6, \"a0\", " + "\"vif-bank\"], [13, \"a0\", \"vif-bank\"]]"); } // Dynamic bitfield stuff. @@ -859,7 +860,7 @@ TEST_F(FormRegressionTest, SetDisplayEnv) { " (set! (-> arg0 bgcolor) (new 'static 'gs-bgcolor))\n" " arg0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, DmaBufferAddVuFunction) { @@ -974,7 +975,7 @@ TEST_F(FormRegressionTest, DmaBufferAddVuFunction) { " )\n" " #f\n" " )"; - test_with_expr(func, type, expected, false, "", {}, "[[[9, 33], \"t2\", \"dma-packet\"]]"); + test_with_expr_jak1(func, type, expected, false, "", {}, "[[[9, 33], \"t2\", \"dma-packet\"]]"); } TEST_F(FormRegressionTest, DmaBucketInsertTag) { @@ -997,11 +998,11 @@ TEST_F(FormRegressionTest, DmaBucketInsertTag) { " )\n" " arg2\n" " )"; - test_with_expr(func, type, expected, false, "", {}, - "[\n" - " [[2, 6], \"v1\", \"dma-bucket\"],\n" - " [3, \"a0\", \"dma-bucket\"]\n" - " ]"); + test_with_expr_jak1(func, type, expected, false, "", {}, + "[\n" + " [[2, 6], \"v1\", \"dma-bucket\"],\n" + " [3, \"a0\", \"dma-bucket\"]\n" + " ]"); } TEST_F(FormRegressionTest, StupidFloatMove) { @@ -1109,7 +1110,7 @@ TEST_F(FormRegressionTest, StupidFloatMove) { " )\n" " 0.0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } // gpr->fpr not being propagated @@ -1128,7 +1129,7 @@ TEST_F(FormRegressionTest, Method11FontContext) { " (set! (-> arg0 origin z) (the float arg1))\n" " arg0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } // 128-bit bitfields, also type for pextuw @@ -1166,7 +1167,7 @@ TEST_F(FormRegressionTest, Method4ResTag) { " (* (-> arg0 elt-count) (-> arg0 elt-type size))\n" " )\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, MakeSqrtTable) { @@ -1240,7 +1241,7 @@ TEST_F(FormRegressionTest, MakeSqrtTable) { " 0\n" " (none)\n" " )"; - test_with_expr( + test_with_expr_jak1( func, type, expected, false, "", {{"L190", "static int sqrt_table[256] =~%{~%"}, {"L189", "~D,~%"}, {"L188", "};~%"}}); } @@ -1288,7 +1289,7 @@ TEST_F(FormRegressionTest, Method2Vec4s) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", {{"L344", "#"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L344", "#"}}); } TEST_F(FormRegressionTest, SoundNameEqual) { @@ -1310,7 +1311,7 @@ TEST_F(FormRegressionTest, SoundNameEqual) { std::string type = "(function sound-name sound-name symbol)"; std::string expected = "(and (= (the-as uint arg0) (the-as uint arg1)) (= (-> arg0 hi) (-> arg1 hi)))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, DebugMenuFuncDecode) { @@ -1376,7 +1377,7 @@ TEST_F(FormRegressionTest, DebugMenuFuncDecode) { " )\n" " )\n" " )"; - test_with_expr(func, type, expected, false, "", {}, "[[13, \"a0\", \"symbol\"]]"); + test_with_expr_jak1(func, type, expected, false, "", {}, "[[13, \"a0\", \"symbol\"]]"); } TEST_F(FormRegressionTest, MatrixNewInlineProp) { @@ -1431,7 +1432,7 @@ TEST_F(FormRegressionTest, MatrixNewInlineProp) { " )\n" " arg0\n" " )"; - test_with_stack_structures(func, type, expected, R"([[16, "matrix"]])"); + test_with_stack_structures_jak1(func, type, expected, R"([[16, "matrix"]])"); } TEST_F(FormRegressionTest, VectorNewInlineProp) { @@ -1491,7 +1492,7 @@ TEST_F(FormRegressionTest, VectorNewInlineProp) { " )\n" " arg0\n" " )"; - test_with_stack_structures(func, type, expected, R"([[16, "vector"]])"); + test_with_stack_structures_jak1(func, type, expected, R"([[16, "vector"]])"); } TEST_F(FormRegressionTest, Method23Trsqv) { @@ -1517,7 +1518,7 @@ TEST_F(FormRegressionTest, Method23Trsqv) { std::string type = "(function trsqv vector float)"; std::string expected = "(vector-y-angle (vector-! (new 'stack-no-clear 'vector) arg1 (-> arg0 trans)))"; - test_with_stack_structures(func, type, expected, R"([[16, "vector"]])"); + test_with_stack_structures_jak1(func, type, expected, R"([[16, "vector"]])"); } TEST_F(FormRegressionTest, VectorLineDistance) { @@ -1612,6 +1613,6 @@ TEST_F(FormRegressionTest, VectorLineDistance) { " )\n" " (vector-length (vector-! (new-stack-vector0) gp-1 v1-3))\n" " )"; - test_with_stack_structures(func, type, expected, - R"([[16, "vector"], [32, "vector"], [48, "vector"], [64, "vector"]])"); + test_with_stack_structures_jak1( + func, type, expected, R"([[16, "vector"], [32, "vector"], [48, "vector"], [64, "vector"]])"); } diff --git a/test/decompiler/test_FormExpressionBuild3.cpp b/test/decompiler/test_FormExpressionBuild3.cpp index 626669dd04..2b51cc38a7 100644 --- a/test/decompiler/test_FormExpressionBuild3.cpp +++ b/test/decompiler/test_FormExpressionBuild3.cpp @@ -53,7 +53,7 @@ TEST_F(FormRegressionTest, VectorDegToVectorRad) { " (none)\n" " )\n" " )"; - test_final_function(func, type, expected); + test_final_function_jak1(func, type, expected); } // weird short circuit thing @@ -141,7 +141,7 @@ TEST_F(FormRegressionTest, WeirdShortCircuit) { " )\n" " s5-0\n" " )"; - test_with_stack_structures(func, type, expected, "[[16, \"event-message-block\"]]"); + test_with_stack_structures_jak1(func, type, expected, "[[16, \"event-message-block\"]]"); } TEST_F(FormRegressionTest, WeirdShortCircuit2) { @@ -162,5 +162,5 @@ TEST_F(FormRegressionTest, WeirdShortCircuit2) { " daddu sp, sp, r0"; std::string type = "(function actor-link-info object)"; std::string expected = "(the-as object (and (-> arg0 prev) (-> arg0 prev extra process)))"; - test_with_stack_structures(func, type, expected, "[[16, \"event-message-block\"]]"); + test_with_stack_structures_jak1(func, type, expected, "[[16, \"event-message-block\"]]"); } \ No newline at end of file diff --git a/test/decompiler/test_FormExpressionBuildLong.cpp b/test/decompiler/test_FormExpressionBuildLong.cpp index 7526641651..f0f0bf907e 100644 --- a/test/decompiler/test_FormExpressionBuildLong.cpp +++ b/test/decompiler/test_FormExpressionBuildLong.cpp @@ -665,32 +665,32 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " (format #t \")\")\n" " arg0\n" " )"; - test_with_expr(func, type, expected, true, "array", - {{"L343", "~f"}, - {"L342", "#("}, - {"L341", "~D"}, - {"L340", " ~D"}, - {"L339", "#x~X"}, - {"L338", " #x~X"}, - {"L337", " ~f"}, - {"L336", "~A"}, - {"L335", " ~A"}, - {"L334", ")"}}, - "[" - "\t\t[23, \"gp\", \"(array int32)\"],\n" - "\t\t[43, \"gp\", \"(array uint32)\"],\n" - "\t\t[63, \"gp\", \"(array int64)\"],\n" - "\t\t[83, \"gp\", \"(array uint64)\"],\n" - "\t\t[102, \"gp\", \"(array int8)\"],\n" - "\t\t[121, \"gp\", \"(array uint8)\"],\n" - "\t\t[141, \"gp\", \"(array int16)\"],\n" - "\t\t[161, \"gp\", \"(array uint16)\"],\n" - "\t\t[186, \"gp\", \"(array uint128)\"],\n" - "\t\t[204, \"gp\", \"(array int32)\"],\n" - "\t\t[223, \"gp\", \"(array float)\"],\n" - "\t\t[232, \"gp\", \"(array float)\"],\n" - "\t\t[249, \"gp\", \"(array basic)\"],\n" - "\t\t[258, \"gp\", \"(array basic)\"]]"); + test_with_expr_jak1(func, type, expected, true, "array", + {{"L343", "~f"}, + {"L342", "#("}, + {"L341", "~D"}, + {"L340", " ~D"}, + {"L339", "#x~X"}, + {"L338", " #x~X"}, + {"L337", " ~f"}, + {"L336", "~A"}, + {"L335", " ~A"}, + {"L334", ")"}}, + "[" + "\t\t[23, \"gp\", \"(array int32)\"],\n" + "\t\t[43, \"gp\", \"(array uint32)\"],\n" + "\t\t[63, \"gp\", \"(array int64)\"],\n" + "\t\t[83, \"gp\", \"(array uint64)\"],\n" + "\t\t[102, \"gp\", \"(array int8)\"],\n" + "\t\t[121, \"gp\", \"(array uint8)\"],\n" + "\t\t[141, \"gp\", \"(array int16)\"],\n" + "\t\t[161, \"gp\", \"(array uint16)\"],\n" + "\t\t[186, \"gp\", \"(array uint128)\"],\n" + "\t\t[204, \"gp\", \"(array int32)\"],\n" + "\t\t[223, \"gp\", \"(array float)\"],\n" + "\t\t[232, \"gp\", \"(array float)\"],\n" + "\t\t[249, \"gp\", \"(array basic)\"],\n" + "\t\t[258, \"gp\", \"(array basic)\"]]"); } TEST_F(FormRegressionTest, ExprArrayMethod3) { @@ -1226,28 +1226,28 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected, true, "array", - {{"L333", "[~8x] ~A~%"}, - {"L332", "~Tallocated-length: ~D~%"}, - {"L331", "~Tlength: ~D~%"}, - {"L330", " ~Tcontent-type: ~A~%"}, - {"L329", "~Tdata[~D]: @ #x~X~%"}, - {"L328", "~T [~D] ~D~%"}, - {"L327", "~T [~D] #x~X~%"}, - {"L326", "~T [~D] ~f~%"}, - {"L325", "~T [~D] ~A~%"}}, - "[\t\t[44, \"gp\", \"(array int32)\"],\n" - "\t\t[62, \"gp\", \"(array uint32)\"],\n" - "\t\t[80, \"gp\", \"(array int64)\"],\n" - "\t\t[98, \"gp\", \"(array uint64)\"],\n" - "\t\t[115, \"gp\", \"(array int8)\"],\n" - "\t\t[132, \"gp\", \"(array int8)\"],\n" - "\t\t[150, \"gp\", \"(array int16)\"],\n" - "\t\t[168, \"gp\", \"(array uint16)\"],\n" - "\t\t[191, \"gp\", \"(array uint128)\"],\n" - "\t\t[207, \"gp\", \"(array int32)\"],\n" - "\t\t[226, \"gp\", \"(array float)\"],\n" - "\t\t[243, \"gp\", \"(array basic)\"]]"); + test_with_expr_jak1(func, type, expected, true, "array", + {{"L333", "[~8x] ~A~%"}, + {"L332", "~Tallocated-length: ~D~%"}, + {"L331", "~Tlength: ~D~%"}, + {"L330", " ~Tcontent-type: ~A~%"}, + {"L329", "~Tdata[~D]: @ #x~X~%"}, + {"L328", "~T [~D] ~D~%"}, + {"L327", "~T [~D] #x~X~%"}, + {"L326", "~T [~D] ~f~%"}, + {"L325", "~T [~D] ~A~%"}}, + "[\t\t[44, \"gp\", \"(array int32)\"],\n" + "\t\t[62, \"gp\", \"(array uint32)\"],\n" + "\t\t[80, \"gp\", \"(array int64)\"],\n" + "\t\t[98, \"gp\", \"(array uint64)\"],\n" + "\t\t[115, \"gp\", \"(array int8)\"],\n" + "\t\t[132, \"gp\", \"(array int8)\"],\n" + "\t\t[150, \"gp\", \"(array int16)\"],\n" + "\t\t[168, \"gp\", \"(array uint16)\"],\n" + "\t\t[191, \"gp\", \"(array uint128)\"],\n" + "\t\t[207, \"gp\", \"(array int32)\"],\n" + "\t\t[226, \"gp\", \"(array float)\"],\n" + "\t\t[243, \"gp\", \"(array basic)\"]]"); } TEST_F(FormRegressionTest, ExprValid) { @@ -2013,7 +2013,7 @@ TEST_F(FormRegressionTest, ExprValid) { " )\n" " )\n" "\n"; - test_with_expr( + test_with_expr_jak1( func, type, expected, false, "", {{"L321", "ERROR: object #x~X ~S is not a valid object (misaligned)~%"}, {"L320", "ERROR: object #x~X ~S is not a valid object (bad address)~%"}, @@ -2397,7 +2397,7 @@ TEST_F(FormRegressionTest, ExprStringToInt) { " )\n" " )\n" " )"; - test_final_function(func, type, expected); + test_final_function_jak1(func, type, expected); } TEST_F(FormRegressionTest, Method19ResTag) { @@ -2888,11 +2888,11 @@ TEST_F(FormRegressionTest, Method19ResTag) { " (logior (logand 0 t0-6) (shl v1-14 32))\n" " )\n" " )"; - test_with_expr(func, type, expected, false, "", {}, - "[\n" - " [46, \"t2\", \"(pointer uint64)\"],\n" - " [100, \"t3\", \"(pointer uint64)\"],\n" - " [184, \"t5\", \"(pointer uint64)\"],\n" - " [64, \"t6\", \"(pointer uint64)\"]\n" - " ]"); + test_with_expr_jak1(func, type, expected, false, "", {}, + "[\n" + " [46, \"t2\", \"(pointer uint64)\"],\n" + " [100, \"t3\", \"(pointer uint64)\"],\n" + " [184, \"t5\", \"(pointer uint64)\"],\n" + " [64, \"t6\", \"(pointer uint64)\"]\n" + " ]"); } \ No newline at end of file diff --git a/test/decompiler/test_gkernel_decomp.cpp b/test/decompiler/test_gkernel_decomp.cpp index dd2e503fae..fb80d840dd 100644 --- a/test/decompiler/test_gkernel_decomp.cpp +++ b/test/decompiler/test_gkernel_decomp.cpp @@ -12,7 +12,7 @@ TEST_F(FormRegressionTest, ExprMethod7Object) { " daddu sp, sp, r0\n"; std::string type = "(function object int object)"; std::string expected = "arg0"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprLoadPackage) { @@ -71,7 +71,7 @@ TEST_F(FormRegressionTest, ExprLoadPackage) { " v0-1\n" " )\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprUnloadPackage) { @@ -110,7 +110,7 @@ TEST_F(FormRegressionTest, ExprUnloadPackage) { " )\n" " *kernel-packages*\n" " )"; - test_with_expr(func, type, expected, true); + test_with_expr_jak1(func, type, expected, true); } TEST_F(FormRegressionTest, ExprMethod1Thread) { @@ -141,7 +141,7 @@ TEST_F(FormRegressionTest, ExprMethod1Thread) { " (set! (-> arg0 process top-thread) (-> arg0 previous))\n" " (none)\n" " )"; - test_with_expr(func, type, expected, false); + test_with_expr_jak1(func, type, expected, false); } TEST_F(FormRegressionTest, ExprMethod2Thread) { @@ -187,7 +187,8 @@ TEST_F(FormRegressionTest, ExprMethod2Thread) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", {{"L343", "#<~A ~S of ~S pc: #x~X @ #x~X>"}}); + test_with_expr_jak1(func, type, expected, false, "", + {{"L343", "#<~A ~S of ~S pc: #x~X @ #x~X>"}}); } TEST_F(FormRegressionTest, ExprMethod9Thread) { @@ -288,7 +289,7 @@ TEST_F(FormRegressionTest, ExprMethod9Thread) { " 0\n" " (none)\n" " )"; - test_with_expr(func, type, expected, false, "", {{"L342", "1 ~A ~%"}, {"L341", "2 ~A ~%"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L342", "1 ~A ~%"}, {"L341", "2 ~A ~%"}}); } TEST_F(FormRegressionTest, ExprMethod0Thread) { @@ -363,9 +364,9 @@ TEST_F(FormRegressionTest, ExprMethod0Thread) { " (set! (-> obj stack-size) arg4)\n" " (the-as cpu-thread obj)\n" " )"; - test_with_expr(func, type, expected, false, "cpu-thread", {}, - "[[[13, 28], \"v0\", \"cpu-thread\"]]", - "{\"vars\":{\"v0-0\":[\"obj\", \"cpu-thread\"]}}"); + test_with_expr_jak1(func, type, expected, false, "cpu-thread", {}, + "[[[13, 28], \"v0\", \"cpu-thread\"]]", + "{\"vars\":{\"v0-0\":[\"obj\", \"cpu-thread\"]}}"); } TEST_F(FormRegressionTest, ExprMethod5CpuThread) { @@ -380,7 +381,7 @@ TEST_F(FormRegressionTest, ExprMethod5CpuThread) { " daddu sp, sp, r0"; std::string type = "(function cpu-thread int)"; std::string expected = "(the-as int (+ (-> arg0 type size) (-> arg0 stack-size)))"; - test_with_expr(func, type, expected, false); + test_with_expr_jak1(func, type, expected, false); } TEST_F(FormRegressionTest, RemoveExit) { @@ -406,7 +407,7 @@ TEST_F(FormRegressionTest, RemoveExit) { " v0-0\n" " )\n" " )"; - test_with_expr(func, type, expected, false); + test_with_expr_jak1(func, type, expected, false); } TEST_F(FormRegressionTest, RemoveMethod0ProcessTree) { @@ -451,7 +452,7 @@ TEST_F(FormRegressionTest, RemoveMethod0ProcessTree) { " (set! (-> v0-0 ppointer) (the-as (pointer process) (&-> v0-0 self)))\n" " v0-0\n" " )"; - test_with_expr(func, type, expected, false, "process-tree"); + test_with_expr_jak1(func, type, expected, false, "process-tree"); } TEST_F(FormRegressionTest, RemoveMethod3ProcessTree) { @@ -547,13 +548,13 @@ TEST_F(FormRegressionTest, RemoveMethod3ProcessTree) { " (format #t \"~Tchild: ~A~%\" (ppointer->process (-> arg0 child)))\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "process-tree", - {{"L340", "[~8x] ~A~%"}, - {"L339", "~Tname: ~S~%"}, - {"L338", "~Tmask: #x~X~%"}, - {"L337", "~Tparent: ~A~%"}, - {"L336", "~Tbrother: ~A~%"}, - {"L335", "~Tchild: ~A~%"}}); + test_with_expr_jak1(func, type, expected, false, "process-tree", + {{"L340", "[~8x] ~A~%"}, + {"L339", "~Tname: ~S~%"}, + {"L338", "~Tmask: #x~X~%"}, + {"L337", "~Tparent: ~A~%"}, + {"L336", "~Tbrother: ~A~%"}, + {"L335", "~Tchild: ~A~%"}}); } TEST_F(FormRegressionTest, ExprMethod0Process) { @@ -666,9 +667,9 @@ TEST_F(FormRegressionTest, ExprMethod0Process) { " )\n" " (the-as process v0-0)\n" " )"; - test_with_expr(func, type, expected, false, "process", {}, - "[\t\t[12, \"a0\", \"int\"],\n" - "\t\t[[13, 43], \"v0\", \"process\"]]"); + test_with_expr_jak1(func, type, expected, false, "process", {}, + "[\t\t[12, \"a0\", \"int\"],\n" + "\t\t[[13, 43], \"v0\", \"process\"]]"); } TEST_F(FormRegressionTest, ExprInspectProcessHeap) { @@ -731,10 +732,10 @@ TEST_F(FormRegressionTest, ExprInspectProcessHeap) { " )\n" " #f\n" " )"; - test_with_expr(func, type, expected, false, "", {}, - "[\t\t[[4,11], \"s5\", \"basic\"],\n" - "\t\t[[17,20], \"s5\", \"pointer\"]]", - "{\"vars\":{\"s5-0\":[\"obj\", \"pointer\"]}}"); + test_with_expr_jak1(func, type, expected, false, "", {}, + "[\t\t[[4,11], \"s5\", \"basic\"],\n" + "\t\t[[17,20], \"s5\", \"pointer\"]]", + "{\"vars\":{\"s5-0\":[\"obj\", \"pointer\"]}}"); } // note: skipped method 3 process @@ -750,7 +751,7 @@ TEST_F(FormRegressionTest, ExprMethod5Process) { " daddu sp, sp, r0"; std::string type = "(function process int)"; std::string expected = "(the-as int (+ (-> process size) (-> arg0 allocated-length)))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod2Process) { @@ -831,8 +832,9 @@ TEST_F(FormRegressionTest, ExprMethod2Process) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", - {{"L317", "#<~A ~S ~A :state ~S "}, {"L316", ":stack ~D/~D :heap ~D/~D @ #x~X>"}}); + test_with_expr_jak1( + func, type, expected, false, "", + {{"L317", "#<~A ~S ~A :state ~S "}, {"L316", ":stack ~D/~D :heap ~D/~D @ #x~X>"}}); } TEST_F(FormRegressionTest, ExprMethod0DeadPool) { @@ -945,7 +947,7 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPool) { " )\n" " s3-0\n" " )"; - test_with_expr(func, type, expected, false, "dead-pool"); + test_with_expr_jak1(func, type, expected, false, "dead-pool"); } TEST_F(FormRegressionTest, ExprMethod14DeadPool) { @@ -1085,7 +1087,7 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPool) { " )"; // note - there's likely an actual bug here. - test_with_expr( + test_with_expr_jak1( func, type, expected, false, "dead-pool", {{"L315", "WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%"}, {"L314", "WARNING: ~A ~A could not be allocated, because ~A was empty.~%"}}, @@ -1111,7 +1113,7 @@ TEST_F(FormRegressionTest, ExprMethod15DeadPool) { " daddiu sp, sp, 16"; std::string type = "(function dead-pool process none)"; std::string expected = "(begin (change-parent arg1 arg0) (none))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) { @@ -1256,10 +1258,10 @@ TEST_F(FormRegressionTest, ExprMethod0DeadPoolHeap) { " (set! (-> obj heap top-base) (-> obj heap top))\n" " obj\n" " )"; - test_with_expr(func, type, expected, false, "dead-pool-heap", {}, - "[\t\t[60, \"v0\", \"int\"],\n" - "\t\t[61, \"a0\", \"pointer\"], [61, \"v0\", \"dead-pool-heap\"]]", - "{\"vars\":{\"v0-0\":[\"obj\", \"dead-pool-heap\"]}}"); + test_with_expr_jak1(func, type, expected, false, "dead-pool-heap", {}, + "[\t\t[60, \"v0\", \"int\"],\n" + "\t\t[61, \"a0\", \"pointer\"], [61, \"v0\", \"dead-pool-heap\"]]", + "{\"vars\":{\"v0-0\":[\"obj\", \"dead-pool-heap\"]}}"); } TEST_F(FormRegressionTest, ExprMethod22DeadPoolHeap) { @@ -1296,7 +1298,7 @@ TEST_F(FormRegressionTest, ExprMethod22DeadPoolHeap) { " (-> arg0 heap base)\n" " )\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod21DeadPoolHeap) { @@ -1382,10 +1384,10 @@ TEST_F(FormRegressionTest, ExprMethod21DeadPoolHeap) { " (&- (-> arg0 heap top) (the-as uint (-> arg0 heap base)))\n" " )\n" " )"; - test_with_expr(func, type, expected, false, "", {}, - "[\t\t[5, \"v1\", \"pointer\"],\n" - "\t\t[13, \"a0\", \"pointer\"],\n" - "\t\t[25, \"v1\", \"pointer\"]]"); + test_with_expr_jak1(func, type, expected, false, "", {}, + "[\t\t[5, \"v1\", \"pointer\"],\n" + "\t\t[13, \"a0\", \"pointer\"],\n" + "\t\t[25, \"v1\", \"pointer\"]]"); } TEST_F(FormRegressionTest, ExprMethod3DeadPoolHeap) { @@ -1561,10 +1563,10 @@ TEST_F(FormRegressionTest, ExprMethod3DeadPoolHeap) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected, false, "", - {{"L300", "~Tprocess-list[0] @ #x~X ~D/~D bytes used~%"}, - {"L299", "~T [~3D] # ~A~%"}, - {"L298", "~T gap: ~D bytes @ #x~X~%"}}); + test_with_expr_jak1(func, type, expected, false, "", + {{"L300", "~Tprocess-list[0] @ #x~X ~D/~D bytes used~%"}, + {"L299", "~T [~3D] # ~A~%"}, + {"L298", "~T gap: ~D bytes @ #x~X~%"}}); } TEST_F(FormRegressionTest, ExprMethod5DeadPoolHeap) { @@ -1579,8 +1581,8 @@ TEST_F(FormRegressionTest, ExprMethod5DeadPoolHeap) { std::string type = "(function dead-pool-heap int)"; std::string expected = "(+ (the-as int (- -4 (the-as int arg0))) (the-as int (-> arg0 heap top)))"; - test_with_expr(func, type, expected, false, "", {}, - "[[3, \"v1\", \"int\"], [3, \"a0\", \"int\"]]"); + test_with_expr_jak1(func, type, expected, false, "", {}, + "[[3, \"v1\", \"int\"], [3, \"a0\", \"int\"]]"); } TEST_F(FormRegressionTest, ExprMethod19DeadPoolHeap) { @@ -1632,7 +1634,7 @@ TEST_F(FormRegressionTest, ExprMethod19DeadPoolHeap) { " (- (memory-total arg0) (gap-size arg0 (-> arg0 alive-list prev)))\n" " 0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod20DeadPoolHeap) { @@ -1645,7 +1647,7 @@ TEST_F(FormRegressionTest, ExprMethod20DeadPoolHeap) { " daddu sp, sp, r0"; std::string type = "(function dead-pool-heap int)"; std::string expected = "(&- (-> arg0 heap top) (the-as uint (-> arg0 heap base)))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod25DeadPoolHeap) { @@ -1688,7 +1690,7 @@ TEST_F(FormRegressionTest, ExprMethod25DeadPoolHeap) { " (&- v1-0 (the-as uint (-> arg0 heap base)))\n" " )\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod26DeadPoolHeap) { @@ -1699,7 +1701,7 @@ TEST_F(FormRegressionTest, ExprMethod26DeadPoolHeap) { " daddu sp, sp, r0"; std::string type = "(function dead-pool-heap uint)"; std::string expected = "(-> arg0 compact-time)"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod24DeadPoolHeap) { @@ -1756,7 +1758,7 @@ TEST_F(FormRegressionTest, ExprMethod24DeadPoolHeap) { " (while (and gp-0 (< (gap-size arg0 gp-0) arg1)) (set! gp-0 (-> gp-0 next)))\n" " gp-0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod14DeadPoolHeap) { @@ -2032,7 +2034,7 @@ TEST_F(FormRegressionTest, ExprMethod14DeadPoolHeap) { " )\n" " s3-0\n" " )"; - test_with_expr( + test_with_expr_jak1( func, type, expected, false, "", {{"L315", "WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%"}, {"L314", "WARNING: ~A ~A could not be allocated, because ~A was empty.~%"}}); @@ -2199,8 +2201,8 @@ TEST_F(FormRegressionTest, ExprMethod15DeadPoolHeap) { " 0\n" " (none)\n" " )"; - test_with_expr(func, type, expected, false, "", - {{"L297", "ERROR: process ~A does not belong to dead-pool-heap ~A.~%"}}); + test_with_expr_jak1(func, type, expected, false, "", + {{"L297", "ERROR: process ~A does not belong to dead-pool-heap ~A.~%"}}); } TEST_F(FormRegressionTest, ExprMethod17DeadPoolHeap) { @@ -2325,7 +2327,7 @@ TEST_F(FormRegressionTest, ExprMethod17DeadPoolHeap) { " )\n" " arg0\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprMethod16DeadPoolHeap) { @@ -2574,7 +2576,7 @@ TEST_F(FormRegressionTest, ExprMethod16DeadPoolHeap) { " 0\n" " (none)\n" " )"; - test_with_expr(func, type, expected, false, "", {{"L296", "~3LLow Actor Memory~%~0L"}}); + test_with_expr_jak1(func, type, expected, false, "", {{"L296", "~3LLow Actor Memory~%~0L"}}); } // nested method calls @@ -2771,5 +2773,5 @@ TEST_F(FormRegressionTest, ExprMethod18DeadPoolHeap) { " 0\n" " (none)\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } diff --git a/test/decompiler/test_math_decomp.cpp b/test/decompiler/test_math_decomp.cpp index 24793b11c9..452079df75 100644 --- a/test/decompiler/test_math_decomp.cpp +++ b/test/decompiler/test_math_decomp.cpp @@ -15,7 +15,7 @@ TEST_F(FormRegressionTest, ExprTruncate) { " daddu sp, sp, r0"; std::string type = "(function float float)"; std::string expected = "(the float (the int arg0))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprIntegralP) { @@ -37,7 +37,7 @@ TEST_F(FormRegressionTest, ExprIntegralP) { " daddu sp, sp, r0"; std::string type = "(function float float)"; std::string expected = "(the-as float (= (the float (the int arg0)) arg0))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprFractionalPart) { @@ -55,7 +55,7 @@ TEST_F(FormRegressionTest, ExprFractionalPart) { " daddu sp, sp, r0"; std::string type = "(function float float)"; std::string expected = "(- arg0 (the float (the int arg0)))"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } TEST_F(FormRegressionTest, ExprSeek) { @@ -103,5 +103,5 @@ TEST_F(FormRegressionTest, ExprSeek) { " (else (- arg0 arg2))\n" " )\n" " )"; - test_with_expr(func, type, expected); + test_with_expr_jak1(func, type, expected); } \ No newline at end of file