mirror of
https://github.com/open-goal/jak-project
synced 2026-08-20 14:24:45 -04:00
improve macro detection
This commit is contained in:
@@ -3150,7 +3150,8 @@ bool try_to_rewrite_vector_inline_ctor(const Env& env,
|
||||
}
|
||||
|
||||
bool try_to_rewrite_matrix_inline_copy(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
if (env.func->name() == "(method 63 collide-shape-moving)") {
|
||||
if (env.func->name() == "matrix-copy!" ||
|
||||
env.func->name() == "(method 63 collide-shape-moving)") {
|
||||
return false;
|
||||
}
|
||||
auto matrix_entries =
|
||||
@@ -3158,13 +3159,21 @@ bool try_to_rewrite_matrix_inline_copy(const Env& env, FormPool& pool, FormStack
|
||||
if (matrix_entries) {
|
||||
// first, check the loads. they should be something like source = (-> MAT vec quad)
|
||||
// MAT should always be a variable
|
||||
const char* names[] = {"rvec", "uvec", "fvec", "trans"};
|
||||
|
||||
std::vector<RegisterAccess> load_src_ras, store_dest_ras, store_src_ras;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto deref_matcher =
|
||||
Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string(names[i]), DerefTokenMatcher::string("quad")});
|
||||
Matcher deref_matcher;
|
||||
if (env.version == GameVersion::Jak1) {
|
||||
deref_matcher = Matcher::deref(
|
||||
Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i),
|
||||
DerefTokenMatcher::string("quad")});
|
||||
} else {
|
||||
const char* names[] = {"rvec", "uvec", "fvec", "trans"};
|
||||
deref_matcher =
|
||||
Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string(names[i]),
|
||||
DerefTokenMatcher::string("quad")});
|
||||
}
|
||||
auto mr = match(deref_matcher, matrix_entries->at(i).source, &env);
|
||||
if (!mr.matched) {
|
||||
return false;
|
||||
@@ -3174,10 +3183,20 @@ bool try_to_rewrite_matrix_inline_copy(const Env& env, FormPool& pool, FormStack
|
||||
|
||||
// check the stores
|
||||
for (int i = 4; i < 8; i++) {
|
||||
Matcher matcher = Matcher::set(Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string(names[i - 4]),
|
||||
DerefTokenMatcher::string("quad")}),
|
||||
Matcher::any_reg(1));
|
||||
Matcher dst_matcher;
|
||||
if (env.version == GameVersion::Jak1) {
|
||||
dst_matcher = Matcher::deref(
|
||||
Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string("vector"), DerefTokenMatcher::integer(i - 4),
|
||||
DerefTokenMatcher::string("quad")});
|
||||
} else {
|
||||
const char* names[] = {"rvec", "uvec", "fvec", "trans"};
|
||||
dst_matcher =
|
||||
Matcher::deref(Matcher::any_reg(0), false,
|
||||
{DerefTokenMatcher::string(names[i - 4]),
|
||||
DerefTokenMatcher::string("quad")});
|
||||
}
|
||||
Matcher matcher = Matcher::set(dst_matcher, Matcher::any_reg(1));
|
||||
auto mr = match(matcher, matrix_entries->at(i).elt, &env);
|
||||
if (!mr.matched) {
|
||||
return false;
|
||||
@@ -3356,6 +3375,8 @@ bool try_to_rewrite_matrix_inline_ctor(const Env& env, FormPool& pool, FormStack
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case GameVersion::JakX:
|
||||
return false;
|
||||
}
|
||||
|
||||
// success!
|
||||
@@ -3380,6 +3401,50 @@ bool is_deref_to_quad(DerefElement* deref) {
|
||||
deref->tokens().back().is_field_name("quad");
|
||||
}
|
||||
|
||||
struct DerefContainerInfo {
|
||||
TypeSpec type;
|
||||
bool is_matrix_row = false;
|
||||
};
|
||||
|
||||
std::optional<DerefContainerInfo> deref_container_info(DerefElement* deref, const Env& env) {
|
||||
if (!is_deref_to_quad(deref)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto base = deref->base()->try_as_element<SimpleExpressionElement>();
|
||||
if (!base || base->expr().kind() != SimpleExpression::Kind::IDENTITY ||
|
||||
!base->expr().get_arg(0).is_var()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
TypeSpec current = env.get_variable_type(base->expr().get_arg(0).var(), true);
|
||||
bool is_matrix_row = current == TypeSpec("matrix") || current == TypeSpec("matrix3");
|
||||
for (size_t i = 0; i + 1 < deref->tokens().size(); ++i) {
|
||||
const auto& token = deref->tokens().at(i);
|
||||
if (token.kind() == DerefToken::Kind::FIELD_NAME) {
|
||||
try {
|
||||
current = env.dts->ts.lookup_field_info(current.base_type(), token.field_name()).type;
|
||||
} catch (const std::exception&) {
|
||||
return {};
|
||||
}
|
||||
} else if (token.kind() == DerefToken::Kind::INTEGER_CONSTANT ||
|
||||
token.kind() == DerefToken::Kind::INTEGER_EXPRESSION) {
|
||||
if (!current.has_single_arg()) {
|
||||
return {};
|
||||
}
|
||||
// get_single_arg() refers into current, so copy it before assignment destroys the argument
|
||||
// storage.
|
||||
const auto element_type = current.get_single_arg();
|
||||
current = element_type;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
is_matrix_row =
|
||||
is_matrix_row || current == TypeSpec("matrix") || current == TypeSpec("matrix3");
|
||||
}
|
||||
return DerefContainerInfo{current, is_matrix_row};
|
||||
}
|
||||
|
||||
Form* pop_last_deref_token(Form* form) {
|
||||
auto deref = form->try_as_element<DerefElement>();
|
||||
ASSERT(deref);
|
||||
@@ -3392,9 +3457,7 @@ Form* pop_last_deref_token(Form* form) {
|
||||
}
|
||||
|
||||
FormElement* try_to_rewrite_vector_copy(Form* dst,
|
||||
const TypeSpec& dst_type,
|
||||
Form* src,
|
||||
const TypeSpec& src_type,
|
||||
FormPool& pool,
|
||||
const Env& env) {
|
||||
if (env.func->name() == "vector-copy!") {
|
||||
@@ -3402,16 +3465,6 @@ FormElement* try_to_rewrite_vector_copy(Form* dst,
|
||||
}
|
||||
|
||||
if (dst && src) {
|
||||
// check types
|
||||
if (dst_type != TypeSpec("vector")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// kinda sus - we really want to check the place where this was loaded...
|
||||
if (src_type != TypeSpec("uint128")) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* dst_deref = dst->try_as_element<DerefElement>();
|
||||
auto* src_deref = src->try_as_element<DerefElement>();
|
||||
if (!dst_deref) {
|
||||
@@ -3422,11 +3475,17 @@ FormElement* try_to_rewrite_vector_copy(Form* dst,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!is_deref_to_quad(dst_deref)) {
|
||||
const auto dst_info = deref_container_info(dst_deref, env);
|
||||
const auto src_info = deref_container_info(src_deref, env);
|
||||
if (!dst_info || !src_info ||
|
||||
!env.dts->ts.tc(TypeSpec("vector"), dst_info->type) ||
|
||||
!env.dts->ts.tc(TypeSpec("vector"), src_info->type)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!is_deref_to_quad(src_deref)) {
|
||||
// A matrix row is represented by an inline vector, but folding its individual quadword copy
|
||||
// would prevent the four-row matrix-copy! recognizer from seeing the complete operation.
|
||||
if (dst_info->is_matrix_row || src_info->is_matrix_row) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -3439,6 +3498,39 @@ FormElement* try_to_rewrite_vector_copy(Form* dst,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FormElement* try_to_rewrite_vector_zero(Form* dst,
|
||||
Form* value,
|
||||
FormPool& pool,
|
||||
const Env& env) {
|
||||
if (env.func->name() == "vector-zero!") {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto dst_deref = dst ? dst->try_as_element<DerefElement>() : nullptr;
|
||||
const auto dst_info = dst_deref ? deref_container_info(dst_deref, env) : std::nullopt;
|
||||
if (!dst_info || !env.dts->ts.tc(TypeSpec("vector"), dst_info->type) ||
|
||||
dst_info->is_matrix_row) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!match(Matcher::cast("uint128", Matcher::integer(0)), value, &env).matched) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pool.alloc_element<GenericElement>(
|
||||
GenericOperator::make_function(pool.form<ConstantTokenElement>("vector-zero!")),
|
||||
std::vector<Form*>{pop_last_deref_token(dst)});
|
||||
}
|
||||
|
||||
bool is_pending_stack_vector_ctor(const FormStack& stack, RegisterAccess destination) {
|
||||
auto entries = stack.try_getting_active_stack_entries({true});
|
||||
if (!entries || !entries->front().destination ||
|
||||
entries->front().destination->reg() != destination.reg()) {
|
||||
return false;
|
||||
}
|
||||
auto stack_value = entries->front().source->try_as_element<StackStructureDefElement>();
|
||||
return stack_value && stack_value->type() == TypeSpec("vector");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) {
|
||||
@@ -3462,11 +3554,9 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s
|
||||
|
||||
FormElement* fr = nullptr;
|
||||
|
||||
// hack: for now only do this on Jak 3
|
||||
if (size() == 16 && env.version == GameVersion::Jak3) {
|
||||
fr = try_to_rewrite_vector_copy(
|
||||
m_dst, env.get_variable_type(m_base_var, true), popped.at(0),
|
||||
m_src_cast_type.value_or(env.get_variable_type(m_expr.var(), true)), pool, env);
|
||||
if (size() == 16 &&
|
||||
(env.version == GameVersion::Jak1 || env.version == GameVersion::Jak3)) {
|
||||
fr = try_to_rewrite_vector_copy(m_dst, popped.at(0), pool, env);
|
||||
}
|
||||
|
||||
if (!fr) {
|
||||
@@ -3486,10 +3576,19 @@ void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& s
|
||||
m_dst->try_as_element<DerefElement>()->inline_nested();
|
||||
auto val = pool.form<SimpleExpressionElement>(m_expr, m_my_idx);
|
||||
val->mark_popped();
|
||||
auto fr = pool.alloc_element<SetFormFormElement>(
|
||||
m_dst, make_optional_cast(m_src_cast_type, val, pool, env));
|
||||
fr->mark_popped();
|
||||
stack.push_form_element(fr, true);
|
||||
auto typed_value = make_optional_cast(m_src_cast_type, val, pool, env);
|
||||
FormElement* fr = nullptr;
|
||||
if (size() == 16 && env.version == GameVersion::Jak1 &&
|
||||
!is_pending_stack_vector_ctor(stack, m_base_var)) {
|
||||
fr = try_to_rewrite_vector_zero(m_dst, typed_value, pool, env);
|
||||
}
|
||||
if (!fr) {
|
||||
fr = pool.alloc_element<SetFormFormElement>(m_dst, typed_value);
|
||||
fr->mark_popped();
|
||||
stack.push_form_element(fr, true);
|
||||
} else {
|
||||
fr->push_to_stack(env, pool, stack);
|
||||
}
|
||||
}
|
||||
|
||||
if (!try_to_rewrite_matrix_inline_ctor(env, pool, stack)) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "ObjectFileDB.h"
|
||||
|
||||
#include "common/demacro/demacro.h"
|
||||
#include "common/formatter/formatter.h"
|
||||
#include "common/goos/PrettyPrinter.h"
|
||||
#include "common/link_types.h"
|
||||
@@ -880,6 +881,10 @@ void ObjectFileDB::ir2_write_results(const fs::path& output_dir,
|
||||
file_util::write_text_file(file_name, file_text);
|
||||
|
||||
auto unformatted_code = ir2_final_out(obj, imports, {});
|
||||
if (!config.demacro_file.empty()) {
|
||||
unformatted_code =
|
||||
demacro::rewrite(unformatted_code, file_util::get_file_path({config.demacro_file})).source;
|
||||
}
|
||||
auto final_name = output_dir / (obj.to_unique_name() + "_disasm.gc");
|
||||
if (config.format_code) {
|
||||
const auto formatted_code = formatter::format_code(unformatted_code);
|
||||
|
||||
@@ -46,6 +46,9 @@ Config make_config_via_json(nlohmann::json& json) {
|
||||
config.expected_elf_name = json.at("expected_elf_name").get<std::string>();
|
||||
}
|
||||
config.all_types_file = json.at("all_types_file").get<std::string>();
|
||||
if (json.contains("demacro_file")) {
|
||||
config.demacro_file = json.at("demacro_file").get<std::string>();
|
||||
}
|
||||
|
||||
auto inputs_json = read_json_file_from_config(json, "inputs_file");
|
||||
config.dgo_names = json.contains("dgo_names")
|
||||
|
||||
@@ -106,6 +106,7 @@ struct Config {
|
||||
|
||||
std::string obj_file_name_map_file;
|
||||
std::string all_types_file;
|
||||
std::string demacro_file;
|
||||
|
||||
bool disassemble_code = false;
|
||||
bool dump_function_metadata = false;
|
||||
|
||||
@@ -19576,10 +19576,15 @@ the original scratchpad decompressor remains available through the development s
|
||||
(define-extern mem-size
|
||||
"Collect value's memory categories using flags, optionally print the complete category table,
|
||||
and return the sum of aligned total bytes."
|
||||
(function basic symbol int int))
|
||||
(function basic symbol mem-usage-flags int))
|
||||
(define-extern jacc-mem-usage
|
||||
"Account for a compressed animation control block, its fixed data, and each compressed frame."
|
||||
(function joint-anim-compressed-control memory-usage-block int joint-anim-compressed-control))
|
||||
(function
|
||||
joint-anim-compressed-control
|
||||
memory-usage-block
|
||||
mem-usage-flags
|
||||
joint-anim-compressed-control
|
||||
))
|
||||
(define-extern joint-anim-inspect-elt
|
||||
"Inspect the payload element selected by rounding index to an integer. Matrix and transformq
|
||||
animations have specialized displays; other animation payload types are left unchanged."
|
||||
@@ -19722,7 +19727,7 @@ under label, then add those totals into the aggregate collision statistics."
|
||||
(define-extern mem-usage-bsp-tree
|
||||
"Recursively count the 32-byte internal nodes reachable from node in the BSP-node memory
|
||||
category. Nonpositive terminal children are not followed; header and flags are unused."
|
||||
(function bsp-header bsp-node memory-usage-block int none))
|
||||
(function bsp-header bsp-node memory-usage-block mem-usage-flags none))
|
||||
(define-extern bsp-camera-asm
|
||||
"Traverse the BSP for camera-position. At each split, select front when
|
||||
dot(camera-position, plane.xyz) - plane.w is nonnegative. Store the terminal leaf index and that
|
||||
@@ -21384,7 +21389,7 @@ instance distance to the level."
|
||||
(define-extern mem-usage-shrub-walk
|
||||
"Recursively account for node storage and leaf instance-shrubbery records across node-count
|
||||
contiguous shrub BVH roots. flags is forwarded for the memory-usage traversal."
|
||||
(function draw-node int memory-usage-block int draw-node))
|
||||
(function draw-node int memory-usage-block mem-usage-flags draw-node))
|
||||
(define-extern shrub-make-perspective-matrix
|
||||
"Copy the current camera transform to out, divide its homogeneous coefficients by pfog0, and fold
|
||||
the horizontal, vertical, depth, and fog offsets into the first three components."
|
||||
|
||||
@@ -0,0 +1,407 @@
|
||||
{
|
||||
// Patterns are matched against LISP forms after type analysis, expression construction, and
|
||||
// let insertion have finished. A `$name` atom captures one form; repeated captures must match
|
||||
// structurally. `$*name` captures zero or more forms within a list, which lets a rule tolerate
|
||||
// unrelated bindings merged into a compiler-generated let.
|
||||
//
|
||||
// `match` and `rewrite` may be either one form string or an array of adjacent form strings.
|
||||
// Rules are tried in file order. Keep rules conservative: this pass intentionally has no type
|
||||
// information with which to disambiguate structurally identical operations.
|
||||
"tables": {
|
||||
// Mirrors memory-usage-h.gc. `next` is the one-past category index stored in
|
||||
// memory-usage-block.length.
|
||||
"mem-usage-id": [
|
||||
{"value": "0", "next": "1", "symbol": "drawable-group"},
|
||||
{"value": "1", "next": "2", "symbol": "tfragment"},
|
||||
{"value": "2", "next": "3", "symbol": "tfragment-base"},
|
||||
{"value": "3", "next": "4", "symbol": "tfragment-common"},
|
||||
{"value": "4", "next": "5", "symbol": "tfragment-level0"},
|
||||
{"value": "5", "next": "6", "symbol": "tfragment-level1"},
|
||||
{"value": "6", "next": "7", "symbol": "tfragment-color"},
|
||||
{"value": "7", "next": "8", "symbol": "tfragment-debug"},
|
||||
{"value": "8", "next": "9", "symbol": "tfragment-pal"},
|
||||
{"value": "9", "next": "10", "symbol": "tie-fragment"},
|
||||
{"value": "10", "next": "11", "symbol": "tie-gif"},
|
||||
{"value": "11", "next": "12", "symbol": "tie-points"},
|
||||
{"value": "12", "next": "13", "symbol": "tie-colors"},
|
||||
{"value": "13", "next": "14", "symbol": "tie-draw-points"},
|
||||
{"value": "14", "next": "15", "symbol": "tie-debug"},
|
||||
{"value": "15", "next": "16", "symbol": "tie-near"},
|
||||
{"value": "16", "next": "17", "symbol": "tie-pal"},
|
||||
{"value": "17", "next": "18", "symbol": "tie-generic"},
|
||||
{"value": "18", "next": "19", "symbol": "instance-tie"},
|
||||
{"value": "19", "next": "20", "symbol": "instance-tie-colors0"},
|
||||
{"value": "20", "next": "21", "symbol": "instance-tie-colors1"},
|
||||
{"value": "21", "next": "22", "symbol": "instance-tie-colors2"},
|
||||
{"value": "22", "next": "23", "symbol": "instance-tie-colors3"},
|
||||
{"value": "23", "next": "24", "symbol": "instance-tie-colors*"},
|
||||
{"value": "24", "next": "25", "symbol": "prototype-bucket-shrub"},
|
||||
{"value": "25", "next": "26", "symbol": "generic-shrub"},
|
||||
{"value": "26", "next": "27", "symbol": "generic-shrub-data"},
|
||||
{"value": "27", "next": "28", "symbol": "shrubbery"},
|
||||
{"value": "28", "next": "29", "symbol": "shrubbery-object"},
|
||||
{"value": "29", "next": "30", "symbol": "shrubbery-vertex"},
|
||||
{"value": "30", "next": "31", "symbol": "shrubbery-color"},
|
||||
{"value": "31", "next": "32", "symbol": "shrubbery-stq"},
|
||||
{"value": "32", "next": "33", "symbol": "shrubbery-pal"},
|
||||
{"value": "33", "next": "34", "symbol": "billboard"},
|
||||
{"value": "34", "next": "35", "symbol": "instance-shrubbery"},
|
||||
{"value": "35", "next": "36", "symbol": "pris-fragment"},
|
||||
{"value": "43", "next": "44", "symbol": "entity"},
|
||||
{"value": "44", "next": "45", "symbol": "camera"},
|
||||
{"value": "45", "next": "46", "symbol": "nav-mesh"},
|
||||
{"value": "48", "next": "49", "symbol": "res"},
|
||||
{"value": "49", "next": "50", "symbol": "ambient"},
|
||||
{"value": "50", "next": "51", "symbol": "collide-fragment-0"},
|
||||
{"value": "51", "next": "52", "symbol": "collision-poly-0"},
|
||||
{"value": "52", "next": "53", "symbol": "collision-vertex-0"},
|
||||
{"value": "53", "next": "54", "symbol": "collide-fragment-1"},
|
||||
{"value": "54", "next": "55", "symbol": "collision-poly-1"},
|
||||
{"value": "55", "next": "56", "symbol": "collision-vertex-1"},
|
||||
{"value": "56", "next": "57", "symbol": "bsp-main"},
|
||||
{"value": "57", "next": "58", "symbol": "bsp-misc"},
|
||||
{"value": "58", "next": "59", "symbol": "bsp-node"},
|
||||
{"value": "59", "next": "60", "symbol": "bsp-leaf-vis-self"},
|
||||
{"value": "60", "next": "61", "symbol": "bsp-leaf-vis-adj"},
|
||||
{"value": "61", "next": "62", "symbol": "draw-node"},
|
||||
{"value": "62", "next": "63", "symbol": "pat"},
|
||||
{"value": "63", "next": "64", "symbol": "level-code"},
|
||||
{"value": "64", "next": "65", "symbol": "entity-links"},
|
||||
{"value": "65", "next": "66", "symbol": "joint"},
|
||||
{"value": "66", "next": "67", "symbol": "joint-anim-compressed"},
|
||||
{"value": "67", "next": "68", "symbol": "joint-anim-compressed-control"},
|
||||
{"value": "68", "next": "69", "symbol": "joint-anim-fixed"},
|
||||
{"value": "69", "next": "70", "symbol": "joint-anim-frame"},
|
||||
{"value": "70", "next": "71", "symbol": "art-group"},
|
||||
{"value": "71", "next": "72", "symbol": "art-mesh-anim"},
|
||||
{"value": "72", "next": "73", "symbol": "art-mesh-geo"},
|
||||
{"value": "73", "next": "74", "symbol": "art-joint-geo"},
|
||||
{"value": "74", "next": "75", "symbol": "art-joint-anim"},
|
||||
{"value": "75", "next": "76", "symbol": "merc-ctrl"},
|
||||
{"value": "76", "next": "77", "symbol": "joint-anim-drawable"},
|
||||
{"value": "77", "next": "78", "symbol": "blend-shape"},
|
||||
{"value": "78", "next": "79", "symbol": "collide-mesh"},
|
||||
{"value": "79", "next": "80", "symbol": "texture"},
|
||||
{"value": "80", "next": "81", "symbol": "string"},
|
||||
{"value": "81", "next": "82", "symbol": "array"},
|
||||
{"value": "82", "next": "83", "symbol": "sprite"},
|
||||
{"value": "83", "next": "84", "symbol": "depth-cue"},
|
||||
{"value": "84", "next": "85", "symbol": "debug"},
|
||||
{"value": "85", "next": "86", "symbol": "sky"},
|
||||
{"value": "86", "next": "87", "symbol": "pris-generic"},
|
||||
{"value": "87", "next": "88", "symbol": "4k-dead-pool"},
|
||||
{"value": "88", "next": "89", "symbol": "8k-dead-pool"},
|
||||
{"value": "89", "next": "90", "symbol": "16k-dead-pool"},
|
||||
{"value": "90", "next": "91", "symbol": "nk-dead-pool"},
|
||||
{"value": "91", "next": "92", "symbol": "target-dead-pool"},
|
||||
{"value": "92", "next": "93", "symbol": "camera-dead-pool"},
|
||||
{"value": "93", "next": "94", "symbol": "debug-dead-pool"},
|
||||
{"value": "94", "next": "95", "symbol": "process-active"},
|
||||
{"value": "95", "next": "96", "symbol": "heap-total"},
|
||||
{"value": "96", "next": "97", "symbol": "heap-process"},
|
||||
{"value": "97", "next": "98", "symbol": "heap-header"},
|
||||
{"value": "98", "next": "99", "symbol": "heap-thread"},
|
||||
{"value": "99", "next": "100", "symbol": "heap-root"},
|
||||
{"value": "100", "next": "101", "symbol": "heap-draw-control"},
|
||||
{"value": "101", "next": "102", "symbol": "heap-joint-control"},
|
||||
{"value": "102", "next": "103", "symbol": "heap-cspace"},
|
||||
{"value": "103", "next": "104", "symbol": "heap-bone"},
|
||||
{"value": "104", "next": "105", "symbol": "heap-part"},
|
||||
{"value": "105", "next": "106", "symbol": "heap-collide-prim"},
|
||||
{"value": "106", "next": "107", "symbol": "heap-misc"},
|
||||
{"value": "107", "next": "108", "symbol": "shadow-geo"},
|
||||
{"value": "108", "next": "109", "symbol": "eye-anim"}
|
||||
],
|
||||
"scratchpad-object-type": [
|
||||
{"type": "terrain-context"},
|
||||
{"type": "cam-dbg-scratch"},
|
||||
{"type": "terrain-bsp"},
|
||||
{"type": "collide-puss-work"},
|
||||
{"type": "vector"},
|
||||
{"type": "vector4w"},
|
||||
{"type": "bone-memory"},
|
||||
{"type": "joint"},
|
||||
{"type": "bone"},
|
||||
{"type": "vu-lights"},
|
||||
{"type": "bone-regs"},
|
||||
{"type": "matrix"},
|
||||
{"type": "generic-tie-shadow"},
|
||||
{"type": "generic-tie-calls"},
|
||||
{"type": "collide-probe-stack"},
|
||||
{"type": "ambient-list"},
|
||||
{"type": "adgif-shader"},
|
||||
{"type": "(inline-array ocean-vertex)"}
|
||||
],
|
||||
"scratchpad-pointer-type": [
|
||||
{"type": "rgba"},
|
||||
{"type": "uint128"},
|
||||
{"type": "process-drawable"}
|
||||
]
|
||||
},
|
||||
"rules": [
|
||||
{
|
||||
"name": "current-frame",
|
||||
"match": "(-> *display* frames (-> *display* on-screen) frame)",
|
||||
"rewrite": "(current-frame)"
|
||||
},
|
||||
{
|
||||
// Let insertion can merge consecutive traversals which reuse the same node and cached-next
|
||||
// locals. Peel off the first traversal and rebuild the remaining let; repeated rule passes
|
||||
// then recover every traversal in the chain.
|
||||
"name": "iterate-engine-connections-merged-let",
|
||||
"match":
|
||||
"(let (($node (-> $engine alive-list next0))) $engine (let (($next (-> $node next0))) (while (!= $node (-> $engine alive-list-end)) $*body (set! $node $next) $engine (set! $next (-> $next next0))) (set! $node (-> $next-engine alive-list next0)) $next-engine (set! $next (-> $node next0)) $*remaining))",
|
||||
"rewrite": [
|
||||
"(iterate-engine-connections ($node $engine) $*body)",
|
||||
"(let (($node (-> $next-engine alive-list next0))) $next-engine (let (($next (-> $node next0))) $*remaining))"
|
||||
]
|
||||
},
|
||||
{
|
||||
// Function-scoped locals produce assignments instead of let bindings around the traversal.
|
||||
"name": "iterate-engine-connections-set-locals",
|
||||
"match": [
|
||||
"(set! $node (-> $engine alive-list next0))",
|
||||
"$engine",
|
||||
"(set! $next (-> $node next0))",
|
||||
"(while (!= $node (-> $engine alive-list-end)) $*body (set! $node $next) $engine (set! $next (-> $next next0)))"
|
||||
],
|
||||
"rewrite": "(iterate-engine-connections ($node $engine) $*body)"
|
||||
},
|
||||
{
|
||||
// Constant engine globals sometimes survive as no-op forms around the cached-next traversal.
|
||||
"name": "iterate-engine-connections-with-engine-forms",
|
||||
"match":
|
||||
"(let (($node (-> $engine alive-list next0))) $engine (let (($next (-> $node next0))) (while (!= $node (-> $engine alive-list-end)) $*body (set! $node $next) $engine (set! $next (-> $next next0)))))",
|
||||
"rewrite": "(iterate-engine-connections ($node $engine) $*body)"
|
||||
},
|
||||
{
|
||||
"name": "iterate-engine-connections-nested-let",
|
||||
"match":
|
||||
"(let (($node (-> $engine alive-list next0))) (let (($next (-> $node next0))) (while (!= $node (-> $engine alive-list-end)) $*body (set! $node $next) (set! $next (-> $next next0)))))",
|
||||
"rewrite": "(iterate-engine-connections ($node $engine) $*body)"
|
||||
},
|
||||
{
|
||||
"name": "iterate-engine-connections-let-star",
|
||||
"match":
|
||||
"(let* (($node (-> $engine alive-list next0)) ($next (-> $node next0))) (while (!= $node (-> $engine alive-list-end)) $*body (set! $node $next) (set! $next (-> $next next0))))",
|
||||
"rewrite": "(iterate-engine-connections ($node $engine) $*body)"
|
||||
},
|
||||
{
|
||||
// Preserve unrelated bindings which let insertion combined with the traversal's node local.
|
||||
// Exact single-binding lets are handled above so this fallback never emits an empty let.
|
||||
"name": "iterate-engine-connections-merged-bindings",
|
||||
"match":
|
||||
"(let ($*before ($node (-> $engine alive-list next0)) $*after) $engine (let (($next (-> $node next0))) (while (!= $node (-> $engine alive-list-end)) $*body (set! $node $next) $engine (set! $next (-> $next next0)))))",
|
||||
"rewrite": "(let ($*before $*after) (iterate-engine-connections ($node $engine) $*body))"
|
||||
},
|
||||
{
|
||||
"name": "with-dma-buffer-add-bucket",
|
||||
"match":
|
||||
"(let* (($buf $buffer) ($start (-> $buf base))) $*body (let (($edge (-> $buf base))) (let (($packet (the-as dma-packet (-> $buf base)))) (set! (-> $packet dma) (new 'static 'dma-tag :id (dma-tag-id next))) (set! (-> $packet vif0) (new 'static 'vif-tag)) (set! (-> $packet vif1) (new 'static 'vif-tag)) (set! (-> $buf base) (&+ (the-as pointer $packet) 16))) (dma-bucket-insert-tag $bucket-group $bucket-id $start (the-as (pointer dma-tag) $edge))))",
|
||||
"rewrite":
|
||||
"(with-dma-buffer-add-bucket (($buf $buffer) $bucket-id) :bucket-group $bucket-group $*body)"
|
||||
},
|
||||
{
|
||||
"name": "with-dma-buffer-add-bucket-pointer-add-cast",
|
||||
"match":
|
||||
"(let* (($buf $buffer) ($start (-> $buf base))) $*body (let (($edge (-> $buf base))) (let (($packet (the-as dma-packet (-> $buf base)))) (set! (-> $packet dma) (new 'static 'dma-tag :id (dma-tag-id next))) (set! (-> $packet vif0) (new 'static 'vif-tag)) (set! (-> $packet vif1) (new 'static 'vif-tag)) (set! (-> $buf base) (the-as pointer (&+ $packet 16)))) (dma-bucket-insert-tag $bucket-group $bucket-id $start (the-as (pointer dma-tag) $edge))))",
|
||||
"rewrite":
|
||||
"(with-dma-buffer-add-bucket (($buf $buffer) $bucket-id) :bucket-group $bucket-group $*body)"
|
||||
},
|
||||
{
|
||||
"name": "with-dma-buffer-add-bucket-object-packet",
|
||||
"match":
|
||||
"(let* (($buf $buffer) ($start (-> $buf base))) $*body (let (($edge (-> $buf base))) (let (($packet (the-as object (-> $buf base)))) (set! (-> (the-as dma-packet $packet) dma) (new 'static 'dma-tag :id (dma-tag-id next))) (set! (-> (the-as dma-packet $packet) vif0) (new 'static 'vif-tag)) (set! (-> (the-as dma-packet $packet) vif1) (new 'static 'vif-tag)) (set! (-> $buf base) (&+ (the-as pointer $packet) 16))) (dma-bucket-insert-tag $bucket-group $bucket-id $start (the-as (pointer dma-tag) $edge))))",
|
||||
"rewrite":
|
||||
"(with-dma-buffer-add-bucket (($buf $buffer) $bucket-id) :bucket-group $bucket-group $*body)"
|
||||
},
|
||||
{
|
||||
// The font setters are methods rather than macros, but Jak 1 inlines them. The enum
|
||||
// constructors make these two field stores structurally unambiguous without type data.
|
||||
"name": "font-set-color-conditional-aliased",
|
||||
"match":
|
||||
"(let (($alias $font)) (set! (-> $alias color) (if $condition (font-color $*true-colors) (font-color $*false-colors))))",
|
||||
"rewrite":
|
||||
"(set-color! $font (if $condition (font-color $*true-colors) (font-color $*false-colors)))"
|
||||
},
|
||||
{
|
||||
"name": "font-set-color-aliased",
|
||||
"match":
|
||||
"(let (($alias $font)) (set! (-> $alias color) (font-color $*colors)))",
|
||||
"rewrite": "(set-color! $font (font-color $*colors))"
|
||||
},
|
||||
{
|
||||
"name": "font-set-color",
|
||||
"match": "(set! (-> $font color) (font-color $*colors))",
|
||||
"rewrite": "(set-color! $font (font-color $*colors))"
|
||||
},
|
||||
{
|
||||
"name": "font-set-flags-aliased",
|
||||
"match":
|
||||
"(let (($alias $font)) (set! (-> $alias flags) (font-flags $*flags)))",
|
||||
"rewrite": "(set-flags! $font (font-flags $*flags))"
|
||||
},
|
||||
{
|
||||
"name": "font-set-flags",
|
||||
"match": "(set! (-> $font flags) (font-flags $*flags))",
|
||||
"rewrite": "(set-flags! $font (font-flags $*flags))"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data {{value}} name) \"{{symbol}}\")",
|
||||
"(+! (-> $usage data {{value}} count) $count)",
|
||||
"(let (($temp $bytes)) (+! (-> $usage data {{value}} used) $temp) (+! (-> $usage data {{value}} total) (logand -16 (+ $temp 15))))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-enum-index-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data (mem-usage-id {{symbol}}) name) \"{{symbol}}\")",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) count) $count)",
|
||||
"(let (($temp $bytes)) (+! (-> $usage data (mem-usage-id {{symbol}}) used) $temp) (+! (-> $usage data (mem-usage-id {{symbol}}) total) (logand -16 (+ $temp 15))))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-runtime-name-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data {{value}} name) (symbol->string '{{symbol}}))",
|
||||
"(+! (-> $usage data {{value}} count) $count)",
|
||||
"(let (($temp $bytes)) (+! (-> $usage data {{value}} used) $temp) (+! (-> $usage data {{value}} total) (logand -16 (+ $temp 15))))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add-symbol! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-enum-index-runtime-name-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data (mem-usage-id {{symbol}}) name) (symbol->string '{{symbol}}))",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) count) $count)",
|
||||
"(let (($temp $bytes)) (+! (-> $usage data (mem-usage-id {{symbol}}) used) $temp) (+! (-> $usage data (mem-usage-id {{symbol}}) total) (logand -16 (+ $temp 15))))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add-symbol! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-flattened-let-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data {{value}} name) \"{{symbol}}\")",
|
||||
"(+! (-> $usage data {{value}} count) $count)",
|
||||
"(+! (-> $usage data {{value}} used) $bytes)",
|
||||
"(+! (-> $usage data {{value}} total) (logand -16 (+ $bytes 15)))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-enum-index-flattened-let-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data (mem-usage-id {{symbol}}) name) \"{{symbol}}\")",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) count) $count)",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) used) $bytes)",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) total) (logand -16 (+ $bytes 15)))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-runtime-name-flattened-let-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data {{value}} name) (symbol->string '{{symbol}}))",
|
||||
"(+! (-> $usage data {{value}} count) $count)",
|
||||
"(+! (-> $usage data {{value}} used) $bytes)",
|
||||
"(+! (-> $usage data {{value}} total) (logand -16 (+ $bytes 15)))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add-symbol! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
"name": "mem-usage-add-enum-index-runtime-name-flattened-let-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data (mem-usage-id {{symbol}}) name) (symbol->string '{{symbol}}))",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) count) $count)",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) used) $bytes)",
|
||||
"(+! (-> $usage data (mem-usage-id {{symbol}}) total) (logand -16 (+ $bytes 15)))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add-symbol! $usage {{symbol}} $count $bytes)"
|
||||
},
|
||||
{
|
||||
// A zero increment is sometimes decompiled as a self-assignment instead of `(+! ... 0)`.
|
||||
"name": "mem-usage-add-zero-count-{{symbol}}",
|
||||
"for_each": "mem-usage-id",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max {{next}} (-> $usage length)))",
|
||||
"(set! (-> $usage data {{value}} name) \"{{symbol}}\")",
|
||||
"(set! (-> $usage data {{value}} count) (-> $usage data {{value}} count))",
|
||||
"(let (($temp $bytes)) (+! (-> $usage data {{value}} used) $temp) (+! (-> $usage data {{value}} total) (logand -16 (+ $temp 15))))"
|
||||
],
|
||||
"rewrite": "(mem-usage-add! $usage {{symbol}} 0 $bytes)"
|
||||
},
|
||||
{
|
||||
// These adjacent calls share the larger one-past length after decompilation.
|
||||
"name": "mem-usage-add-generic-shrub-pair",
|
||||
"match": [
|
||||
"(set! (-> $usage length) (max 27 (-> $usage length)))",
|
||||
"(set! (-> $usage data 25 name) \"generic-shrub\")",
|
||||
"(+! (-> $usage data 25 count) $header-count)",
|
||||
"(let (($header-temp $header-bytes)) (+! (-> $usage data 25 used) $header-temp) (+! (-> $usage data 25 total) (logand -16 (+ $header-temp 15))))",
|
||||
"(set! (-> $usage data 26 name) \"generic-shrub-data\")",
|
||||
"(+! (-> $usage data 26 count) $stream-count)",
|
||||
"(let (($stream-temp $stream-bytes)) (+! (-> $usage data 26 used) $stream-temp) (+! (-> $usage data 26 total) (logand -16 (+ $stream-temp 15))))"
|
||||
],
|
||||
"rewrite": [
|
||||
"(mem-usage-add! $usage generic-shrub $header-count $header-bytes)",
|
||||
"(mem-usage-add! $usage generic-shrub-data $stream-count $stream-bytes)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "scratchpad-object-direct-{{type}}",
|
||||
"for_each": "scratchpad-object-type",
|
||||
"match": "(the-as {{type}} #x70000000)",
|
||||
"rewrite": "(scratchpad-object {{type}})"
|
||||
},
|
||||
{
|
||||
"name": "scratchpad-object-offset-{{type}}",
|
||||
"for_each": "scratchpad-object-type",
|
||||
"match": "(the-as {{type}} (+ $offset #x70000000))",
|
||||
"rewrite": "(scratchpad-object {{type}} :offset $offset)"
|
||||
},
|
||||
{
|
||||
"name": "scratchpad-object-reversed-offset-{{type}}",
|
||||
"for_each": "scratchpad-object-type",
|
||||
"match": "(the-as {{type}} (+ #x70000000 $offset))",
|
||||
"rewrite": "(scratchpad-object {{type}} :offset $offset)"
|
||||
},
|
||||
{
|
||||
"name": "scratchpad-pointer-direct-{{type}}",
|
||||
"for_each": "scratchpad-pointer-type",
|
||||
"match": "(the-as (pointer {{type}}) #x70000000)",
|
||||
"rewrite": "(scratchpad-ptr {{type}})"
|
||||
},
|
||||
{
|
||||
"name": "scratchpad-pointer-offset-{{type}}",
|
||||
"for_each": "scratchpad-pointer-type",
|
||||
"match": "(the-as (pointer {{type}}) (+ $offset #x70000000))",
|
||||
"rewrite": "(scratchpad-ptr {{type}} :offset $offset)"
|
||||
},
|
||||
{
|
||||
"name": "scratchpad-pointer-reversed-offset-{{type}}",
|
||||
"for_each": "scratchpad-pointer-type",
|
||||
"match": "(the-as (pointer {{type}}) (+ #x70000000 $offset))",
|
||||
"rewrite": "(scratchpad-ptr {{type}} :offset $offset)"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -101,6 +101,7 @@
|
||||
"art_info_file": "decompiler/config/jak1/ntsc_v1/art_info.jsonc",
|
||||
"import_deps_file": "decompiler/config/jak1/ntsc_v1/import_deps.jsonc",
|
||||
"all_types_file": "decompiler/config/jak1/all-types.gc",
|
||||
"demacro_file": "decompiler/config/jak1/demacro.jsonc",
|
||||
"art_group_dump_file": "decompiler/config/jak1/ntsc_v1/art-group-info.min.json",
|
||||
"joint_node_dump_file": "decompiler/config/jak1/ntsc_v1/joint-node-info.min.json",
|
||||
"tex_dump_file": "decompiler/config/jak1/ntsc_v1/tex-info.min.json",
|
||||
|
||||
Reference in New Issue
Block a user