mirror of
https://github.com/open-goal/jak-project
synced 2026-07-27 06:45:56 -04:00
Cleanup PR
This commit is contained in:
@@ -522,6 +522,17 @@ std::shared_ptr<IR> try_dsrav(Instruction& instr, int idx) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<IR> try_dsrlv(Instruction& instr, int idx) {
|
||||
if (is_gpr_3(instr, InstructionKind::DSRLV, {}, {}, {}) &&
|
||||
!instr.get_src(0).is_reg(make_gpr(Reg::S7)) && !instr.get_src(1).is_reg(make_gpr(Reg::S7))) {
|
||||
return make_set(IR_Set::REG_64, make_reg(instr.get_dst(0).get_reg(), idx),
|
||||
std::make_shared<IR_IntMath2>(IR_IntMath2::RIGHT_SHIFT_LOGIC,
|
||||
make_reg(instr.get_src(0).get_reg(), idx),
|
||||
make_reg(instr.get_src(1).get_reg(), idx)));
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<IR> try_sw(Instruction& instr, int idx) {
|
||||
if (instr.kind == InstructionKind::SW && instr.get_src(1).is_sym() &&
|
||||
instr.get_src(2).is_reg(make_gpr(Reg::S7))) {
|
||||
@@ -1208,6 +1219,7 @@ std::shared_ptr<IR> 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);
|
||||
|
||||
@@ -1469,6 +1481,9 @@ void add_basic_ops_to_block(Function* func, const BasicBlock& block, LinkedObjec
|
||||
case InstructionKind::DSRAV:
|
||||
result = try_dsrav(i, instr);
|
||||
break;
|
||||
case InstructionKind::DSRLV:
|
||||
result = try_dsrlv(i, instr);
|
||||
break;
|
||||
default:
|
||||
result = nullptr;
|
||||
}
|
||||
|
||||
+225
-11
@@ -107,6 +107,7 @@ void clean_up_cond_with_else(std::shared_ptr<IR>* ir, LinkedObjectFile& file) {
|
||||
assert(jump_to_next.first->branch_delay.kind == BranchDelay::NOP);
|
||||
// patch the jump to next with a condition.
|
||||
auto replacement = std::make_shared<IR_Compare>(jump_to_next.first->condition);
|
||||
replacement->condition.invert();
|
||||
*(jump_to_next.second) = replacement;
|
||||
|
||||
// patch the jump at the end of a block.
|
||||
@@ -133,6 +134,208 @@ void clean_up_cond_with_else(std::shared_ptr<IR>* ir, LinkedObjectFile& file) {
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Does the instruction in the delay slot set a register to false?
|
||||
* Note. a beql s7, x followed by a or y, x, r0 will count as this. I don't know why but
|
||||
* GOAL does this on comparisons to false.
|
||||
*/
|
||||
bool delay_slot_sets_false(IR_Branch* branch) {
|
||||
if (branch->branch_delay.kind == BranchDelay::SET_REG_FALSE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (branch->condition.kind == Condition::FALSE &&
|
||||
branch->branch_delay.kind == BranchDelay::SET_REG_REG) {
|
||||
auto reg_check = dynamic_cast<IR_Register*>(branch->condition.src0.get());
|
||||
assert(reg_check);
|
||||
auto reg_read = dynamic_cast<IR_Register*>(branch->branch_delay.source.get());
|
||||
assert(reg_read);
|
||||
return reg_check->reg == reg_read->reg;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Does the instruction in the delay slot set a register to a truthy value, like in a GOAL
|
||||
* or form branch? Either it explicitly sets #t, or it tests the value for being not false,
|
||||
* then uses that
|
||||
*/
|
||||
bool delay_slot_sets_truthy(IR_Branch* branch) {
|
||||
if (branch->branch_delay.kind == BranchDelay::SET_REG_TRUE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (branch->condition.kind == Condition::TRUTHY &&
|
||||
branch->branch_delay.kind == BranchDelay::SET_REG_REG) {
|
||||
auto reg_check = dynamic_cast<IR_Register*>(branch->condition.src0.get());
|
||||
assert(reg_check);
|
||||
auto reg_read = dynamic_cast<IR_Register*>(branch->branch_delay.source.get());
|
||||
assert(reg_read);
|
||||
return reg_check->reg == reg_read->reg;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Try to convert a short circuit to an and.
|
||||
*/
|
||||
bool try_clean_up_sc_as_and(std::shared_ptr<IR_ShortCircuit>& ir, LinkedObjectFile& file) {
|
||||
(void)file;
|
||||
Register destination;
|
||||
std::shared_ptr<IR> ir_dest = nullptr;
|
||||
for (int i = 0; i < int(ir->entries.size()) - 1; i++) {
|
||||
auto branch = get_condition_branch(&ir->entries.at(i).condition);
|
||||
assert(branch.first);
|
||||
if (!delay_slot_sets_false(branch.first)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
ir_dest = branch.first->branch_delay.destination;
|
||||
destination = dynamic_cast<IR_Register*>(branch.first->branch_delay.destination.get())->reg;
|
||||
} else {
|
||||
if (destination !=
|
||||
dynamic_cast<IR_Register*>(branch.first->branch_delay.destination.get())->reg) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ir->kind = IR_ShortCircuit::AND;
|
||||
ir->final_result = ir_dest;
|
||||
|
||||
// now get rid of the branches
|
||||
for (int i = 0; i < int(ir->entries.size()) - 1; i++) {
|
||||
auto branch = get_condition_branch(&ir->entries.at(i).condition);
|
||||
assert(branch.first);
|
||||
auto replacement = std::make_shared<IR_Compare>(branch.first->condition);
|
||||
replacement->condition.invert();
|
||||
*(branch.second) = replacement;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Try to convert a short circuit to an or.
|
||||
* Note - this will convert an and to a very strange or, so always use the try as and first.
|
||||
*/
|
||||
bool try_clean_up_sc_as_or(std::shared_ptr<IR_ShortCircuit>& ir, LinkedObjectFile& file) {
|
||||
(void)file;
|
||||
Register destination;
|
||||
std::shared_ptr<IR> ir_dest = nullptr;
|
||||
for (int i = 0; i < int(ir->entries.size()) - 1; i++) {
|
||||
auto branch = get_condition_branch(&ir->entries.at(i).condition);
|
||||
assert(branch.first);
|
||||
if (!delay_slot_sets_truthy(branch.first)) {
|
||||
return false;
|
||||
}
|
||||
assert(dynamic_cast<IR_Register*>(branch.first->branch_delay.destination.get()));
|
||||
|
||||
if (i == 0) {
|
||||
ir_dest = branch.first->branch_delay.destination;
|
||||
destination = dynamic_cast<IR_Register*>(branch.first->branch_delay.destination.get())->reg;
|
||||
} else {
|
||||
if (destination !=
|
||||
dynamic_cast<IR_Register*>(branch.first->branch_delay.destination.get())->reg) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ir->kind = IR_ShortCircuit::OR;
|
||||
ir->final_result = ir_dest;
|
||||
|
||||
for (int i = 0; i < int(ir->entries.size()) - 1; i++) {
|
||||
auto branch = get_condition_branch(&ir->entries.at(i).condition);
|
||||
assert(branch.first);
|
||||
auto replacement = std::make_shared<IR_Compare>(branch.first->condition);
|
||||
*(branch.second) = replacement;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void clean_up_sc(std::shared_ptr<IR_ShortCircuit>& ir, LinkedObjectFile& file);
|
||||
|
||||
/*!
|
||||
* A form like (and x (or y z)) will be recognized as a single SC Vertex by the CFG pass.
|
||||
* In the case where we fail to clean it up as an AND or an OR, we should attempt splitting.
|
||||
* Part of the complexity here is that we want to clean up the split recursively so things like
|
||||
* (and x (or y (and a b)))
|
||||
* or
|
||||
* (and x (or y (and a b)) c d (or z))
|
||||
* will work correctly. This may require doing more splitting on both sections!
|
||||
*/
|
||||
bool try_splitting_nested_sc(std::shared_ptr<IR_ShortCircuit>& ir, LinkedObjectFile& file) {
|
||||
auto first_branch = get_condition_branch(&ir->entries.front().condition);
|
||||
assert(first_branch.first);
|
||||
bool first_is_and = delay_slot_sets_false(first_branch.first);
|
||||
bool first_is_or = delay_slot_sets_truthy(first_branch.first);
|
||||
assert(first_is_and != first_is_or); // one or the other but not both!
|
||||
|
||||
int first_different = -1; // the index of the first one that's different.
|
||||
|
||||
for (int i = 1; i < int(ir->entries.size()) - 1; i++) {
|
||||
auto branch = get_condition_branch(&ir->entries.at(i).condition);
|
||||
assert(branch.first);
|
||||
bool is_and = delay_slot_sets_false(branch.first);
|
||||
bool is_or = delay_slot_sets_truthy(branch.first);
|
||||
assert(is_and != is_or);
|
||||
|
||||
if (first_different == -1) {
|
||||
// haven't seen a change yet.
|
||||
if (first_is_and != is_and) {
|
||||
// change!
|
||||
first_different = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(first_different != -1);
|
||||
|
||||
std::vector<IR_ShortCircuit::Entry> nested_ir;
|
||||
for (int i = first_different; i < int(ir->entries.size()); i++) {
|
||||
nested_ir.push_back(ir->entries.at(i));
|
||||
}
|
||||
|
||||
auto s = int(ir->entries.size());
|
||||
for (int i = first_different; i < s; i++) {
|
||||
ir->entries.pop_back();
|
||||
}
|
||||
|
||||
auto nested_sc = std::make_shared<IR_ShortCircuit>(nested_ir);
|
||||
clean_up_sc(nested_sc, file);
|
||||
|
||||
// the real trick
|
||||
IR_ShortCircuit::Entry nested_entry;
|
||||
nested_entry.condition = nested_sc;
|
||||
ir->entries.push_back(nested_entry);
|
||||
|
||||
clean_up_sc(ir, file);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Try to clean up a single short circuit IR. It may get split up into nested IR_ShortCircuits
|
||||
* if there is a case like (and a (or b c))
|
||||
*/
|
||||
void clean_up_sc(std::shared_ptr<IR_ShortCircuit>& ir, LinkedObjectFile& file) {
|
||||
(void)file;
|
||||
assert(ir->entries.size() > 1);
|
||||
if (!try_clean_up_sc_as_and(ir, file)) {
|
||||
if (!try_clean_up_sc_as_or(ir, file)) {
|
||||
if (!try_splitting_nested_sc(ir, file)) {
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* A GOAL comparison which produces a boolean is recognized as a cond-no-else by the CFG analysis.
|
||||
* But it should not be decompiled as a branching statement.
|
||||
@@ -153,11 +356,6 @@ void convert_cond_no_else_to_compare(std::shared_ptr<IR>* ir) {
|
||||
|
||||
auto condition_as_single = dynamic_cast<IR_Branch*>(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>(
|
||||
IR_Set::REG_64, dst, std::make_shared<IR_Compare>(condition.first->condition));
|
||||
*ir = replacement;
|
||||
@@ -186,6 +384,7 @@ void convert_cond_no_else_to_compare(std::shared_ptr<IR>* ir) {
|
||||
* this.
|
||||
*/
|
||||
void clean_up_cond_no_else(std::shared_ptr<IR>* ir, LinkedObjectFile& file) {
|
||||
(void)file;
|
||||
auto cne = dynamic_cast<IR_Cond*>(ir->get());
|
||||
assert(cne);
|
||||
for (size_t idx = 0; idx < cne->entries.size(); idx++) {
|
||||
@@ -212,6 +411,7 @@ void clean_up_cond_no_else(std::shared_ptr<IR>* ir, LinkedObjectFile& file) {
|
||||
}
|
||||
|
||||
auto replacement = std::make_shared<IR_Compare>(jump_to_next.first->condition);
|
||||
replacement->condition.invert();
|
||||
*(jump_to_next.second) = replacement;
|
||||
e.cleaned = true;
|
||||
|
||||
@@ -282,12 +482,19 @@ bool is_int_math_3(IR* ir,
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Are these IR's both the same register? False if either is not a register.
|
||||
*/
|
||||
bool is_same_reg(IR* a, IR* b) {
|
||||
auto ar = dynamic_cast<IR_Register*>(a);
|
||||
auto br = dynamic_cast<IR_Register*>(b);
|
||||
return ar && br && ar->reg == br->reg;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Try to convert this SC Vertex into an abs (integer).
|
||||
* Will return a converted abs IR if successful, or nullptr if its not possible
|
||||
*/
|
||||
std::shared_ptr<IR> try_sc_as_abs(Function& f, LinkedObjectFile& file, ShortCircuit* vtx) {
|
||||
if (vtx->entries.size() != 1) {
|
||||
return nullptr;
|
||||
@@ -344,7 +551,7 @@ std::shared_ptr<IR> 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<BlockVtx*>(vtx->entries.at(0));
|
||||
auto b0 = dynamic_cast<CfgVtx*>(vtx->entries.at(0));
|
||||
auto b1 = dynamic_cast<BlockVtx*>(vtx->entries.at(1));
|
||||
if (!b0 || !b1) {
|
||||
return nullptr;
|
||||
@@ -399,8 +606,13 @@ std::shared_ptr<IR> 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)) {
|
||||
|
||||
bool is_arith = is_int_math_3(dsrav_candidate.get(), IR_IntMath2::RIGHT_SHIFT_ARITH, result->reg,
|
||||
value_in->reg, clobber);
|
||||
bool is_logical = is_int_math_3(dsrav_candidate.get(), IR_IntMath2::RIGHT_SHIFT_LOGIC,
|
||||
result->reg, value_in->reg, clobber);
|
||||
|
||||
if (!is_arith && !is_logical) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -422,7 +634,8 @@ std::shared_ptr<IR> 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>(
|
||||
IR_Set::REG_64, dest_ir, std::make_shared<IR_Ash>(shift_ir, value_ir, clobber_ir)));
|
||||
IR_Set::REG_64, dest_ir,
|
||||
std::make_shared<IR_Ash>(shift_ir, value_ir, clobber_ir, is_arith)));
|
||||
return b0_ptr;
|
||||
}
|
||||
|
||||
@@ -453,7 +666,7 @@ std::shared_ptr<IR> try_sc_as_type_of(Function& f, LinkedObjectFile& file, Short
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto b0 = dynamic_cast<BlockVtx*>(vtx->entries.at(0));
|
||||
auto b0 = dynamic_cast<CfgVtx*>(vtx->entries.at(0));
|
||||
auto b1 = dynamic_cast<BlockVtx*>(vtx->entries.at(1));
|
||||
auto b2 = dynamic_cast<BlockVtx*>(vtx->entries.at(2));
|
||||
|
||||
@@ -698,6 +911,7 @@ std::shared_ptr<IR> cfg_to_ir(Function& f, LinkedObjectFile& file, CfgVtx* vtx)
|
||||
entries.push_back(e);
|
||||
}
|
||||
auto result = std::make_shared<IR_ShortCircuit>(entries);
|
||||
clean_up_sc(result, file);
|
||||
// todo clean these into real and/or.
|
||||
return result;
|
||||
} else if (dynamic_cast<CondNoElse*>(vtx)) {
|
||||
@@ -795,4 +1009,4 @@ std::shared_ptr<IR> build_cfg_ir(Function& function,
|
||||
} catch (std::runtime_error& e) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -793,8 +793,8 @@ void IR_ShortCircuit::get_children(std::vector<std::shared_ptr<IR>>* 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));
|
||||
return pretty_print::build_list(pretty_print::to_symbol(is_signed ? "ash.si" : "ash.ui"),
|
||||
value->to_form(file), shift_amount->to_form(file));
|
||||
}
|
||||
|
||||
void IR_Ash::get_children(std::vector<std::shared_ptr<IR>>* output) const {
|
||||
|
||||
+5
-2
@@ -357,12 +357,15 @@ class IR_ShortCircuit : public IR {
|
||||
class IR_Ash : public IR {
|
||||
public:
|
||||
std::shared_ptr<IR> shift_amount, value, clobber;
|
||||
bool is_signed = true;
|
||||
IR_Ash(std::shared_ptr<IR> _shift_amount,
|
||||
std::shared_ptr<IR> _value,
|
||||
std::shared_ptr<IR> _clobber)
|
||||
std::shared_ptr<IR> _clobber,
|
||||
bool _is_signed)
|
||||
: shift_amount(std::move(_shift_amount)),
|
||||
value(std::move(_value)),
|
||||
clobber(std::move(_clobber)) {}
|
||||
clobber(std::move(_clobber)),
|
||||
is_signed(_is_signed) {}
|
||||
goos::Object to_form(const LinkedObjectFile& file) const override;
|
||||
void get_children(std::vector<std::shared_ptr<IR>>* output) const override;
|
||||
};
|
||||
|
||||
@@ -592,13 +592,13 @@ 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 asm_funcs = 0;
|
||||
int non_asm_funcs = 0;
|
||||
int successful_cfg_irs = 0;
|
||||
|
||||
std::map<int, std::vector<std::string>> unresolved_by_length;
|
||||
@@ -624,7 +624,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++;
|
||||
non_asm_funcs++;
|
||||
if (func.ir) {
|
||||
successful_cfg_irs++;
|
||||
}
|
||||
@@ -633,13 +633,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 +646,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 +659,19 @@ 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));
|
||||
non_asm_funcs, 100.f * float(resolved_cfg_functions) / float(non_asm_funcs));
|
||||
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));
|
||||
printf(" %d/%d cfgs converted to ir (%.2f%%)\n", successful_cfg_irs, non_asm_funcs,
|
||||
100.f * float(successful_cfg_irs) / float(non_asm_funcs));
|
||||
|
||||
// for (auto& kv : unresolved_by_length) {
|
||||
// printf("LEN %d\n", kv.first);
|
||||
|
||||
@@ -1,72 +1,94 @@
|
||||
|
||||
|
||||
{
|
||||
"game_version":1,
|
||||
// the order here matters. KERNEL and GAME should go first
|
||||
"dgo_names":["CGO/KERNEL.CGO", "CGO/GAME.CGO"],
|
||||
/*, "CGO/ENGINE.CGO"
|
||||
, "CGO/ART.CGO", "DGO/BEA.DGO", "DGO/CIT.DGO", "CGO/COMMON.CGO", "DGO/DAR.DGO", "DGO/DEM.DGO",
|
||||
"DGO/FIN.DGO", "DGO/INT.DGO", "DGO/JUB.DGO", "DGO/JUN.DGO", "CGO/JUNGLE.CGO", "CGO/L1.CGO", "DGO/FIC.DGO",
|
||||
"DGO/LAV.DGO", "DGO/MAI.DGO", "CGO/MAINCAVE.CGO", "DGO/MIS.DGO", "DGO/OGR.DGO", "CGO/RACERP.CGO", "DGO/ROB.DGO", "DGO/ROL.DGO",
|
||||
"DGO/SNO.DGO", "DGO/SUB.DGO", "DGO/SUN.DGO", "CGO/SUNKEN.CGO", "DGO/SWA.DGO", "DGO/TIT.DGO", "DGO/TRA.DGO", "DGO/VI1.DGO",
|
||||
"DGO/VI2.DGO", "DGO/VI3.DGO", "CGO/VILLAGEP.CGO", "CGO/WATER-AN.CGO"
|
||||
],*/
|
||||
"game_version" : 1,
|
||||
// the order here matters. KERNEL and GAME should go first
|
||||
"dgo_names"
|
||||
: [ "CGO/KERNEL.CGO", "CGO/GAME.CGO" ],
|
||||
/*, "CGO/ENGINE.CGO"
|
||||
, "CGO/ART.CGO", "DGO/BEA.DGO", "DGO/CIT.DGO", "CGO/COMMON.CGO", "DGO/DAR.DGO",
|
||||
"DGO/DEM.DGO", "DGO/FIN.DGO", "DGO/INT.DGO", "DGO/JUB.DGO", "DGO/JUN.DGO",
|
||||
"CGO/JUNGLE.CGO", "CGO/L1.CGO", "DGO/FIC.DGO", "DGO/LAV.DGO", "DGO/MAI.DGO",
|
||||
"CGO/MAINCAVE.CGO", "DGO/MIS.DGO", "DGO/OGR.DGO", "CGO/RACERP.CGO", "DGO/ROB.DGO",
|
||||
"DGO/ROL.DGO", "DGO/SNO.DGO", "DGO/SUB.DGO", "DGO/SUN.DGO", "CGO/SUNKEN.CGO",
|
||||
"DGO/SWA.DGO", "DGO/TIT.DGO", "DGO/TRA.DGO", "DGO/VI1.DGO", "DGO/VI2.DGO", "DGO/VI3.DGO",
|
||||
"CGO/VILLAGEP.CGO", "CGO/WATER-AN.CGO"
|
||||
],*/
|
||||
|
||||
"write_disassembly":true,
|
||||
"write_hex_near_instructions":false,
|
||||
// if false, skips disassembling object files without functions, as these are usually large and not interesting yet.
|
||||
"disassemble_objects_without_functions":false,
|
||||
"write_disassembly" : true,
|
||||
"write_hex_near_instructions"
|
||||
: false,
|
||||
// if false, skips disassembling object files without functions, as these are usually large
|
||||
// and not interesting yet.
|
||||
"disassemble_objects_without_functions" : false,
|
||||
|
||||
// to write out data of each object file
|
||||
"write_hexdump":false,
|
||||
// to write out hexdump on the v3 only, to avoid the huge level data files
|
||||
"write_hexdump_on_v3_only":true,
|
||||
// to write out data of each object file
|
||||
"write_hexdump"
|
||||
: false,
|
||||
// to write out hexdump on the v3 only, to avoid the huge level data files
|
||||
"write_hexdump_on_v3_only"
|
||||
: true,
|
||||
|
||||
// to write out "scripts", which are currently just all the linked lists found
|
||||
"write_scripts":true,
|
||||
// to write out "scripts", which are currently just all the linked lists found
|
||||
"write_scripts" : true,
|
||||
|
||||
// Experimental Stuff
|
||||
"find_basic_blocks":true,
|
||||
// Experimental Stuff
|
||||
"find_basic_blocks" : true,
|
||||
|
||||
"asm_functions_by_name":[
|
||||
"asm_functions_by_name"
|
||||
: [
|
||||
// gcommon
|
||||
"min", "max", "(method 2 vec4s)", "quad-copy!", "(method 3 vec4s)", "breakpoint-range-set!",
|
||||
|
||||
// pskernel
|
||||
"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",
|
||||
"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",
|
||||
|
||||
// this one needs more investigation. nothing looks weird about it but it fails...
|
||||
"camera-change-to",
|
||||
|
||||
// this one fails due to false compaction where an else case has only a not expression in it.
|
||||
// two back to back arithmetic shifts...
|
||||
"texture-relocate",
|
||||
|
||||
// this one fails due to false compaction where an else case has only a not expression in
|
||||
// it.
|
||||
"master-is-hopeful-better?",
|
||||
|
||||
// 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)",
|
||||
// merged right typecase... can probably handle this
|
||||
"cspace-inspect-tree",
|
||||
|
||||
// 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)",
|
||||
|
||||
// real asm
|
||||
"cspace<-parented-transformq-joint!", "blerc-a-fragment", "render-boundary-tri", "render-boundary-quad",
|
||||
"(method 19 collide-shape-prim-sphere)","vector-segment-distance-point!", "exp", "(method 11 collide-mesh-cache)",
|
||||
"cspace<-parented-transformq-joint!", "blerc-a-fragment", "render-boundary-tri",
|
||||
"render-boundary-quad", "(method 19 collide-shape-prim-sphere)",
|
||||
"vector-segment-distance-point!", "exp", "(method 11 collide-mesh-cache)",
|
||||
"(method 13 collide-edge-work)", "ambient-inspect",
|
||||
|
||||
"(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", "matrix-axis-sin-cos!", "matrix-axis-sin-cos-vu!", "generic-prepare-dma-single",
|
||||
"(method 13 collide-shape-prim-sphere)", "(method 14 collide-shape-prim-sphere)", "(method 12 collide-shape-prim-sphere)",
|
||||
"adgif-shader<-texture-with-update!", "generic-interp-dproc", "sprite-draw-distorters", "draw-bones", "(method 9 collide-mesh-cache)",
|
||||
"(method 18 collide-shape-prim-sphere)","birth-pickup-at-point",
|
||||
"(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", "matrix-axis-sin-cos!", "matrix-axis-sin-cos-vu!",
|
||||
"generic-prepare-dma-single", "(method 13 collide-shape-prim-sphere)",
|
||||
"(method 14 collide-shape-prim-sphere)", "(method 12 collide-shape-prim-sphere)",
|
||||
"adgif-shader<-texture-with-update!", "generic-interp-dproc", "sprite-draw-distorters",
|
||||
"draw-bones", "(method 9 collide-mesh-cache)", "(method 18 collide-shape-prim-sphere)",
|
||||
"birth-pickup-at-point",
|
||||
|
||||
"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",
|
||||
"dma-sync-fast", "bsp-camera-asm",
|
||||
"generic-none-dma-wait", "unpack-comp-rle", "level-remap-texture", "(method 10 collide-edge-hold-list)"
|
||||
]
|
||||
}
|
||||
"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", "dma-sync-fast", "bsp-camera-asm",
|
||||
"generic-none-dma-wait", "unpack-comp-rle", "level-remap-texture",
|
||||
"(method 10 collide-edge-hold-list)"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user