diff --git a/decompiler/CMakeLists.txt b/decompiler/CMakeLists.txt index d1b37b8edc..e529f88049 100644 --- a/decompiler/CMakeLists.txt +++ b/decompiler/CMakeLists.txt @@ -17,6 +17,7 @@ add_executable(decompiler Disasm/InstructionMatching.cpp Function/CfgVtx.cpp Function/CfgVtx.h IR/BasicOpBuilder.cpp + IR/CfgBuilder.cpp IR/IR.cpp) target_link_libraries(decompiler diff --git a/decompiler/Function/Function.cpp b/decompiler/Function/Function.cpp index dd433763d6..96233104fb 100644 --- a/decompiler/Function/Function.cpp +++ b/decompiler/Function/Function.cpp @@ -572,8 +572,8 @@ bool Function::instr_starts_basic_op(int idx) { return false; } -IR* Function::get_basic_op_at_instr(int idx) { - return basic_ops.at(instruction_to_basic_op.at(idx)).get(); +std::shared_ptr Function::get_basic_op_at_instr(int idx) { + return basic_ops.at(instruction_to_basic_op.at(idx)); } int Function::get_basic_op_count() { diff --git a/decompiler/Function/Function.h b/decompiler/Function/Function.h index c0420ec055..156d1b8e14 100644 --- a/decompiler/Function/Function.h +++ b/decompiler/Function/Function.h @@ -68,10 +68,12 @@ class Function { void add_basic_op(std::shared_ptr op, int start_instr, int end_instr); bool has_basic_ops() { return !basic_ops.empty(); } bool instr_starts_basic_op(int idx); - IR* get_basic_op_at_instr(int idx); + std::shared_ptr get_basic_op_at_instr(int idx); int get_basic_op_count(); int get_failed_basic_op_count(); + std::shared_ptr ir = nullptr; + int segment = -1; int start_word = -1; int end_word = -1; // not inclusive, but does include padding. diff --git a/decompiler/IR/BasicOpBuilder.cpp b/decompiler/IR/BasicOpBuilder.cpp index aa677aa000..b7012b0291 100644 --- a/decompiler/IR/BasicOpBuilder.cpp +++ b/decompiler/IR/BasicOpBuilder.cpp @@ -1402,7 +1402,7 @@ void add_basic_ops_to_block(Function* func, const BasicBlock& block, LinkedObjec if (!result) { state.reset(); // temp hack for debug: - printf("Instruction -> BasicOp failed on %s\n", i.to_string(*file).c_str()); + // printf("Instruction -> BasicOp failed on %s\n", i.to_string(*file).c_str()); func->add_basic_op(std::make_shared(), instr, instr + 1); } else { func->add_basic_op(result, instr, instr + length); diff --git a/decompiler/IR/CfgBuilder.cpp b/decompiler/IR/CfgBuilder.cpp new file mode 100644 index 0000000000..5239620f68 --- /dev/null +++ b/decompiler/IR/CfgBuilder.cpp @@ -0,0 +1,180 @@ +#include +#include "CfgBuilder.h" +#include "decompiler/Function/CfgVtx.h" +#include "decompiler/Function/Function.h" + +std::vector> IR::get_all_ir(LinkedObjectFile& file) const { + std::vector> result; + get_children(&result); + size_t last_checked = 0; + size_t last_last_checked = -1; + + while (last_checked != last_last_checked) { + last_last_checked = last_checked; + auto end_of_check = result.size(); + for (size_t i = last_checked; i < end_of_check; i++) { + auto it = result.at(i).get(); + assert(it); + it->get_children(&result); + } + last_checked = end_of_check; + } + + // Todo, remove this check which is just for debugging. + std::unordered_set> unique_ir; + for (auto& x : result) { + unique_ir.insert(x); + } + assert(unique_ir.size() == result.size()); + return result; +} + +namespace { + +std::shared_ptr cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx); + +/*! + * This adds a single CfgVtx* to a list of IR's by converting it with cfg to IR. + * The trick here is that it will recursively inline anything which would generate an IR begin. + * This avoids the case where Begin's are nested excessively. + */ +void insert_cfg_into_list(Function& f, + LinkedObjectFile& file, + std::vector>* output, + CfgVtx* vtx) { + auto as_sequence = dynamic_cast(vtx); + auto as_block = dynamic_cast(vtx); + if (as_sequence) { + for (auto& x : as_sequence->seq) { + insert_cfg_into_list(f, file, output, x); + } + } else if (as_block) { + auto& block = f.basic_blocks.at(as_block->block_id); + IR* last = nullptr; + for (int instr = block.start_word; instr < block.end_word; instr++) { + auto got = f.get_basic_op_at_instr(instr); + if (got.get() == last) { + continue; + } + last = got.get(); + output->push_back(got); + } + } else { + output->push_back(cfg_to_ir(f, file, vtx)); + } +} + +std::shared_ptr cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx) { + if (dynamic_cast(vtx)) { + auto* bv = dynamic_cast(vtx); + auto& block = f.basic_blocks.at(bv->block_id); + std::vector> irs; + IR* last = nullptr; + for (int instr = block.start_word; instr < block.end_word; instr++) { + auto got = f.get_basic_op_at_instr(instr); + if (got.get() == last) { + continue; + } + last = got.get(); + irs.push_back(got); + } + + if (irs.size() == 1) { + return irs.front(); + } else { + return std::make_shared(irs); + } + + } else if (dynamic_cast(vtx)) { + auto* sv = dynamic_cast(vtx); + + std::vector> irs; + insert_cfg_into_list(f, file, &irs, sv); + + return std::make_shared(irs); + } else if (dynamic_cast(vtx)) { + auto wvtx = dynamic_cast(vtx); + auto result = std::make_shared(cfg_to_ir(f, file, wvtx->condition), + cfg_to_ir(f, file, wvtx->body)); + return result; + } + + else { + throw std::runtime_error("not yet implemented IR conversion."); + return nullptr; + } +} + +void clean_up_while_loops(IR_Begin* sequence, LinkedObjectFile& file) { + std::vector to_remove; // the list of branches to remove by index in this sequence + for (size_t i = 0; i < sequence->forms.size(); i++) { + auto* form_as_while = dynamic_cast(sequence->forms.at(i).get()); + if (form_as_while) { + assert(i != 0); + auto prev_as_branch = dynamic_cast(sequence->forms.at(i - 1).get()); + assert(prev_as_branch); + printf("got while intro branch %s\n", prev_as_branch->print(file).c_str()); + // this should be an always jump. We'll assume that the CFG builder successfully checked + // the brach destination, but we will check the condition. + assert(prev_as_branch->condition.kind == Condition::ALWAYS); + assert(prev_as_branch->branch_delay.kind == BranchDelay::NOP); + to_remove.push_back(i - 1); + + // now we should try to find the condition branch: + IR_Branch* condition_branch = dynamic_cast(form_as_while->condition.get()); + std::shared_ptr* condition_branch_location = &form_as_while->condition; + if (!condition_branch) { + // not 100% sure this will always work + auto as_seq = dynamic_cast(form_as_while->condition.get()); + if (as_seq) { + condition_branch = dynamic_cast(as_seq->forms.back().get()); + condition_branch_location = &as_seq->forms.back(); + } + } + + assert(condition_branch); + assert(condition_branch->branch_delay.kind == BranchDelay::NOP); + printf("got while condition branch %s\n", condition_branch->print(file).c_str()); + auto replacement = std::make_shared(condition_branch->condition); + *condition_branch_location = replacement; + } + } + + // remove the implied forward always branches. + for (int i = int(to_remove.size()); i-- > 0;) { + auto idx = to_remove.at(i); + assert(dynamic_cast(sequence->forms.at(idx).get())); + sequence->forms.erase(sequence->forms.begin() + idx); + } +} +} // namespace + +std::shared_ptr build_cfg_ir(Function& function, + ControlFlowGraph& cfg, + LinkedObjectFile& file) { + // printf("build cfg ir\n"); + if (!cfg.is_fully_resolved()) { + return nullptr; + } + + try { + auto top_level = cfg.get_single_top_level(); + // todo, we should apply transformations for fixing up branch instructions for each IR. + // and possibly annotate the IR control flow structure so that we can determine if its and/or + // or whatever. This may require rejecting a huge number of inline assembly functions, and + // possibly resolving the min/max/ash issue. + auto ir = cfg_to_ir(function, file, top_level); + auto all_children = ir->get_all_ir(file); + all_children.push_back(ir); + for (auto& child : all_children) { + // printf("child is %s\n", child->print(file).c_str()); + auto as_begin = dynamic_cast(child.get()); + if (as_begin) { + clean_up_while_loops(as_begin, file); + } + } + return ir; + } catch (std::runtime_error& e) { + return nullptr; + } +} \ No newline at end of file diff --git a/decompiler/IR/CfgBuilder.h b/decompiler/IR/CfgBuilder.h new file mode 100644 index 0000000000..b15b08b626 --- /dev/null +++ b/decompiler/IR/CfgBuilder.h @@ -0,0 +1,10 @@ +#pragma once + +#include + +class IR; +class Function; +class LinkedObjectFile; +class ControlFlowGraph; + +std::shared_ptr build_cfg_ir(Function& function, ControlFlowGraph& cfg, LinkedObjectFile& file); \ No newline at end of file diff --git a/decompiler/IR/IR.cpp b/decompiler/IR/IR.cpp index 2b6ba34187..195bd72c00 100644 --- a/decompiler/IR/IR.cpp +++ b/decompiler/IR/IR.cpp @@ -5,15 +5,35 @@ std::string IR::print(const LinkedObjectFile& file) const { return to_form(file)->toStringPretty(); } +std::shared_ptr
IR_Failed::to_form(const LinkedObjectFile& file) const { + (void)file; + return buildList("INVALID-OPERATION"); +} + +void IR_Failed::get_children(std::vector>* output) const { + (void)output; +} + std::shared_ptr IR_Register::to_form(const LinkedObjectFile& file) const { (void)file; return toForm(reg.to_charp()); } +void IR_Register::get_children(std::vector>* output) const { + (void)output; +} + std::shared_ptr IR_Set::to_form(const LinkedObjectFile& file) const { return buildList(toForm("set!"), dst->to_form(file), src->to_form(file)); } +void IR_Set::get_children(std::vector>* output) const { + // note that we are not returning clobber here because it shouldn't contain anything that + // the IR simplification code should touch. + output->push_back(dst); + output->push_back(src); +} + std::shared_ptr IR_Store::to_form(const LinkedObjectFile& file) const { std::string store_operator; switch (kind) { @@ -48,26 +68,33 @@ std::shared_ptr IR_Store::to_form(const LinkedObjectFile& file) const { return buildList(toForm(store_operator), dst->to_form(file), src->to_form(file)); } -std::shared_ptr IR_Failed::to_form(const LinkedObjectFile& file) const { - (void)file; - return buildList("INVALID-OPERATION"); -} - std::shared_ptr IR_Symbol::to_form(const LinkedObjectFile& file) const { (void)file; return toForm("'" + name); } +void IR_Symbol::get_children(std::vector>* output) const { + (void)output; +} + std::shared_ptr IR_SymbolValue::to_form(const LinkedObjectFile& file) const { (void)file; return toForm(name); } +void IR_SymbolValue::get_children(std::vector>* output) const { + (void)output; +} + std::shared_ptr IR_StaticAddress::to_form(const LinkedObjectFile& file) const { // return buildList(toForm("&"), file.get_label_name(label_id)); return toForm(file.get_label_name(label_id)); } +void IR_StaticAddress::get_children(std::vector>* output) const { + (void)output; +} + std::shared_ptr IR_Load::to_form(const LinkedObjectFile& file) const { std::string load_operator; switch (kind) { @@ -116,6 +143,10 @@ std::shared_ptr IR_Load::to_form(const LinkedObjectFile& file) const { return buildList(toForm(load_operator), location->to_form(file)); } +void IR_Load::get_children(std::vector>* output) const { + output->push_back(location); +} + std::shared_ptr IR_FloatMath2::to_form(const LinkedObjectFile& file) const { std::string math_operator; switch (kind) { @@ -144,6 +175,15 @@ std::shared_ptr IR_FloatMath2::to_form(const LinkedObjectFile& file) const return buildList(toForm(math_operator), arg0->to_form(file), arg1->to_form(file)); } +void IR_FloatMath2::get_children(std::vector>* output) const { + output->push_back(arg0); + output->push_back(arg1); +} + +void IR_FloatMath1::get_children(std::vector>* output) const { + output->push_back(arg); +} + std::shared_ptr IR_IntMath2::to_form(const LinkedObjectFile& file) const { std::string math_operator; switch (kind) { @@ -198,6 +238,11 @@ std::shared_ptr IR_IntMath2::to_form(const LinkedObjectFile& file) const { return buildList(toForm(math_operator), arg0->to_form(file), arg1->to_form(file)); } +void IR_IntMath2::get_children(std::vector>* output) const { + output->push_back(arg0); + output->push_back(arg1); +} + std::shared_ptr IR_IntMath1::to_form(const LinkedObjectFile& file) const { std::string math_operator; switch (kind) { @@ -210,6 +255,10 @@ std::shared_ptr IR_IntMath1::to_form(const LinkedObjectFile& file) const { return buildList(toForm(math_operator), arg->to_form(file)); } +void IR_IntMath1::get_children(std::vector>* output) const { + output->push_back(arg); +} + std::shared_ptr IR_FloatMath1::to_form(const LinkedObjectFile& file) const { std::string math_operator; switch (kind) { @@ -239,11 +288,19 @@ std::shared_ptr IR_Call::to_form(const LinkedObjectFile& file) const { return buildList("call!"); } +void IR_Call::get_children(std::vector>* output) const { + (void)output; +} + std::shared_ptr IR_IntegerConstant::to_form(const LinkedObjectFile& file) const { (void)file; return toForm(std::to_string(value)); } +void IR_IntegerConstant::get_children(std::vector>* output) const { + (void)output; +} + std::shared_ptr BranchDelay::to_form(const LinkedObjectFile& file) const { (void)file; switch (kind) { @@ -262,6 +319,16 @@ std::shared_ptr BranchDelay::to_form(const LinkedObjectFile& file) const { } } +void BranchDelay::get_children(std::vector>* output) const { + if (destination) { + output->push_back(destination); + } + + if (source) { + output->push_back(source); + } +} + std::shared_ptr IR_Nop::to_form(const LinkedObjectFile& file) const { (void)file; return buildList("nop!"); @@ -296,6 +363,16 @@ int Condition::num_args() const { } } +void Condition::get_children(std::vector>* output) const { + if (src0) { + output->push_back(src0); + } + + if (src1) { + output->push_back(src1); + } +} + std::shared_ptr Condition::to_form(const LinkedObjectFile& file) const { int nargs = num_args(); std::string condtion_operator; @@ -381,11 +458,71 @@ std::shared_ptr IR_Branch::to_form(const LinkedObjectFile& file) const { toForm(file.get_label_name(dest_label_idx)), branch_delay.to_form(file)); } +void IR_Branch::get_children(std::vector>* output) const { + condition.get_children(output); + branch_delay.get_children(output); +} + std::shared_ptr IR_Compare::to_form(const LinkedObjectFile& file) const { return condition.to_form(file); } +void IR_Compare::get_children(std::vector>* output) const { + condition.get_children(output); +} + std::shared_ptr IR_Suspend::to_form(const LinkedObjectFile& file) const { (void)file; return buildList("suspend!"); +} + +void IR_Nop::get_children(std::vector>* output) const { + (void)output; +} + +void IR_Suspend::get_children(std::vector>* output) const { + (void)output; +} + +std::shared_ptr IR_Begin::to_form(const LinkedObjectFile& file) const { + std::vector> list; + list.push_back(toForm("begin")); + for (auto& x : forms) { + list.push_back(x->to_form(file)); + } + return buildList(list); +} + +void IR_Begin::get_children(std::vector>* output) const { + for (auto& x : forms) { + output->push_back(x); + } +} + +namespace { +void print_inlining_begin(std::vector>* output, + IR* ir, + const LinkedObjectFile& file) { + auto as_begin = dynamic_cast(ir); + if (as_begin) { + for (auto& x : as_begin->forms) { + output->push_back(x->to_form(file)); + } + } else { + output->push_back(ir->to_form(file)); + } +} +} // namespace + +std::shared_ptr IR_WhileLoop::to_form(const LinkedObjectFile& file) const { + std::vector> list; + list.push_back(toForm("while")); + list.push_back(condition->to_form(file)); + print_inlining_begin(&list, body.get(), file); + return buildList(list); +} + +void IR_WhileLoop::get_children(std::vector>* output) const { + output->push_back(condition); + output->push_back(body); } \ No newline at end of file diff --git a/decompiler/IR/IR.h b/decompiler/IR/IR.h index e347afe9b5..1285a34857 100644 --- a/decompiler/IR/IR.h +++ b/decompiler/IR/IR.h @@ -2,6 +2,7 @@ #define JAK_IR_H #include +#include #include "decompiler/Disasm/Register.h" #include "decompiler/util/LispPrint.h" @@ -10,7 +11,9 @@ class LinkedObjectFile; class IR { public: virtual std::shared_ptr to_form(const LinkedObjectFile& file) const = 0; + std::vector> get_all_ir(LinkedObjectFile& file) const; std::string print(const LinkedObjectFile& file) const; + virtual void get_children(std::vector>* output) const = 0; bool is_basic_op = false; }; @@ -19,12 +22,14 @@ class IR_Failed : public IR { public: IR_Failed() = default; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_Register : public IR { public: IR_Register(Register _reg, int _instr_idx) : reg(_reg), instr_idx(_instr_idx) {} std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; Register reg; int instr_idx = -1; }; @@ -45,6 +50,7 @@ class IR_Set : public IR { IR_Set(Kind _kind, std::shared_ptr _dst, std::shared_ptr _src) : kind(_kind), dst(std::move(_dst)), src(std::move(_src)) {} std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; std::shared_ptr dst, src; std::shared_ptr clobber = nullptr; }; @@ -60,34 +66,38 @@ class IR_Store : public IR_Set { class IR_Symbol : public IR { public: - IR_Symbol(std::string _name) : name(std::move(_name)) {} + explicit IR_Symbol(std::string _name) : name(std::move(_name)) {} std::string name; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_SymbolValue : public IR { public: - IR_SymbolValue(std::string _name) : name(std::move(_name)) {} + explicit IR_SymbolValue(std::string _name) : name(std::move(_name)) {} std::string name; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_StaticAddress : public IR { public: - IR_StaticAddress(int _label_id) : label_id(_label_id) {} + explicit IR_StaticAddress(int _label_id) : label_id(_label_id) {} int label_id = -1; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_Load : public IR { public: enum Kind { UNSIGNED, SIGNED, FLOAT } kind; - IR_Load(Kind _kind, int _size, const std::shared_ptr& _location) - : kind(_kind), size(_size), location(_location) {} + IR_Load(Kind _kind, int _size, std::shared_ptr _location) + : kind(_kind), size(_size), location(std::move(_location)) {} int size; std::shared_ptr location; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_FloatMath2 : public IR { @@ -97,6 +107,7 @@ class IR_FloatMath2 : public IR { : kind(_kind), arg0(std::move(_arg0)), arg1(std::move(_arg1)) {} std::shared_ptr arg0, arg1; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_FloatMath1 : public IR { @@ -105,6 +116,7 @@ class IR_FloatMath1 : public IR { IR_FloatMath1(Kind _kind, std::shared_ptr _arg) : kind(_kind), arg(std::move(_arg)) {} std::shared_ptr arg; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_IntMath2 : public IR { @@ -130,6 +142,7 @@ class IR_IntMath2 : public IR { : kind(_kind), arg0(std::move(_arg0)), arg1(std::move(_arg1)) {} std::shared_ptr arg0, arg1; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_IntMath1 : public IR { @@ -138,12 +151,14 @@ class IR_IntMath1 : public IR { IR_IntMath1(Kind _kind, std::shared_ptr _arg) : kind(_kind), arg(std::move(_arg)) {} std::shared_ptr arg; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_Call : public IR { public: IR_Call() = default; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_IntegerConstant : public IR { @@ -151,13 +166,15 @@ class IR_IntegerConstant : public IR { int64_t value; explicit IR_IntegerConstant(int64_t _value) : value(_value) {} std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; struct BranchDelay { enum Kind { NOP, SET_REG_FALSE, SET_REG_TRUE, SET_REG_REG, UNKNOWN } kind; std::shared_ptr destination = nullptr, source = nullptr; - BranchDelay(Kind _kind) : kind(_kind) {} + explicit BranchDelay(Kind _kind) : kind(_kind) {} std::shared_ptr to_form(const LinkedObjectFile& file) const; + void get_children(std::vector>* output) const; }; struct Condition { @@ -201,6 +218,7 @@ struct Condition { int num_args() const; std::shared_ptr to_form(const LinkedObjectFile& file) const; std::shared_ptr src0, src1, clobber; + void get_children(std::vector>* output) const; }; class IR_Branch : public IR { @@ -217,6 +235,7 @@ class IR_Branch : public IR { bool likely; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_Compare : public IR { @@ -226,18 +245,38 @@ class IR_Compare : public IR { Condition condition; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_Nop : public IR { public: IR_Nop() = default; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; }; class IR_Suspend : public IR { public: IR_Suspend() = default; std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; +}; + +class IR_Begin : public IR { + public: + IR_Begin(const std::vector>& _forms) : forms(std::move(_forms)) {} + std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; + std::vector> forms; +}; + +class IR_WhileLoop : public IR { + public: + IR_WhileLoop(std::shared_ptr _condition, std::shared_ptr _body) + : condition(std::move(_condition)), body(std::move(_body)) {} + std::shared_ptr to_form(const LinkedObjectFile& file) const override; + void get_children(std::vector>* output) const override; + std::shared_ptr condition, body; }; #endif // JAK_IR_H diff --git a/decompiler/ObjectFile/LinkedObjectFile.cpp b/decompiler/ObjectFile/LinkedObjectFile.cpp index 6f4249bd7f..d96908afa7 100644 --- a/decompiler/ObjectFile/LinkedObjectFile.cpp +++ b/decompiler/ObjectFile/LinkedObjectFile.cpp @@ -622,6 +622,11 @@ std::string LinkedObjectFile::print_disassembly() { */ } + if (func.ir) { + result += ";; ir\n"; + result += func.ir->print(*this); + } + result += "\n\n\n"; } diff --git a/decompiler/ObjectFile/ObjectFileDB.cpp b/decompiler/ObjectFile/ObjectFileDB.cpp index 8bdcb184e4..3a96107e6e 100644 --- a/decompiler/ObjectFile/ObjectFileDB.cpp +++ b/decompiler/ObjectFile/ObjectFileDB.cpp @@ -19,6 +19,7 @@ #include "common/util/FileUtil.h" #include "decompiler/Function/BasicBlocks.h" #include "decompiler/IR/BasicOpBuilder.h" +#include "decompiler/IR/CfgBuilder.h" /*! * Get a unique name for this object file. @@ -602,6 +603,7 @@ void ObjectFileDB::analyze_functions() { timer.start(); int total_basic_blocks = 0; for_each_function([&](Function& func, int segment_id, ObjectFileData& data) { + // printf("in %s\n", func.guessed_name.to_string().c_str()); auto blocks = find_blocks_in_function(data.linked_data, segment_id, func); total_basic_blocks += blocks.size(); func.basic_blocks = blocks; @@ -618,6 +620,8 @@ void ObjectFileDB::analyze_functions() { total_basic_ops += func.get_basic_op_count(); total_failed_basic_ops += func.get_failed_basic_op_count(); + func.ir = build_cfg_ir(func, *func.cfg, data.linked_data); + if (func.cfg->is_fully_resolved()) { resolved_cfg_functions++; } diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index ee8b6740ca..e5f8d1e038 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -36,6 +36,12 @@ "resend-exception", "kernel-set-interrupt-vector", "kernel-set-exception-vector", "return-from-exception", "kernel-read", "kernel-read-function", "kernel-write", "kernel-write-function", "kernel-copy-to-kernel-ram", + "(method 11 cpu-thread)", "atan0", "sincos!", "sincos-rad!", "disasm-dma-list", "vblank-handler", "vif1-handler", + "vif1-handler-debug", "entity-actor-count", "decompress-frame-data-pair-to-accumulator", + "decompress-frame-data-to-accumulator", "normalize-frame-quaternions", "clear-frame-accumulator", + "generic-copy-vtx-dclr-dtex", "generic-no-light-dproc-only", "generic-no-light-proc", "mercneric-bittable-asm", + "generic-tie-decompress", + "collide-do-primitives", "draw-bones-check-longest-edge-asm", "sp-launch-particles-var", "(method 15 collide-shape-prim-mesh)", "(method 15 collide-shape-prim-sphere)", "(method 45 collide-shape)", "cam-layout-save-cam-trans", "kernel-copy-function", "dma-sync-hang", "generic-no-light-dproc",