diff --git a/decompiler/IR/BasicOpBuilder.cpp b/decompiler/IR/BasicOpBuilder.cpp index 2ac138c610..a6480ac9f8 100644 --- a/decompiler/IR/BasicOpBuilder.cpp +++ b/decompiler/IR/BasicOpBuilder.cpp @@ -1208,6 +1208,7 @@ std::shared_ptr try_lwu(Instruction& i0, } // namespace void add_basic_ops_to_block(Function* func, const BasicBlock& block, LinkedObjectFile* file) { + (void)file; for (int instr = block.start_word; instr < block.end_word; instr++) { auto& i = func->instructions.at(instr); diff --git a/decompiler/IR/CfgBuilder.cpp b/decompiler/IR/CfgBuilder.cpp index bffa16626d..b6cfd704df 100644 --- a/decompiler/IR/CfgBuilder.cpp +++ b/decompiler/IR/CfgBuilder.cpp @@ -106,7 +106,7 @@ void clean_up_cond_with_else(std::shared_ptr* ir, LinkedObjectFile& file) { assert(jump_to_next.first); assert(jump_to_next.first->branch_delay.kind == BranchDelay::NOP); // patch the jump to next with a condition. - auto replacement = std::make_shared(jump_to_next.first->condition); + auto replacement = std::make_shared(jump_to_next.first->condition) *(jump_to_next.second) = replacement; // patch the jump at the end of a block. @@ -153,10 +153,6 @@ void convert_cond_no_else_to_compare(std::shared_ptr* ir) { auto condition_as_single = dynamic_cast(cne->entries.front().condition.get()); if (condition_as_single) { - // as far as I can tell this is totally valid but just happens to not appear? - // if this case is ever hit in the future it's fine and we just need to implement this. - // but leaving empty for now so there's fewer things to test. - // assert(false); auto replacement = std::make_shared( IR_Set::REG_64, dst, std::make_shared(condition.first->condition)); @@ -186,6 +182,7 @@ void convert_cond_no_else_to_compare(std::shared_ptr* ir) { * this. */ void clean_up_cond_no_else(std::shared_ptr* ir, LinkedObjectFile& file) { + auto cne = dynamic_cast(ir->get()); assert(cne); for (size_t idx = 0; idx < cne->entries.size(); idx++) { @@ -212,6 +209,7 @@ void clean_up_cond_no_else(std::shared_ptr* ir, LinkedObjectFile& file) { } auto replacement = std::make_shared(jump_to_next.first->condition); + *(jump_to_next.second) = replacement; e.cleaned = true; @@ -344,7 +342,6 @@ std::shared_ptr try_sc_as_ash(Function& f, LinkedObjectFile& file, ShortCirc } // todo, I think b0 could possibly be something more complicated, depending on how we order. - auto b0 = dynamic_cast(vtx->entries.at(0)); auto b1 = dynamic_cast(vtx->entries.at(1)); if (!b0 || !b1) { return nullptr; @@ -399,8 +396,7 @@ std::shared_ptr try_sc_as_ash(Function& f, LinkedObjectFile& file, ShortCirc assert(result); assert(value_in); - if (!is_int_math_3(dsrav_candidate.get(), IR_IntMath2::RIGHT_SHIFT_ARITH, result->reg, - value_in->reg, clobber)) { + return nullptr; } @@ -422,7 +418,6 @@ std::shared_ptr try_sc_as_ash(Function& f, LinkedObjectFile& file, ShortCirc b0_ir->forms.pop_back(); // add the ash b0_ir->forms.push_back(std::make_shared( - IR_Set::REG_64, dest_ir, std::make_shared(shift_ir, value_ir, clobber_ir))); return b0_ptr; } @@ -453,7 +448,6 @@ std::shared_ptr try_sc_as_type_of(Function& f, LinkedObjectFile& file, Short return nullptr; } - auto b0 = dynamic_cast(vtx->entries.at(0)); auto b1 = dynamic_cast(vtx->entries.at(1)); auto b2 = dynamic_cast(vtx->entries.at(2)); @@ -698,6 +692,7 @@ std::shared_ptr cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx) entries.push_back(e); } auto result = std::make_shared(entries); + // todo clean these into real and/or. return result; } else if (dynamic_cast(vtx)) { diff --git a/decompiler/IR/IR.cpp b/decompiler/IR/IR.cpp index f2bce71428..a5c9b11773 100644 --- a/decompiler/IR/IR.cpp +++ b/decompiler/IR/IR.cpp @@ -793,8 +793,6 @@ void IR_ShortCircuit::get_children(std::vector>* output) con } goos::Object IR_Ash::to_form(const LinkedObjectFile& file) const { - return pretty_print::build_list(pretty_print::to_symbol("ash"), value->to_form(file), - shift_amount->to_form(file)); } void IR_Ash::get_children(std::vector>* output) const { diff --git a/decompiler/IR/IR.h b/decompiler/IR/IR.h index 7d358bd379..917ab553b9 100644 --- a/decompiler/IR/IR.h +++ b/decompiler/IR/IR.h @@ -357,12 +357,6 @@ class IR_ShortCircuit : public IR { class IR_Ash : public IR { public: std::shared_ptr shift_amount, value, clobber; - IR_Ash(std::shared_ptr _shift_amount, - std::shared_ptr _value, - std::shared_ptr _clobber) - : shift_amount(std::move(_shift_amount)), - value(std::move(_value)), - clobber(std::move(_clobber)) {} goos::Object to_form(const LinkedObjectFile& file) const override; void get_children(std::vector>* output) const override; }; diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index 5c5b7fd61a..6f84043feb 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -592,13 +592,12 @@ void ObjectFileDB::analyze_functions() { // } } - int total_nontrivial_functions = 0; - int total_resolved_nontrivial_functions = 0; + int total_trivial_cfg_functions = 0; int total_named_functions = 0; int total_basic_ops = 0; int total_failed_basic_ops = 0; - int attempted_cfg_irs = 0; + int successful_cfg_irs = 0; std::map> unresolved_by_length; @@ -624,7 +623,7 @@ void ObjectFileDB::analyze_functions() { total_failed_basic_ops += func.get_failed_basic_op_count(); func.ir = build_cfg_ir(func, *func.cfg, data.linked_data); - attempted_cfg_irs++; + if (func.ir) { successful_cfg_irs++; } @@ -633,13 +632,11 @@ void ObjectFileDB::analyze_functions() { resolved_cfg_functions++; } } else { - resolved_cfg_functions++; + asm_funcs++; } if (func.basic_blocks.size() > 1 && !func.suspected_asm) { - total_nontrivial_functions++; if (func.cfg->is_fully_resolved()) { - total_resolved_nontrivial_functions++; } else { if (!func.guessed_name.empty()) { unresolved_by_length[func.end_word - func.start_word].push_back( @@ -648,6 +645,10 @@ void ObjectFileDB::analyze_functions() { } } + if (!func.suspected_asm && func.basic_blocks.size() <= 1) { + total_trivial_cfg_functions++; + } + if (!func.guessed_name.empty()) { total_named_functions++; } @@ -657,21 +658,14 @@ void ObjectFileDB::analyze_functions() { // } }); - printf("Found %d functions (%d with nontrivial cfgs)\n", total_functions, - total_nontrivial_functions); + printf("Found %d functions (%d with no control flow)\n", total_functions, + total_trivial_cfg_functions); printf("Named %d/%d functions (%.2f%%)\n", total_named_functions, total_functions, 100.f * float(total_named_functions) / float(total_functions)); + printf("Excluding %d asm functions\n", asm_funcs); printf("Found %d basic blocks in %.3f ms\n", total_basic_blocks, timer.getMs()); printf(" %d/%d functions passed cfg analysis stage (%.2f%%)\n", resolved_cfg_functions, - total_functions, 100.f * float(resolved_cfg_functions) / float(total_functions)); - printf(" %d/%d nontrivial cfg's resolved (%.2f%%)\n", total_resolved_nontrivial_functions, - total_nontrivial_functions, - 100.f * float(total_resolved_nontrivial_functions) / float(total_nontrivial_functions)); - int successful_basic_ops = total_basic_ops - total_failed_basic_ops; - printf(" %d/%d basic ops converted successfully (%.2f%%)\n", successful_basic_ops, - total_basic_ops, 100.f * float(successful_basic_ops) / float(total_basic_ops)); - printf(" %d/%d cfgs converted to ir (%.2f%%)\n", successful_cfg_irs, attempted_cfg_irs, - 100.f * float(successful_cfg_irs) / float(attempted_cfg_irs)); + // for (auto& kv : unresolved_by_length) { // printf("LEN %d\n", kv.first); diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index 3697fcaab8..909ee74fff 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -45,6 +45,7 @@ // fails for unknown reason "target-falling-anim-trans", "change-brother", + // these are all valid, but use short circuiting branches in strange ways. There's probably a few compiler uses that we're not "(method 21 actor-link-info)","(method 20 actor-link-info)","(method 28 collide-shape-prim-mesh)", "(method 35 collide-shape)", "debug-menu-item-var-render", "(method 14 level)","add-blue-motion","anim-tester-add-newobj","(method 27 orb-cache-top)",