[decomp] better handling of animation code and art files (#1352)

* update refs

* [decompiler] read and process art groups

* finish decompiler art group selection & detect in `ja-group?`

* make art stuff work on offline tests!

* [decompiler] detect `ja-group!` (primitive)

* corrections.

* more

* use new feature on skel groups!

* find `loop!` as well

* fully fledged `ja` macro & decomp + `loop` detect

* fancy fixed point printing!

* update source

* `:num! max` (i knew i should've done this)

* Update jak1_ntsc_black_label.jsonc

* hi imports

* make compiling the game work

* fix `defskelgroup`

* clang

* update refs

* fix chan

* fix seek and finalboss

* fix tests

* delete unused function

* track let rewrite stats

* reorder `rewrite_let`

* Update .gitattributes

* fix bug with `:num! max`

* Update robotboss-part.gc

* Update goal-lib.gc

* document `ja`

* get rid of pc fixes thing

* use std::abs
This commit is contained in:
ManDude
2022-05-20 02:30:14 +01:00
committed by GitHub
parent 971a69e15c
commit 0212aa10c9
786 changed files with 21658 additions and 49501 deletions
+53 -22
View File
@@ -58,26 +58,28 @@ void ObjectFileDB::analyze_functions_ir2(
ir2_do_segment_analysis_phase1(MAIN_SEGMENT, config, data);
ir2_setup_labels(config, data);
ir2_do_segment_analysis_phase2(TOP_LEVEL_SEGMENT, config, data);
try {
if (data.linked_data.functions_by_seg.size() == 3) {
if (data.linked_data.functions_by_seg.size() == 3) {
enum { DEFPART, DEFSTATE, DEFSKELGROUP } step = DEFPART;
try {
run_defpartgroup(data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).front());
}
} catch (const std::exception& e) {
lg::error("Failed to find defpartgroups: {}", e.what());
}
try {
if (data.linked_data.functions_by_seg.size() == 3) {
step = DEFSTATE;
run_defstate(data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).front(), skip_states);
}
} catch (const std::exception& e) {
lg::error("Failed to find defstates: {}", e.what());
}
try {
if (data.linked_data.functions_by_seg.size() == 3) {
step = DEFSKELGROUP;
run_defskelgroups(data.linked_data.functions_by_seg.at(TOP_LEVEL_SEGMENT).front());
} catch (const std::exception& e) {
switch (step) {
case DEFPART:
lg::error("Failed to find defpartgroups: {}", e.what());
break;
case DEFSTATE:
lg::error("Failed to find defstates: {}", e.what());
break;
case DEFSKELGROUP:
lg::error("Failed to find defskelgroups: {}", e.what());
break;
}
}
} catch (const std::exception& e) {
lg::error("Failed to find defskelgroups: {}", e.what());
}
ir2_do_segment_analysis_phase2(DEBUG_SEGMENT, config, data);
ir2_do_segment_analysis_phase2(MAIN_SEGMENT, config, data);
@@ -104,6 +106,20 @@ void ObjectFileDB::analyze_functions_ir2(
fmt::print("Done in {:.2f}ms\n", file_timer.getMs());
});
int total = stats.let.total();
lg::info("LET REWRITE STATS: {} total", total);
lg::info(" dotimes: {}", stats.let.dotimes);
lg::info(" countdown: {}", stats.let.countdown);
lg::info(" abs: {}", stats.let.abs);
lg::info(" abs2: {}", stats.let.abs2);
lg::info(" ja: {}", stats.let.ja);
lg::info(" set_vector: {}", stats.let.set_vector);
lg::info(" set_vector2: {}", stats.let.set_vector2);
lg::info(" case_no_else: {}", stats.let.case_no_else);
lg::info(" case_with_else: {}", stats.let.case_with_else);
lg::info(" unused: {}", stats.let.unused);
lg::info(" send_event: {}", stats.let.send_event);
if (config.generate_symbol_definition_map) {
lg::info("Generating symbol definition map...");
map_builder.build_map();
@@ -403,6 +419,7 @@ Value try_lookup(const std::unordered_map<Key, Value>& map, const Key& key) {
* - NOTE: this will update register info usage more accurately for functions.
*/
void ObjectFileDB::ir2_type_analysis_pass(int seg, const Config& config, ObjectFileData& data) {
auto obj_name = data.to_unique_name();
for_each_function_in_seg_in_obj(seg, data, [&](Function& func) {
if (!func.suspected_asm) {
TypeSpec ts;
@@ -414,9 +431,11 @@ void ObjectFileDB::ir2_type_analysis_pass(int seg, const Config& config, ObjectF
auto register_casts =
try_lookup(config.register_type_casts_by_function_by_atomic_op_idx, func_name);
func.ir2.env.set_type_casts(register_casts);
auto stack_casts =
try_lookup(config.stack_type_casts_by_function_by_stack_offset, func_name);
func.ir2.env.set_stack_casts(stack_casts);
if (config.hacks.pair_functions_by_name.find(func_name) !=
config.hacks.pair_functions_by_name.end()) {
func.ir2.env.set_sloppy_pair_typing();
@@ -426,8 +445,18 @@ void ObjectFileDB::ir2_type_analysis_pass(int seg, const Config& config, ObjectF
config.hacks.reject_cond_to_value.end()) {
func.ir2.env.aggressively_reject_cond_to_value_rewrite = true;
}
func.ir2.env.set_stack_structure_hints(
try_lookup(config.stack_structure_hints_by_function, func_name));
if (config.art_groups_by_function.find(func_name) != config.art_groups_by_function.end()) {
func.ir2.env.set_art_group(config.art_groups_by_function.at(func_name));
} else if (config.art_groups_by_file.find(obj_name) != config.art_groups_by_file.end()) {
func.ir2.env.set_art_group(config.art_groups_by_file.at(obj_name));
} else {
func.ir2.env.set_art_group(obj_name + "-ag");
}
if (run_type_analysis_ir2(ts, dts, func)) {
func.ir2.env.types_succeeded = true;
} else {
@@ -446,7 +475,7 @@ void ObjectFileDB::ir2_register_usage_pass(int seg, ObjectFileData& data) {
if (!func.suspected_asm && func.ir2.atomic_ops_succeeded) {
func.ir2.env.set_reg_use(analyze_ir2_register_usage(func));
auto block_0_start = func.ir2.env.reg_use().block.at(0).input;
auto& block_0_start = func.ir2.env.reg_use().block.at(0).input;
std::vector<Register> dep_regs;
for (auto x : block_0_start) {
dep_regs.push_back(x);
@@ -572,12 +601,14 @@ void ObjectFileDB::ir2_insert_lets(int seg, ObjectFileData& data) {
for_each_function_in_seg_in_obj(seg, data, [&](Function& func) {
if (func.ir2.expressions_succeeded) {
try {
insert_lets(func, func.ir2.env, *func.ir2.form_pool, func.ir2.top_form);
insert_lets(func, func.ir2.env, *func.ir2.form_pool, func.ir2.top_form, stats.let);
} catch (const std::exception& e) {
func.warnings.general_warning(
fmt::format("Error while inserting lets: {}. Make sure that the return type is not "
"none if something is actually returned.",
e.what()));
const auto err = fmt::format(
"Error while inserting lets: {}. Make sure that the return type is not "
"none if something is actually returned.",
e.what());
lg::warn(err);
func.warnings.general_warning(err);
}
}
});