mirror of
https://github.com/open-goal/jak-project
synced 2026-09-03 02:14:07 -04:00
add some more cfg ir stuff
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<IR> Function::get_basic_op_at_instr(int idx) {
|
||||
return basic_ops.at(instruction_to_basic_op.at(idx));
|
||||
}
|
||||
|
||||
int Function::get_basic_op_count() {
|
||||
|
||||
@@ -68,10 +68,12 @@ class Function {
|
||||
void add_basic_op(std::shared_ptr<IR> 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<IR> get_basic_op_at_instr(int idx);
|
||||
int get_basic_op_count();
|
||||
int get_failed_basic_op_count();
|
||||
|
||||
std::shared_ptr<IR> ir = nullptr;
|
||||
|
||||
int segment = -1;
|
||||
int start_word = -1;
|
||||
int end_word = -1; // not inclusive, but does include padding.
|
||||
|
||||
@@ -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<IR_Failed>(), instr, instr + 1);
|
||||
} else {
|
||||
func->add_basic_op(result, instr, instr + length);
|
||||
|
||||
@@ -0,0 +1,180 @@
|
||||
#include <unordered_set>
|
||||
#include "CfgBuilder.h"
|
||||
#include "decompiler/Function/CfgVtx.h"
|
||||
#include "decompiler/Function/Function.h"
|
||||
|
||||
std::vector<std::shared_ptr<IR>> IR::get_all_ir(LinkedObjectFile& file) const {
|
||||
std::vector<std::shared_ptr<IR>> 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<std::shared_ptr<IR>> unique_ir;
|
||||
for (auto& x : result) {
|
||||
unique_ir.insert(x);
|
||||
}
|
||||
assert(unique_ir.size() == result.size());
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::shared_ptr<IR> 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<std::shared_ptr<IR>>* output,
|
||||
CfgVtx* vtx) {
|
||||
auto as_sequence = dynamic_cast<SequenceVtx*>(vtx);
|
||||
auto as_block = dynamic_cast<BlockVtx*>(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<IR> cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx) {
|
||||
if (dynamic_cast<BlockVtx*>(vtx)) {
|
||||
auto* bv = dynamic_cast<BlockVtx*>(vtx);
|
||||
auto& block = f.basic_blocks.at(bv->block_id);
|
||||
std::vector<std::shared_ptr<IR>> 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<IR_Begin>(irs);
|
||||
}
|
||||
|
||||
} else if (dynamic_cast<SequenceVtx*>(vtx)) {
|
||||
auto* sv = dynamic_cast<SequenceVtx*>(vtx);
|
||||
|
||||
std::vector<std::shared_ptr<IR>> irs;
|
||||
insert_cfg_into_list(f, file, &irs, sv);
|
||||
|
||||
return std::make_shared<IR_Begin>(irs);
|
||||
} else if (dynamic_cast<WhileLoop*>(vtx)) {
|
||||
auto wvtx = dynamic_cast<WhileLoop*>(vtx);
|
||||
auto result = std::make_shared<IR_WhileLoop>(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<size_t> 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<IR_WhileLoop*>(sequence->forms.at(i).get());
|
||||
if (form_as_while) {
|
||||
assert(i != 0);
|
||||
auto prev_as_branch = dynamic_cast<IR_Branch*>(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<IR_Branch*>(form_as_while->condition.get());
|
||||
std::shared_ptr<IR>* condition_branch_location = &form_as_while->condition;
|
||||
if (!condition_branch) {
|
||||
// not 100% sure this will always work
|
||||
auto as_seq = dynamic_cast<IR_Begin*>(form_as_while->condition.get());
|
||||
if (as_seq) {
|
||||
condition_branch = dynamic_cast<IR_Branch*>(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<IR_Compare>(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<IR_Branch*>(sequence->forms.at(idx).get()));
|
||||
sequence->forms.erase(sequence->forms.begin() + idx);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::shared_ptr<IR> 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<IR_Begin*>(child.get());
|
||||
if (as_begin) {
|
||||
clean_up_while_loops(as_begin, file);
|
||||
}
|
||||
}
|
||||
return ir;
|
||||
} catch (std::runtime_error& e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
class IR;
|
||||
class Function;
|
||||
class LinkedObjectFile;
|
||||
class ControlFlowGraph;
|
||||
|
||||
std::shared_ptr<IR> build_cfg_ir(Function& function, ControlFlowGraph& cfg, LinkedObjectFile& file);
|
||||
+142
-5
@@ -5,15 +5,35 @@ std::string IR::print(const LinkedObjectFile& file) const {
|
||||
return to_form(file)->toStringPretty();
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Failed::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return buildList("INVALID-OPERATION");
|
||||
}
|
||||
|
||||
void IR_Failed::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Register::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return toForm(reg.to_charp());
|
||||
}
|
||||
|
||||
void IR_Register::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> 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<std::shared_ptr<IR>>* 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<Form> IR_Store::to_form(const LinkedObjectFile& file) const {
|
||||
std::string store_operator;
|
||||
switch (kind) {
|
||||
@@ -48,26 +68,33 @@ std::shared_ptr<Form> IR_Store::to_form(const LinkedObjectFile& file) const {
|
||||
return buildList(toForm(store_operator), dst->to_form(file), src->to_form(file));
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Failed::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return buildList("INVALID-OPERATION");
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Symbol::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return toForm("'" + name);
|
||||
}
|
||||
|
||||
void IR_Symbol::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_SymbolValue::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return toForm(name);
|
||||
}
|
||||
|
||||
void IR_SymbolValue::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> 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<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Load::to_form(const LinkedObjectFile& file) const {
|
||||
std::string load_operator;
|
||||
switch (kind) {
|
||||
@@ -116,6 +143,10 @@ std::shared_ptr<Form> IR_Load::to_form(const LinkedObjectFile& file) const {
|
||||
return buildList(toForm(load_operator), location->to_form(file));
|
||||
}
|
||||
|
||||
void IR_Load::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
output->push_back(location);
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_FloatMath2::to_form(const LinkedObjectFile& file) const {
|
||||
std::string math_operator;
|
||||
switch (kind) {
|
||||
@@ -144,6 +175,15 @@ std::shared_ptr<Form> 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<std::shared_ptr<IR>>* output) const {
|
||||
output->push_back(arg0);
|
||||
output->push_back(arg1);
|
||||
}
|
||||
|
||||
void IR_FloatMath1::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
output->push_back(arg);
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_IntMath2::to_form(const LinkedObjectFile& file) const {
|
||||
std::string math_operator;
|
||||
switch (kind) {
|
||||
@@ -198,6 +238,11 @@ std::shared_ptr<Form> 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<std::shared_ptr<IR>>* output) const {
|
||||
output->push_back(arg0);
|
||||
output->push_back(arg1);
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_IntMath1::to_form(const LinkedObjectFile& file) const {
|
||||
std::string math_operator;
|
||||
switch (kind) {
|
||||
@@ -210,6 +255,10 @@ std::shared_ptr<Form> IR_IntMath1::to_form(const LinkedObjectFile& file) const {
|
||||
return buildList(toForm(math_operator), arg->to_form(file));
|
||||
}
|
||||
|
||||
void IR_IntMath1::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
output->push_back(arg);
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_FloatMath1::to_form(const LinkedObjectFile& file) const {
|
||||
std::string math_operator;
|
||||
switch (kind) {
|
||||
@@ -239,11 +288,19 @@ std::shared_ptr<Form> IR_Call::to_form(const LinkedObjectFile& file) const {
|
||||
return buildList("call!");
|
||||
}
|
||||
|
||||
void IR_Call::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_IntegerConstant::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return toForm(std::to_string(value));
|
||||
}
|
||||
|
||||
void IR_IntegerConstant::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> BranchDelay::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
switch (kind) {
|
||||
@@ -262,6 +319,16 @@ std::shared_ptr<Form> BranchDelay::to_form(const LinkedObjectFile& file) const {
|
||||
}
|
||||
}
|
||||
|
||||
void BranchDelay::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
if (destination) {
|
||||
output->push_back(destination);
|
||||
}
|
||||
|
||||
if (source) {
|
||||
output->push_back(source);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> 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<std::shared_ptr<IR>>* output) const {
|
||||
if (src0) {
|
||||
output->push_back(src0);
|
||||
}
|
||||
|
||||
if (src1) {
|
||||
output->push_back(src1);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> Condition::to_form(const LinkedObjectFile& file) const {
|
||||
int nargs = num_args();
|
||||
std::string condtion_operator;
|
||||
@@ -381,11 +458,71 @@ std::shared_ptr<Form> 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<std::shared_ptr<IR>>* output) const {
|
||||
condition.get_children(output);
|
||||
branch_delay.get_children(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Compare::to_form(const LinkedObjectFile& file) const {
|
||||
return condition.to_form(file);
|
||||
}
|
||||
|
||||
void IR_Compare::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
condition.get_children(output);
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Suspend::to_form(const LinkedObjectFile& file) const {
|
||||
(void)file;
|
||||
return buildList("suspend!");
|
||||
}
|
||||
|
||||
void IR_Nop::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
void IR_Suspend::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
(void)output;
|
||||
}
|
||||
|
||||
std::shared_ptr<Form> IR_Begin::to_form(const LinkedObjectFile& file) const {
|
||||
std::vector<std::shared_ptr<Form>> 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<std::shared_ptr<IR>>* output) const {
|
||||
for (auto& x : forms) {
|
||||
output->push_back(x);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void print_inlining_begin(std::vector<std::shared_ptr<Form>>* output,
|
||||
IR* ir,
|
||||
const LinkedObjectFile& file) {
|
||||
auto as_begin = dynamic_cast<IR_Begin*>(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<Form> IR_WhileLoop::to_form(const LinkedObjectFile& file) const {
|
||||
std::vector<std::shared_ptr<Form>> 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<std::shared_ptr<IR>>* output) const {
|
||||
output->push_back(condition);
|
||||
output->push_back(body);
|
||||
}
|
||||
+45
-6
@@ -2,6 +2,7 @@
|
||||
#define JAK_IR_H
|
||||
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include "decompiler/Disasm/Register.h"
|
||||
#include "decompiler/util/LispPrint.h"
|
||||
|
||||
@@ -10,7 +11,9 @@ class LinkedObjectFile;
|
||||
class IR {
|
||||
public:
|
||||
virtual std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const = 0;
|
||||
std::vector<std::shared_ptr<IR>> get_all_ir(LinkedObjectFile& file) const;
|
||||
std::string print(const LinkedObjectFile& file) const;
|
||||
virtual void get_children(std::vector<std::shared_ptr<IR>>* output) const = 0;
|
||||
|
||||
bool is_basic_op = false;
|
||||
};
|
||||
@@ -19,12 +22,14 @@ class IR_Failed : public IR {
|
||||
public:
|
||||
IR_Failed() = default;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<IR> _dst, std::shared_ptr<IR> _src)
|
||||
: kind(_kind), dst(std::move(_dst)), src(std::move(_src)) {}
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
std::shared_ptr<IR> dst, src;
|
||||
std::shared_ptr<IR> 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<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<IR>& _location)
|
||||
: kind(_kind), size(_size), location(_location) {}
|
||||
IR_Load(Kind _kind, int _size, std::shared_ptr<IR> _location)
|
||||
: kind(_kind), size(_size), location(std::move(_location)) {}
|
||||
int size;
|
||||
std::shared_ptr<IR> location;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<IR> arg0, arg1;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_FloatMath1 : public IR {
|
||||
@@ -105,6 +116,7 @@ class IR_FloatMath1 : public IR {
|
||||
IR_FloatMath1(Kind _kind, std::shared_ptr<IR> _arg) : kind(_kind), arg(std::move(_arg)) {}
|
||||
std::shared_ptr<IR> arg;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<IR> arg0, arg1;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_IntMath1 : public IR {
|
||||
@@ -138,12 +151,14 @@ class IR_IntMath1 : public IR {
|
||||
IR_IntMath1(Kind _kind, std::shared_ptr<IR> _arg) : kind(_kind), arg(std::move(_arg)) {}
|
||||
std::shared_ptr<IR> arg;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_Call : public IR {
|
||||
public:
|
||||
IR_Call() = default;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* 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<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
struct BranchDelay {
|
||||
enum Kind { NOP, SET_REG_FALSE, SET_REG_TRUE, SET_REG_REG, UNKNOWN } kind;
|
||||
std::shared_ptr<IR> destination = nullptr, source = nullptr;
|
||||
BranchDelay(Kind _kind) : kind(_kind) {}
|
||||
explicit BranchDelay(Kind _kind) : kind(_kind) {}
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const;
|
||||
};
|
||||
|
||||
struct Condition {
|
||||
@@ -201,6 +218,7 @@ struct Condition {
|
||||
int num_args() const;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const;
|
||||
std::shared_ptr<IR> src0, src1, clobber;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const;
|
||||
};
|
||||
|
||||
class IR_Branch : public IR {
|
||||
@@ -217,6 +235,7 @@ class IR_Branch : public IR {
|
||||
bool likely;
|
||||
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_Compare : public IR {
|
||||
@@ -226,18 +245,38 @@ class IR_Compare : public IR {
|
||||
Condition condition;
|
||||
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_Nop : public IR {
|
||||
public:
|
||||
IR_Nop() = default;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_Suspend : public IR {
|
||||
public:
|
||||
IR_Suspend() = default;
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
class IR_Begin : public IR {
|
||||
public:
|
||||
IR_Begin(const std::vector<std::shared_ptr<IR>>& _forms) : forms(std::move(_forms)) {}
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
std::vector<std::shared_ptr<IR>> forms;
|
||||
};
|
||||
|
||||
class IR_WhileLoop : public IR {
|
||||
public:
|
||||
IR_WhileLoop(std::shared_ptr<IR> _condition, std::shared_ptr<IR> _body)
|
||||
: condition(std::move(_condition)), body(std::move(_body)) {}
|
||||
std::shared_ptr<Form> to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
std::shared_ptr<IR> condition, body;
|
||||
};
|
||||
|
||||
#endif // JAK_IR_H
|
||||
|
||||
@@ -622,6 +622,11 @@ std::string LinkedObjectFile::print_disassembly() {
|
||||
*/
|
||||
}
|
||||
|
||||
if (func.ir) {
|
||||
result += ";; ir\n";
|
||||
result += func.ir->print(*this);
|
||||
}
|
||||
|
||||
result += "\n\n\n";
|
||||
}
|
||||
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user