diff --git a/include/psprecomp/runtime.hpp b/include/psprecomp/runtime.hpp index 9349a17..aba8cb0 100644 --- a/include/psprecomp/runtime.hpp +++ b/include/psprecomp/runtime.hpp @@ -311,12 +311,12 @@ public: return run_starvation_boundary(ctx); } - // Tier-2 hot-leaf lowering keeps the scheduler accounting that an ordinary - // cross-unit generated call would have performed, while allowing trivial - // leaf accessors to be emitted directly in their measured caller. No HLE - // or PSP ownership switch can occur inside those leaf bodies, so only the - // starvation safe-point cadence needs to be preserved here. - [[nodiscard]] PSPRECOMP_RUNTIME_FORCEINLINE bool account_inlined_generated_leaf( + // Account one logical outer generated dispatch that was deliberately + // removed by a profile-guided superblock. Publishing the destination PC + // before calling this helper is mandatory: a starvation boundary may switch + // PSP ownership at exactly the same point where the unfused outer dispatcher + // used to run. + [[nodiscard]] PSPRECOMP_RUNTIME_FORCEINLINE bool account_inlined_dispatch_boundary( AllegrexContext &ctx) { const std::uint64_t starvation_interval = g_runtime_starvation_interval_fast; if (starvation_interval == 0u) return true; @@ -324,6 +324,14 @@ public: return run_starvation_boundary(ctx); } + // Tier-2 hot-leaf lowering keeps the scheduler accounting that an ordinary + // cross-unit generated call would have performed, while allowing trivial + // leaf accessors to be emitted directly in their measured caller. + [[nodiscard]] PSPRECOMP_RUNTIME_FORCEINLINE bool account_inlined_generated_leaf( + AllegrexContext &ctx) { + return account_inlined_dispatch_boundary(ctx); + } + // Tier-2 profile-guided superblocks can fuse a cross-unit edge into a local // C++ goto. The guest-visible control flow is unchanged, but the ordinary // invoke_chained_direct() native frame no longer exists. These helpers keep diff --git a/profiles/vcs/CMakeLists.txt b/profiles/vcs/CMakeLists.txt index a9825b0..d1eb3cb 100644 --- a/profiles/vcs/CMakeLists.txt +++ b/profiles/vcs/CMakeLists.txt @@ -167,6 +167,7 @@ set(VCS_TIER2_CLUSTER_SOURCES host/vcs_tier2_cluster_physics.cpp host/vcs_tier2_cluster_world.cpp host/vcs_tier2_cluster_edge43.cpp + host/vcs_tier2_cluster_collisionloop.cpp ) if(MSVC) set_source_files_properties( diff --git a/profiles/vcs/generated/generated_unit_0037.cpp b/profiles/vcs/generated/generated_unit_0037.cpp index 9a1badf..8edace3 100644 --- a/profiles/vcs/generated/generated_unit_0037.cpp +++ b/profiles/vcs/generated/generated_unit_0037.cpp @@ -1,5 +1,6 @@ #include "psprecomp/runtime.hpp" #include "generated_units.hpp" +#include "vcs_tier2_superblocks.hpp" #include #include #include @@ -8398,6 +8399,12 @@ L_0889BF84: ctx.fpr[24] = std::bit_cast(ctx.gpr[4]); goto L_0889BFC0; L_0889BFC0: +// TIER2_SUPERBLOCK_V2_HOOK_BEGIN + if (vcs::tier2_cluster_enabled(vcs::Tier2ClusterId::CollisionLoop) && rt.memory().direct_fastmem_enabled()) { + vcs::tier2_superblock_collisionloop(rt, ctx, aot_mem, 0x0889BFC0u); + return; + } +// TIER2_SUPERBLOCK_V2_HOOK_END ctx.gpr[18] = (aot_mem.aot_load32(ctx.gpr[30] + static_cast(0))); ctx.gpr[30] = (aot_mem.aot_load32(ctx.gpr[30] + static_cast(8))); ctx.gpr[4] = (aot_mem.aot_load16(ctx.gpr[18] + static_cast(84))); diff --git a/profiles/vcs/generated/generated_unit_0038.cpp b/profiles/vcs/generated/generated_unit_0038.cpp index d94b86c..84317db 100644 --- a/profiles/vcs/generated/generated_unit_0038.cpp +++ b/profiles/vcs/generated/generated_unit_0038.cpp @@ -1,5 +1,6 @@ #include "psprecomp/runtime.hpp" #include "generated_units.hpp" +#include "vcs_tier2_superblocks.hpp" #include #include #include @@ -1025,6 +1026,12 @@ LOCAL_DISPATCH: } } L_0889C000: +// TIER2_SUPERBLOCK_V2_HOOK_BEGIN + if (vcs::tier2_cluster_enabled(vcs::Tier2ClusterId::CollisionLoop) && rt.memory().direct_fastmem_enabled()) { + vcs::tier2_superblock_collisionloop(rt, ctx, aot_mem, 0x0889C000u); + return; + } +// TIER2_SUPERBLOCK_V2_HOOK_END { const bool branch_taken = ctx.gpr[4] == 0u; // nop if (branch_taken) { @@ -1912,6 +1919,12 @@ L_0889C5B0: aot_mem.aot_store32(ctx.gpr[4] + static_cast(0), ctx.gpr[18]); goto L_0889C5B8; L_0889C5B8: +// TIER2_SUPERBLOCK_V2_HOOK_BEGIN + if (vcs::tier2_cluster_enabled(vcs::Tier2ClusterId::CollisionLoop) && rt.memory().direct_fastmem_enabled()) { + vcs::tier2_superblock_collisionloop(rt, ctx, aot_mem, 0x0889C5B8u); + return; + } +// TIER2_SUPERBLOCK_V2_HOOK_END { const bool branch_taken = ctx.gpr[30] != 0u; // nop if (branch_taken) { diff --git a/profiles/vcs/generated/generated_unit_0043.cpp b/profiles/vcs/generated/generated_unit_0043.cpp index 1a9f0b0..c0d81a1 100644 --- a/profiles/vcs/generated/generated_unit_0043.cpp +++ b/profiles/vcs/generated/generated_unit_0043.cpp @@ -9533,6 +9533,12 @@ L_088B3FCC: ctx.gpr[4] = (ctx.gpr[20] | 0u); goto L_088B1780; L_088B3FFC: +// TIER2_SUPERBLOCK_V2_HOOK_BEGIN + if (vcs::tier2_cluster_enabled(vcs::Tier2ClusterId::Edge43) && rt.memory().direct_fastmem_enabled()) { + vcs::tier2_superblock_edge43(rt, ctx, aot_mem, 0x088B3FFCu); + return; + } +// TIER2_SUPERBLOCK_V2_HOOK_END if (ctx.gpr[2] == 0u) { ctx.gpr[4] = (aot_mem.aot_load32(ctx.gpr[29] + static_cast(48))); (void)rt.invoke_chained_direct<&recomp_unit_0044_entry, 44u, 9u, 0x088B40F8u>(ctx, &aot_mem); return; diff --git a/profiles/vcs/host/vcs_runtime_log.cpp b/profiles/vcs/host/vcs_runtime_log.cpp index e4d3e33..6c5a883 100644 --- a/profiles/vcs/host/vcs_runtime_log.cpp +++ b/profiles/vcs/host/vcs_runtime_log.cpp @@ -65,7 +65,7 @@ void runtime_log_initialize(const VcsConfiguration &configuration) { return; } s.file << "VCSNative runtime log\n"; - s.file << "stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18\n"; + s.file << "stage=perf-v8.3-cpu-boundary-fusion-2026-08-18\n"; s.file << "config=" << configuration.source_path.string() << '\n'; s.file << "started=" << timestamp_now() << '\n'; s.file << "perf_telemetry=" << (configuration.diagnostics.perf_telemetry ? 1 : 0) @@ -81,16 +81,16 @@ void runtime_log_initialize(const VcsConfiguration &configuration) { << " chain_telemetry_compiled=0\n"; #endif s.file << "tier2_superblocks=" << (tier2_superblocks_enabled() ? 1 : 0) - << " version=4 clusters=7 mask=0x" << std::hex << tier2_cluster_mask() << std::dec - << " hot_blocks=1060 static_fused_calls=36 static_fused_tail=13 hooks=25" + << " version=4 clusters=8 mask=0x" << std::hex << tier2_cluster_mask() << std::dec + << " hot_blocks=1139 static_fused_calls=36 static_fused_tail=18 static_pc_fused=1 hooks=29" << " entity_leaf_inline_sites=13 geometry_inline_leaf_sites=0 direct_generated_leaf_sites=5" - << " unwind_fix=1 reentry_guard=1 dataflow=1 vfpu_block32=133 mem_runs=35 mem_words=287" - << " append32=51 advance32=89 simd_mat4=4 simd_matvec=19" - << " gpr_shadow_clusters=4 gpr_shadow_regs=24 gpr_shadow_occurrences=3461 geometry_shadow=0" - << " perf_layer=8 cpu_lean_revision=2 correctness_revision=8271 recovery_from_821=1" + << " unwind_fix=1 reentry_guard=1 dataflow=1 vfpu_block32=153 mem_runs=39 mem_words=299" + << " append32=51 advance32=89 simd_mat4=4 simd_matvec=21" + << " gpr_shadow_clusters=5 gpr_shadow_regs=30 gpr_shadow_occurrences=3841 geometry_shadow=0" + << " perf_layer=9 cpu_lean_revision=3 correctness_revision=8271 recovery_from_821=1 cpu_boundary_fusion=1 edge43_continuation_fused=1 collisionloop_blocks=78 collisionloop_static_pc_fused=1 collisionloop_scheduler_accounting=1" << " save_transaction=1 save_lifecycle_v82=1 sas_endflag_latched=1 sas_loop_history_restore=1" << " atrac_virtual_source=1 atrac_stall_diag=1 atrac_stream_resident_status=1 atrac_nonloop_resident=-2 atrac_loop_resident=-3 output2_success_zero=1 output2_master_watermark=1 output2_late_catchup=0 save_repro_checkpoint=1 save_repro_trace=1 save_repro_hotkey_f8=1 save_repro_trace_hotkey_f10=1 save_repro_auto_restore=1 save_repro_dispatch_sample_stride=64 save_repro_passive_until_f8=1 save_repro_hle_hotpath=0 save_repro_ui_hotkeys=1 save_repro_f10_async_fallback=1 save_repro_collector_partial_bundle=1 save_repro_internal_ini_gate=1 save_repro_default_enabled=0 save_exitdelete_semantics=1 save_repro_legacy_exitdelete_repair=1 save_partition_reuse=1 news_atrac_v825_guard=1 runtime_chain_telemetry_default=0 arch_fastmem=1 aot_direct_fastmem_default=1" - << " tier2_direct_fastmem=1 tier2_direct_mem_sites=1969 tier2_deep_telemetry_default=0 geometry_fusion_rollback=1" + << " tier2_direct_fastmem=1 tier2_direct_mem_sites=2115 tier2_deep_telemetry_default=0 geometry_fusion_rollback=1" << " entity_leaf_inline=1 entity_leaf_scheduler_accounting=1 entity_leaf_resume_pc_fix=1" << " ge_async_default=0 parallel_vertex_decode_default=0" << " v5_vfpu_fast_quarantined=1 native_vfpu_088b1780_v4=1" diff --git a/profiles/vcs/host/vcs_tier2_cluster_collisionloop.cpp b/profiles/vcs/host/vcs_tier2_cluster_collisionloop.cpp new file mode 100644 index 0000000..fc59366 --- /dev/null +++ b/profiles/vcs/host/vcs_tier2_cluster_collisionloop.cpp @@ -0,0 +1,1363 @@ +// AUTO-GENERATED by profiles/vcs/tools/build_tier2_superblocks.py. +// Tier-2 SUPERBLOCK V4 150FPS cluster: collisionloop +#include "vcs_tier2_superblocks.hpp" +#include "psprecomp/runtime.hpp" +#include "generated_units.hpp" +#include "vcs_fast_paths.hpp" +#include "vcs_tier2_direct_memory.hpp" + +#include + +namespace vcs { +using namespace psprecomp; + +void tier2_superblock_collisionloop(psprecomp::Runtime &rt, + psprecomp::AllegrexContext &ctx, + psprecomp::GuestMemory::AotFastView &aot_mem, + std::uint32_t entry_pc) { + tier2_detail::SampleScope tier2_scope(Tier2ClusterId::CollisionLoop); + auto &tier2_stats = tier2_scope.stats(); + Tier2DirectMemoryView tier2_mem(rt.memory().direct_fastmem_base_address()); + constexpr std::uint32_t kTier2ReturnCapacity = 32u; + std::uint32_t tier2_pending_transfers = 0u; + std::uint32_t tier2_return_depth = 0u; + std::uint32_t tier2_return_pc[kTier2ReturnCapacity]; + std::uint32_t tier2_return_unit[kTier2ReturnCapacity]; + std::uint32_t tier2_return_pending_base[kTier2ReturnCapacity]; + std::uint32_t tier2_resume_pc = 0u; + std::uint32_t tier2_resume_unit = 0u; + std::uint32_t jump_target = 0u; + std::uint32_t local_pc = 0u; + std::uint32_t local_transfers = 0u; + std::uint32_t entry_id = 0u; + std::uint32_t tier2_gpr_4 = ctx.gpr[4]; + std::uint32_t tier2_gpr_29 = ctx.gpr[29]; + std::uint32_t tier2_gpr_5 = ctx.gpr[5]; + std::uint32_t tier2_gpr_18 = ctx.gpr[18]; + std::uint32_t tier2_gpr_16 = ctx.gpr[16]; + std::uint32_t tier2_gpr_6 = ctx.gpr[6]; + bool tier2_gpr_shadow_valid = true; +#define TIER2_GPR_SYNC_OUT() do { if (tier2_gpr_shadow_valid) { ctx.gpr[4] = tier2_gpr_4; ctx.gpr[29] = tier2_gpr_29; ctx.gpr[5] = tier2_gpr_5; ctx.gpr[18] = tier2_gpr_18; ctx.gpr[16] = tier2_gpr_16; ctx.gpr[6] = tier2_gpr_6; } } while (false) +#define TIER2_GPR_SYNC_IN() do { if (tier2_gpr_shadow_valid) { tier2_gpr_4 = ctx.gpr[4]; tier2_gpr_29 = ctx.gpr[29]; tier2_gpr_5 = ctx.gpr[5]; tier2_gpr_18 = ctx.gpr[18]; tier2_gpr_16 = ctx.gpr[16]; tier2_gpr_6 = ctx.gpr[6]; } } while (false) +#define TIER2_GPR_BEFORE_COLD() do { TIER2_GPR_SYNC_OUT(); tier2_gpr_shadow_valid = false; } while (false) + + auto tier2_complete_shadow = [&](std::uint32_t count) -> bool { + TIER2_GPR_SYNC_OUT(); + const bool same = rt.tier2_complete_fused_transfers(ctx, count); + if (!same) tier2_gpr_shadow_valid = false; + return same; + }; + +#define TIER2_SB_RETURN() do { TIER2_GPR_SYNC_OUT(); tier2_scope.finish(); /* Unwind every logical invoke_chained_direct frame in true LIFO order. Tail frames created inside a fused JAL unwind before that JAL; outer JAL frames are also released after context invalidation. */ while (tier2_return_depth != 0u) { std::uint32_t tier2_base_ = tier2_return_pending_base[tier2_return_depth - 1u]; if (tier2_base_ > tier2_pending_transfers) { ++tier2_stats.fallbacks; tier2_base_ = tier2_pending_transfers; } const std::uint32_t tier2_tail_count_ = tier2_pending_transfers - tier2_base_; tier2_pending_transfers = tier2_base_; if (tier2_tail_count_ != 0u) (void)tier2_complete_shadow(tier2_tail_count_); --tier2_return_depth; (void)tier2_complete_shadow(1u); } if (tier2_pending_transfers != 0u) { (void)tier2_complete_shadow(tier2_pending_transfers); tier2_pending_transfers = 0u; } return; } while (false) + + goto TIER2_ENTRY_DISPATCH; + +TIER2_FUSED_RETURN_DISPATCH: + switch (tier2_resume_pc) { + case 0x0889BFC0u: goto SB_L_0889BFC0; + case 0x0889BFD8u: goto SB_L_0889BFD8; + case 0x0889BFE4u: goto SB_L_0889BFE4; + case 0x0889C000u: goto SB_L_0889C000; + case 0x0889C008u: goto SB_L_0889C008; + case 0x0889C014u: goto SB_L_0889C014; + case 0x0889C01Cu: goto SB_L_0889C01C; + case 0x0889C024u: goto SB_L_0889C024; + case 0x0889C054u: goto SB_L_0889C054; + case 0x0889C06Cu: goto SB_L_0889C06C; + case 0x0889C074u: goto SB_L_0889C074; + case 0x0889C084u: goto SB_L_0889C084; + case 0x0889C08Cu: goto SB_L_0889C08C; + case 0x0889C094u: goto SB_L_0889C094; + case 0x0889C09Cu: goto SB_L_0889C09C; + case 0x0889C0A8u: goto SB_L_0889C0A8; + case 0x0889C0B0u: goto SB_L_0889C0B0; + case 0x0889C0B8u: goto SB_L_0889C0B8; + case 0x0889C0C0u: goto SB_L_0889C0C0; + case 0x0889C0D4u: goto SB_L_0889C0D4; + case 0x0889C0E4u: goto SB_L_0889C0E4; + case 0x0889C0F0u: goto SB_L_0889C0F0; + case 0x0889C0F8u: goto SB_L_0889C0F8; + case 0x0889C114u: goto SB_L_0889C114; + case 0x0889C120u: goto SB_L_0889C120; + case 0x0889C13Cu: goto SB_L_0889C13C; + case 0x0889C14Cu: goto SB_L_0889C14C; + case 0x0889C158u: goto SB_L_0889C158; + case 0x0889C160u: goto SB_L_0889C160; + case 0x0889C168u: goto SB_L_0889C168; + case 0x0889C180u: goto SB_L_0889C180; + case 0x0889C188u: goto SB_L_0889C188; + case 0x0889C194u: goto SB_L_0889C194; + case 0x0889C1A4u: goto SB_L_0889C1A4; + case 0x0889C1B4u: goto SB_L_0889C1B4; + case 0x0889C1C4u: goto SB_L_0889C1C4; + case 0x0889C1CCu: goto SB_L_0889C1CC; + case 0x0889C1E0u: goto SB_L_0889C1E0; + case 0x0889C1F0u: goto SB_L_0889C1F0; + case 0x0889C1FCu: goto SB_L_0889C1FC; + case 0x0889C204u: goto SB_L_0889C204; + case 0x0889C21Cu: goto SB_L_0889C21C; + case 0x0889C234u: goto SB_L_0889C234; + case 0x0889C23Cu: goto SB_L_0889C23C; + case 0x0889C254u: goto SB_L_0889C254; + case 0x0889C26Cu: goto SB_L_0889C26C; + case 0x0889C274u: goto SB_L_0889C274; + case 0x0889C298u: goto SB_L_0889C298; + case 0x0889C2A0u: goto SB_L_0889C2A0; + case 0x0889C2A8u: goto SB_L_0889C2A8; + case 0x0889C2C0u: goto SB_L_0889C2C0; + case 0x0889C2C8u: goto SB_L_0889C2C8; + case 0x0889C2D0u: goto SB_L_0889C2D0; + case 0x0889C2F8u: goto SB_L_0889C2F8; + case 0x0889C378u: goto SB_L_0889C378; + case 0x0889C380u: goto SB_L_0889C380; + case 0x0889C388u: goto SB_L_0889C388; + case 0x0889C394u: goto SB_L_0889C394; + case 0x0889C3B0u: goto SB_L_0889C3B0; + case 0x0889C3B8u: goto SB_L_0889C3B8; + case 0x0889C3DCu: goto SB_L_0889C3DC; + case 0x0889C3E4u: goto SB_L_0889C3E4; + case 0x0889C3ECu: goto SB_L_0889C3EC; + case 0x0889C404u: goto SB_L_0889C404; + case 0x0889C40Cu: goto SB_L_0889C40C; + case 0x0889C414u: goto SB_L_0889C414; + case 0x0889C43Cu: goto SB_L_0889C43C; + case 0x0889C4B8u: goto SB_L_0889C4B8; + case 0x0889C4C0u: goto SB_L_0889C4C0; + case 0x0889C4D8u: goto SB_L_0889C4D8; + case 0x0889C4E8u: goto SB_L_0889C4E8; + case 0x0889C4F4u: goto SB_L_0889C4F4; + case 0x0889C570u: goto SB_L_0889C570; + case 0x0889C580u: goto SB_L_0889C580; + case 0x0889C590u: goto SB_L_0889C590; + case 0x0889C5A0u: goto SB_L_0889C5A0; + case 0x0889C5B0u: goto SB_L_0889C5B0; + case 0x0889C5B8u: goto SB_L_0889C5B8; + default: break; + } + switch (tier2_resume_unit) { + + default: break; + } + ctx.pc = tier2_resume_pc; + TIER2_SB_RETURN(); + +TIER2_LOCAL_DISPATCH_U0037: + if (tier2_return_depth != 0u && local_pc == tier2_return_pc[tier2_return_depth - 1u]) { + tier2_resume_pc = local_pc; + tier2_resume_unit = tier2_return_unit[tier2_return_depth - 1u]; + // Match invoke_chained_direct(): when the callee has returned, ctx.pc + // already contains the caller continuation before any starvation + // boundary/accounting can run. A scheduler switch here must never see + // the stale callee PC. + ctx.pc = local_pc; + const std::uint32_t tier2_pending_base = + tier2_return_pending_base[tier2_return_depth - 1u]; + bool tier2_same_context = true; + if (tier2_pending_transfers < tier2_pending_base) { + ++tier2_stats.fallbacks; + ctx.pc = local_pc; + TIER2_SB_RETURN(); + } + const std::uint32_t tier2_nested_tail = + tier2_pending_transfers - tier2_pending_base; + if (tier2_nested_tail != 0u) { + tier2_pending_transfers = tier2_pending_base; + if (!tier2_complete_shadow(tier2_nested_tail)) + tier2_same_context = false; + } + --tier2_return_depth; + if (!tier2_complete_shadow(1u)) + tier2_same_context = false; + if (!tier2_same_context) TIER2_SB_RETURN(); + goto TIER2_FUSED_RETURN_DISPATCH; + } + switch (local_pc) { + case 0x0889BFC0u: goto SB_L_0889BFC0; + case 0x0889BFD8u: goto SB_L_0889BFD8; + case 0x0889BFE4u: goto SB_L_0889BFE4; + default: + ctx.pc = local_pc; + TIER2_SB_RETURN(); + } + +TIER2_LOCAL_DISPATCH_U0038: + if (tier2_return_depth != 0u && local_pc == tier2_return_pc[tier2_return_depth - 1u]) { + tier2_resume_pc = local_pc; + tier2_resume_unit = tier2_return_unit[tier2_return_depth - 1u]; + // Match invoke_chained_direct(): when the callee has returned, ctx.pc + // already contains the caller continuation before any starvation + // boundary/accounting can run. A scheduler switch here must never see + // the stale callee PC. + ctx.pc = local_pc; + const std::uint32_t tier2_pending_base = + tier2_return_pending_base[tier2_return_depth - 1u]; + bool tier2_same_context = true; + if (tier2_pending_transfers < tier2_pending_base) { + ++tier2_stats.fallbacks; + ctx.pc = local_pc; + TIER2_SB_RETURN(); + } + const std::uint32_t tier2_nested_tail = + tier2_pending_transfers - tier2_pending_base; + if (tier2_nested_tail != 0u) { + tier2_pending_transfers = tier2_pending_base; + if (!tier2_complete_shadow(tier2_nested_tail)) + tier2_same_context = false; + } + --tier2_return_depth; + if (!tier2_complete_shadow(1u)) + tier2_same_context = false; + if (!tier2_same_context) TIER2_SB_RETURN(); + goto TIER2_FUSED_RETURN_DISPATCH; + } + switch (local_pc) { + case 0x0889C000u: goto SB_L_0889C000; + case 0x0889C008u: goto SB_L_0889C008; + case 0x0889C014u: goto SB_L_0889C014; + case 0x0889C01Cu: goto SB_L_0889C01C; + case 0x0889C024u: goto SB_L_0889C024; + case 0x0889C054u: goto SB_L_0889C054; + case 0x0889C06Cu: goto SB_L_0889C06C; + case 0x0889C074u: goto SB_L_0889C074; + case 0x0889C084u: goto SB_L_0889C084; + case 0x0889C08Cu: goto SB_L_0889C08C; + case 0x0889C094u: goto SB_L_0889C094; + case 0x0889C09Cu: goto SB_L_0889C09C; + case 0x0889C0A8u: goto SB_L_0889C0A8; + case 0x0889C0B0u: goto SB_L_0889C0B0; + case 0x0889C0B8u: goto SB_L_0889C0B8; + case 0x0889C0C0u: goto SB_L_0889C0C0; + case 0x0889C0D4u: goto SB_L_0889C0D4; + case 0x0889C0E4u: goto SB_L_0889C0E4; + case 0x0889C0F0u: goto SB_L_0889C0F0; + case 0x0889C0F8u: goto SB_L_0889C0F8; + case 0x0889C114u: goto SB_L_0889C114; + case 0x0889C120u: goto SB_L_0889C120; + case 0x0889C13Cu: goto SB_L_0889C13C; + case 0x0889C14Cu: goto SB_L_0889C14C; + case 0x0889C158u: goto SB_L_0889C158; + case 0x0889C160u: goto SB_L_0889C160; + case 0x0889C168u: goto SB_L_0889C168; + case 0x0889C180u: goto SB_L_0889C180; + case 0x0889C188u: goto SB_L_0889C188; + case 0x0889C194u: goto SB_L_0889C194; + case 0x0889C1A4u: goto SB_L_0889C1A4; + case 0x0889C1B4u: goto SB_L_0889C1B4; + case 0x0889C1C4u: goto SB_L_0889C1C4; + case 0x0889C1CCu: goto SB_L_0889C1CC; + case 0x0889C1E0u: goto SB_L_0889C1E0; + case 0x0889C1F0u: goto SB_L_0889C1F0; + case 0x0889C1FCu: goto SB_L_0889C1FC; + case 0x0889C204u: goto SB_L_0889C204; + case 0x0889C21Cu: goto SB_L_0889C21C; + case 0x0889C234u: goto SB_L_0889C234; + case 0x0889C23Cu: goto SB_L_0889C23C; + case 0x0889C254u: goto SB_L_0889C254; + case 0x0889C26Cu: goto SB_L_0889C26C; + case 0x0889C274u: goto SB_L_0889C274; + case 0x0889C298u: goto SB_L_0889C298; + case 0x0889C2A0u: goto SB_L_0889C2A0; + case 0x0889C2A8u: goto SB_L_0889C2A8; + case 0x0889C2C0u: goto SB_L_0889C2C0; + case 0x0889C2C8u: goto SB_L_0889C2C8; + case 0x0889C2D0u: goto SB_L_0889C2D0; + case 0x0889C2F8u: goto SB_L_0889C2F8; + case 0x0889C378u: goto SB_L_0889C378; + case 0x0889C380u: goto SB_L_0889C380; + case 0x0889C388u: goto SB_L_0889C388; + case 0x0889C394u: goto SB_L_0889C394; + case 0x0889C3B0u: goto SB_L_0889C3B0; + case 0x0889C3B8u: goto SB_L_0889C3B8; + case 0x0889C3DCu: goto SB_L_0889C3DC; + case 0x0889C3E4u: goto SB_L_0889C3E4; + case 0x0889C3ECu: goto SB_L_0889C3EC; + case 0x0889C404u: goto SB_L_0889C404; + case 0x0889C40Cu: goto SB_L_0889C40C; + case 0x0889C414u: goto SB_L_0889C414; + case 0x0889C43Cu: goto SB_L_0889C43C; + case 0x0889C4B8u: goto SB_L_0889C4B8; + case 0x0889C4C0u: goto SB_L_0889C4C0; + case 0x0889C4D8u: goto SB_L_0889C4D8; + case 0x0889C4E8u: goto SB_L_0889C4E8; + case 0x0889C4F4u: goto SB_L_0889C4F4; + case 0x0889C570u: goto SB_L_0889C570; + case 0x0889C580u: goto SB_L_0889C580; + case 0x0889C590u: goto SB_L_0889C590; + case 0x0889C5A0u: goto SB_L_0889C5A0; + case 0x0889C5B0u: goto SB_L_0889C5B0; + case 0x0889C5B8u: goto SB_L_0889C5B8; + default: + ctx.pc = local_pc; + TIER2_SB_RETURN(); + } + + +TIER2_ENTRY_DISPATCH: + switch (entry_pc) { + case 0x0889BFC0u: goto SB_L_0889BFC0; + case 0x0889C000u: goto SB_L_0889C000; + case 0x0889C5B8u: goto SB_L_0889C5B8; + default: + ctx.pc = entry_pc; + ++tier2_stats.fallbacks; + TIER2_SB_RETURN(); + } + +// TIER2_GPR_BODY_BEGIN +SB_L_0889BFC0: + tier2_gpr_18 = (tier2_mem.aot_load32(ctx.gpr[30] + static_cast(0))); + ctx.gpr[30] = (tier2_mem.aot_load32(ctx.gpr[30] + static_cast(8))); + tier2_gpr_4 = (tier2_mem.aot_load16(tier2_gpr_18 + static_cast(84))); + tier2_gpr_5 = (tier2_mem.aot_load16(ctx.gpr[28] + static_cast(-25492))); + { const bool branch_taken = tier2_gpr_4 == tier2_gpr_5; + ctx.gpr[17] = (tier2_mem.aot_load8(tier2_gpr_29 + static_cast(596))); + if (branch_taken) { + if (!rt.tier2_enter_fused_transfer<38u, 0x0889C5B8u>(ctx)) { + ctx.pc = 0x0889C5B8u; + TIER2_SB_RETURN(); + } + ++tier2_pending_transfers; + ++tier2_stats.fused_tail_edges; + goto SB_L_0889C5B8; + } + goto SB_L_0889BFD8; + } + +SB_L_0889BFD8: + tier2_gpr_4 = (tier2_mem.aot_load32(ctx.gpr[28] + static_cast(8068))); + { const bool branch_taken = tier2_gpr_18 == tier2_gpr_4; + // nop + if (branch_taken) { + if (!rt.tier2_enter_fused_transfer<38u, 0x0889C5B8u>(ctx)) { + ctx.pc = 0x0889C5B8u; + TIER2_SB_RETURN(); + } + ++tier2_pending_transfers; + ++tier2_stats.fused_tail_edges; + goto SB_L_0889C5B8; + } + goto SB_L_0889BFE4; + } + +SB_L_0889BFE4: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(72))); + tier2_gpr_4 = (tier2_gpr_4 & 512u); + tier2_gpr_4 = (0u < tier2_gpr_4 ? 1u : 0u); + tier2_gpr_16 = (tier2_mem.aot_load8(tier2_gpr_29 + static_cast(608))); + tier2_gpr_4 = (tier2_gpr_4 & 255u); + tier2_gpr_4 = (tier2_gpr_4 | ctx.gpr[17]); + tier2_gpr_4 = (tier2_gpr_4 | tier2_gpr_16); + // Generated corpus boundary: unwind any logical tail-call frames first, + // then account the outer dispatch that this local edge removes. + if (tier2_pending_transfers != 0u) { + const std::uint32_t tier2_static_pending_ = tier2_pending_transfers; + tier2_pending_transfers = 0u; + if (!tier2_complete_shadow(tier2_static_pending_)) { + tier2_gpr_shadow_valid = false; + TIER2_SB_RETURN(); + } + } + ctx.pc = 0x0889C000u; + TIER2_GPR_SYNC_OUT(); + if (!rt.account_inlined_dispatch_boundary(ctx)) { + tier2_gpr_shadow_valid = false; + TIER2_SB_RETURN(); + } + TIER2_GPR_SYNC_IN(); + goto SB_L_0889C000; +SB_L_0889C000: + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C008; + } + +SB_L_0889C008: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(628))); + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C024; + } + goto SB_L_0889C014; + } + +SB_L_0889C014: + ctx.gpr[31] = (0x0889C01Cu); + tier2_gpr_4 = (tier2_gpr_18 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0036_entry, 36u, 434u, 0x088961FCu>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C01Cu) goto SB_L_0889C01C; + TIER2_SB_RETURN(); + +SB_L_0889C01C: + { const bool branch_taken = ctx.gpr[2] != 0u; + // nop + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C024; + } + +SB_L_0889C024: + tier2_gpr_4 = (tier2_mem.aot_load16(ctx.gpr[28] + static_cast(-25492))); + tier2_mem.aot_store16(tier2_gpr_18 + static_cast(84), static_cast(tier2_gpr_4)); + ctx.gpr[19] = (0u | 0u); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(16))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(336), std::bit_cast(ctx.fpr[12])); + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(72))); + tier2_gpr_4 = (tier2_gpr_4 & 14u); + tier2_gpr_4 = (tier2_gpr_4 ^ 6u); + tier2_gpr_4 = (tier2_gpr_4 < static_cast(1) ? 1u : 0u); + tier2_gpr_4 = (tier2_gpr_4 & 255u); + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C0F8; + } + goto SB_L_0889C054; + } + +SB_L_0889C054: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(72))); + tier2_gpr_4 = (tier2_gpr_4 & 512u); + tier2_gpr_4 = (0u < tier2_gpr_4 ? 1u : 0u); + tier2_gpr_4 = (tier2_gpr_4 & 255u); + { const bool branch_taken = tier2_gpr_4 != 0u; + // nop + if (branch_taken) { + goto SB_L_0889C0C0; + } + goto SB_L_0889C06C; + } + +SB_L_0889C06C: + { const bool branch_taken = ctx.gpr[17] == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C084; + } + goto SB_L_0889C074; + } + +SB_L_0889C074: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(2228))); + tier2_gpr_5 = (0u | 58u); + { const bool branch_taken = tier2_gpr_4 == tier2_gpr_5; + // nop + if (branch_taken) { + goto SB_L_0889C0C0; + } + goto SB_L_0889C084; + } + +SB_L_0889C084: + { const bool branch_taken = tier2_gpr_16 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C0B8; + } + goto SB_L_0889C08C; + } + +SB_L_0889C08C: + ctx.gpr[31] = (0x0889C094u); + tier2_gpr_4 = (tier2_gpr_18 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0067_entry, 67u, 195u, 0x08910B38u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C094u) goto SB_L_0889C094; + TIER2_SB_RETURN(); + +SB_L_0889C094: + { const bool branch_taken = ctx.gpr[2] == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C0B8; + } + goto SB_L_0889C09C; + } + +SB_L_0889C09C: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(1152))); + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C0B8; + } + goto SB_L_0889C0A8; + } + +SB_L_0889C0A8: + ctx.gpr[31] = (0x0889C0B0u); + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(1152))); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0191_entry, 191u, 409u, 0x08B017A8u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C0B0u) goto SB_L_0889C0B0; + TIER2_SB_RETURN(); + +SB_L_0889C0B0: + { const bool branch_taken = ctx.gpr[2] != 0u; + // nop + if (branch_taken) { + goto SB_L_0889C0C0; + } + goto SB_L_0889C0B8; + } + +SB_L_0889C0B8: + { const bool branch_taken = 0u == 0u; + ctx.gpr[19] = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C26C; + } + goto SB_L_0889C0C0; + } + +SB_L_0889C0C0: + tier2_gpr_4 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(tier2_gpr_18 + static_cast(86)))))); + tier2_gpr_6 = (tier2_mem.aot_load32(ctx.gpr[28] + static_cast(7656))); + tier2_gpr_6 = (static_cast(tier2_gpr_4) < static_cast(tier2_gpr_6) ? 1u : 0u); + { const bool branch_taken = tier2_gpr_6 == 0u; + tier2_gpr_5 = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C0E4; + } + goto SB_L_0889C0D4; + } + +SB_L_0889C0D4: + tier2_gpr_4 = (tier2_gpr_4 << 2u); + tier2_gpr_5 = (tier2_mem.aot_load32(ctx.gpr[28] + static_cast(24))); + tier2_gpr_4 = (tier2_gpr_5 + tier2_gpr_4); + tier2_gpr_5 = (tier2_mem.aot_load32(tier2_gpr_4 + static_cast(0))); + goto SB_L_0889C0E4; + +SB_L_0889C0E4: + tier2_gpr_4 = (tier2_gpr_5 | 0u); + ctx.gpr[31] = (0x0889C0F0u); + tier2_gpr_5 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(80))); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0063_entry, 63u, 664u, 0x089039E4u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C0F0u) goto SB_L_0889C0F0; + TIER2_SB_RETURN(); + +SB_L_0889C0F0: + { const bool branch_taken = 0u == 0u; + ctx.gpr[19] = (ctx.gpr[2] | 0u); + if (branch_taken) { + goto SB_L_0889C26C; + } + goto SB_L_0889C0F8; + } + +SB_L_0889C0F8: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(72))); + tier2_gpr_4 = (tier2_gpr_4 & 14u); + tier2_gpr_4 = (tier2_gpr_4 ^ 14u); + tier2_gpr_4 = (tier2_gpr_4 < static_cast(1) ? 1u : 0u); + tier2_gpr_4 = (tier2_gpr_4 & 255u); + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C23C; + } + goto SB_L_0889C114; + } + +SB_L_0889C114: + tier2_gpr_16 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(352))); + { const bool branch_taken = tier2_gpr_16 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C158; + } + goto SB_L_0889C120; + } + +SB_L_0889C120: + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(640), ctx.gpr[21]); + tier2_mem.aot_store8(tier2_gpr_29 + static_cast(596), static_cast(ctx.gpr[17])); + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_16 + static_cast(108))); + ctx.gpr[17] = (tier2_gpr_4 + static_cast(16)); + tier2_gpr_4 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(ctx.gpr[17] + static_cast(0)))))); + ctx.gpr[31] = (0x0889C13Cu); + ctx.gpr[21] = (tier2_gpr_16 + tier2_gpr_4); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0115_entry, 115u, 419u, 0x089D273Cu>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C13Cu) goto SB_L_0889C13C; + TIER2_SB_RETURN(); + +SB_L_0889C13C: + tier2_gpr_6 = (tier2_mem.aot_load32(ctx.gpr[17] + static_cast(4))); + tier2_gpr_4 = (ctx.gpr[21] | 0u); + jump_target = tier2_gpr_6; + ctx.gpr[31] = (0x0889C14Cu); + tier2_gpr_5 = (ctx.gpr[2] | 0u); + ctx.pc = jump_target; + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_call(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C14Cu) goto SB_L_0889C14C; + TIER2_SB_RETURN(); + +SB_L_0889C14C: + ctx.gpr[17] = (tier2_mem.aot_load8(tier2_gpr_29 + static_cast(596))); + { const bool branch_taken = ctx.gpr[2] != 0u; + ctx.gpr[21] = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(640))); + if (branch_taken) { + goto SB_L_0889C160; + } + goto SB_L_0889C158; + } + +SB_L_0889C158: + { const bool branch_taken = 0u == 0u; + tier2_gpr_16 = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C160; + } + goto SB_L_0889C160; + } + +SB_L_0889C160: + { const bool branch_taken = tier2_gpr_16 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C204; + } + goto SB_L_0889C168; + } + +SB_L_0889C168: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(72))); + tier2_gpr_4 = (tier2_gpr_4 & 512u); + tier2_gpr_4 = (0u < tier2_gpr_4 ? 1u : 0u); + tier2_gpr_4 = (tier2_gpr_4 & 255u); + { const bool branch_taken = tier2_gpr_4 != 0u; + // nop + if (branch_taken) { + goto SB_L_0889C1CC; + } + goto SB_L_0889C180; + } + +SB_L_0889C180: + { const bool branch_taken = ctx.gpr[17] == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C1C4; + } + goto SB_L_0889C188; + } + +SB_L_0889C188: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_16 + static_cast(96))); + if (tier2_gpr_4 != 0u) { + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_16 + static_cast(96))); + goto SB_L_0889C1B4; + } + goto SB_L_0889C194; + +SB_L_0889C194: + tier2_gpr_5 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(tier2_gpr_16 + static_cast(10)))))); + tier2_gpr_6 = (tier2_gpr_29 + static_cast(384)); + ctx.gpr[31] = (0x0889C1A4u); + tier2_gpr_4 = (tier2_gpr_16 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0166_entry, 166u, 47u, 0x08A9C6FCu>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C1A4u) goto SB_L_0889C1A4; + TIER2_SB_RETURN(); + +SB_L_0889C1A4: + tier2_mem.aot_store32(tier2_gpr_16 + static_cast(96), ctx.gpr[2]); + tier2_gpr_4 = (tier2_mem.aot_load8(tier2_gpr_29 + static_cast(384))); + tier2_mem.aot_store8(tier2_gpr_16 + static_cast(4), static_cast(tier2_gpr_4)); + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_16 + static_cast(96))); + goto SB_L_0889C1B4; + +SB_L_0889C1B4: + tier2_gpr_4 = (tier2_mem.aot_load8(tier2_gpr_4 + static_cast(180))); + tier2_gpr_5 = (0u | 58u); + { const bool branch_taken = tier2_gpr_4 == tier2_gpr_5; + // nop + if (branch_taken) { + goto SB_L_0889C1CC; + } + goto SB_L_0889C1C4; + } + +SB_L_0889C1C4: + { const bool branch_taken = 0u == 0u; + ctx.gpr[19] = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C234; + } + goto SB_L_0889C1CC; + } + +SB_L_0889C1CC: + tier2_gpr_4 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(tier2_gpr_18 + static_cast(86)))))); + tier2_gpr_6 = (tier2_mem.aot_load32(ctx.gpr[28] + static_cast(7656))); + tier2_gpr_6 = (static_cast(tier2_gpr_4) < static_cast(tier2_gpr_6) ? 1u : 0u); + { const bool branch_taken = tier2_gpr_6 == 0u; + tier2_gpr_5 = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C1F0; + } + goto SB_L_0889C1E0; + } + +SB_L_0889C1E0: + tier2_gpr_4 = (tier2_gpr_4 << 2u); + tier2_gpr_5 = (tier2_mem.aot_load32(ctx.gpr[28] + static_cast(24))); + tier2_gpr_4 = (tier2_gpr_5 + tier2_gpr_4); + tier2_gpr_5 = (tier2_mem.aot_load32(tier2_gpr_4 + static_cast(0))); + goto SB_L_0889C1F0; + +SB_L_0889C1F0: + tier2_gpr_4 = (tier2_gpr_5 | 0u); + ctx.gpr[31] = (0x0889C1FCu); + tier2_gpr_5 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(80))); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0063_entry, 63u, 664u, 0x089039E4u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C1FCu) goto SB_L_0889C1FC; + TIER2_SB_RETURN(); + +SB_L_0889C1FC: + { const bool branch_taken = 0u == 0u; + ctx.gpr[19] = (ctx.gpr[2] | 0u); + if (branch_taken) { + goto SB_L_0889C234; + } + goto SB_L_0889C204; + } + +SB_L_0889C204: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(72))); + tier2_gpr_4 = (tier2_gpr_4 & 512u); + tier2_gpr_4 = (0u < tier2_gpr_4 ? 1u : 0u); + tier2_gpr_4 = (tier2_gpr_4 & 255u); + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C234; + } + goto SB_L_0889C21C; + } + +SB_L_0889C21C: + tier2_gpr_4 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(tier2_gpr_18 + static_cast(86)))))); + tier2_gpr_4 = (tier2_gpr_4 << 2u); + tier2_gpr_5 = (tier2_mem.aot_load32(ctx.gpr[28] + static_cast(24))); + tier2_gpr_4 = (tier2_gpr_5 + tier2_gpr_4); + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_4 + static_cast(0))); + ctx.gpr[19] = (tier2_mem.aot_load32(tier2_gpr_4 + static_cast(20))); + goto SB_L_0889C234; + +SB_L_0889C234: + { const bool branch_taken = 0u == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C26C; + } + goto SB_L_0889C23C; + } + +SB_L_0889C23C: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(72))); + tier2_gpr_4 = (tier2_gpr_4 & 512u); + tier2_gpr_4 = (0u < tier2_gpr_4 ? 1u : 0u); + tier2_gpr_4 = (tier2_gpr_4 & 255u); + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C26C; + } + goto SB_L_0889C254; + } + +SB_L_0889C254: + tier2_gpr_4 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(tier2_gpr_18 + static_cast(86)))))); + tier2_gpr_4 = (tier2_gpr_4 << 2u); + tier2_gpr_5 = (tier2_mem.aot_load32(ctx.gpr[28] + static_cast(24))); + tier2_gpr_4 = (tier2_gpr_5 + tier2_gpr_4); + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_4 + static_cast(0))); + ctx.gpr[19] = (tier2_mem.aot_load32(tier2_gpr_4 + static_cast(20))); + goto SB_L_0889C26C; + +SB_L_0889C26C: + { const bool branch_taken = ctx.gpr[19] == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C388; + } + goto SB_L_0889C274; + } + +SB_L_0889C274: + ctx.gpr[17] = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(632))); + tier2_gpr_16 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(612))); + ctx.gpr[17] = (ctx.gpr[17] & 255u); + tier2_gpr_16 = (tier2_gpr_16 & 255u); + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(600))); + tier2_gpr_6 = (ctx.gpr[19] + static_cast(16)); + ctx.gpr[7] = (tier2_gpr_29 + static_cast(464)); + ctx.gpr[31] = (0x0889C298u); + tier2_gpr_5 = (tier2_gpr_18 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0043_entry, 43u, 207u, 0x088B1820u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C298u) goto SB_L_0889C298; + TIER2_SB_RETURN(); + +SB_L_0889C298: + { const bool branch_taken = ctx.gpr[2] != 0u; + tier2_gpr_4 = (tier2_gpr_29 + static_cast(464)); + if (branch_taken) { + goto SB_L_0889C2A8; + } + goto SB_L_0889C2A0; + } + +SB_L_0889C2A0: + { const bool branch_taken = 0u == 0u; + tier2_gpr_4 = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C378; + } + goto SB_L_0889C2A8; + } + +SB_L_0889C2A8: + ctx.gpr[7] = (tier2_gpr_29 + static_cast(16)); + tier2_gpr_5 = (ctx.gpr[19] | 0u); + tier2_gpr_6 = (ctx.gpr[20] | 0u); + ctx.gpr[8] = (ctx.gpr[17] | 0u); + ctx.gpr[31] = (0x0889C2C0u); + ctx.gpr[9] = (tier2_gpr_16 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0043_entry, 43u, 484u, 0x088B3CECu>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C2C0u) goto SB_L_0889C2C0; + TIER2_SB_RETURN(); + +SB_L_0889C2C0: + if (ctx.gpr[2] != 0u) { + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(0))); + goto SB_L_0889C2D0; + } + goto SB_L_0889C2C8; + +SB_L_0889C2C8: + { const bool branch_taken = 0u == 0u; + tier2_gpr_4 = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C378; + } + goto SB_L_0889C2D0; + } + +SB_L_0889C2D0: + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(448), std::bit_cast(ctx.fpr[12])); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(4))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(452), std::bit_cast(ctx.fpr[12])); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(8))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(456), std::bit_cast(ctx.fpr[12])); + tier2_gpr_16 = (tier2_gpr_29 + static_cast(448)); + tier2_gpr_4 = (ctx.gpr[23] | 0u); + tier2_gpr_5 = (tier2_gpr_18 | 0u); + ctx.gpr[31] = (0x0889C2F8u); + tier2_gpr_6 = (tier2_gpr_16 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0035_entry, 35u, 194u, 0x08891710u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C2F8u) goto SB_L_0889C2F8; + TIER2_SB_RETURN(); + +SB_L_0889C2F8: + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[23] + static_cast(0))); + tier2_gpr_4 = (std::bit_cast(ctx.fpr[12])); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[23] + static_cast(4))); + tier2_gpr_5 = (std::bit_cast(ctx.fpr[13])); + ctx.fpr[14] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[23] + static_cast(8))); + tier2_gpr_6 = (std::bit_cast(ctx.fpr[14])); + { const std::uint32_t tier2_words[3]{tier2_gpr_4, tier2_gpr_5, tier2_gpr_6}; + tier2_mem.aot_store32_block(ctx.gpr[20] + static_cast(0), tier2_words); } + ctx.fpr[15] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(16))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(448), std::bit_cast(ctx.fpr[15])); + ctx.fpr[15] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(20))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(452), std::bit_cast(ctx.fpr[15])); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(24))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(456), std::bit_cast(ctx.fpr[12])); + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<4u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(16); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<5u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(32); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<6u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_16 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<7u, 4u>(vfpu_value); } + { float vfpu_matrix[16]{}, vfpu_target_raw[4]{}, vfpu_target[4]{}, vfpu_result[4]{}; + ctx.read_vfpu_matrix(vfpu_matrix, 36u, 3u); + ctx.read_vfpu_vector_ct<7u, 3u>(vfpu_target_raw); + constexpr std::uint32_t vfpu_side = 3u; + constexpr std::uint32_t vfpu_input_length = 3u; + for (std::uint32_t i = 0; i < 4u; ++i) vfpu_target[i] = i < vfpu_input_length ? vfpu_target_raw[i] : 0.0f; + if (vfpu_side - 1u >= vfpu_input_length) vfpu_target[vfpu_side - 1u] = 1.0f; + if constexpr (vfpu_side == 4u) { + psprecomp::vcs_tier2_mat4_vec_first3_ordered(vfpu_matrix, vfpu_target, vfpu_result); + } else { + for (std::uint32_t row = 0; row + 1u < vfpu_side; ++row) { + float sum = 0.0f; + for (std::uint32_t column = 0; column < vfpu_side; ++column) sum += vfpu_matrix[row * 4u + column] * vfpu_target[column]; + vfpu_result[row] = sum; + } + } + float vfpu_final_row[4]{vfpu_matrix[(vfpu_side - 1u) * 4u + 0u], vfpu_matrix[(vfpu_side - 1u) * 4u + 1u], + vfpu_matrix[(vfpu_side - 1u) * 4u + 2u], vfpu_matrix[(vfpu_side - 1u) * 4u + 3u]}; + ctx.apply_vfpu_source_prefix_ct<4u, 0u>(vfpu_final_row); + ctx.apply_vfpu_source_prefix_ct<4u, 1u>(vfpu_target); + for (std::uint32_t column = 0; column < 4u; ++column) vfpu_result[vfpu_side - 1u] += vfpu_final_row[column] * vfpu_target[column]; + const std::uint32_t vfpu_destination_prefix = ctx.vfpu_ctrl[2]; + const std::uint32_t vfpu_last_lane = vfpu_side - 1u; + ctx.vfpu_ctrl[2] = ((vfpu_destination_prefix & (1u << 8u)) << vfpu_last_lane) | + ((vfpu_destination_prefix & 3u) << (vfpu_last_lane * 2u)); + ctx.write_vfpu_vector_with_destination_prefix(vfpu_result, 0u, vfpu_side); } + { float vfpu_value[4]{}; ctx.read_vfpu_vector_ct<0u, 4u>(vfpu_value); + const std::uint32_t vfpu_address = ctx.gpr[23] + static_cast(0); + const std::uint32_t tier2_vfpu_words[4]{std::bit_cast(vfpu_value[0]), std::bit_cast(vfpu_value[1]), std::bit_cast(vfpu_value[2]), std::bit_cast(vfpu_value[3])}; + tier2_mem.aot_store32_block(vfpu_address, tier2_vfpu_words); } + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(620))); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[23] + static_cast(0))); + tier2_gpr_5 = (std::bit_cast(ctx.fpr[12])); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[23] + static_cast(4))); + tier2_gpr_6 = (std::bit_cast(ctx.fpr[13])); + ctx.fpr[14] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[23] + static_cast(8))); + ctx.gpr[7] = (std::bit_cast(ctx.fpr[14])); + { const std::uint32_t tier2_words[3]{tier2_gpr_5, tier2_gpr_6, ctx.gpr[7]}; + tier2_mem.aot_store32_block(tier2_gpr_4 + static_cast(0), tier2_words); } + tier2_gpr_4 = (0u | 1u); + goto SB_L_0889C378; + +SB_L_0889C378: + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C388; + } + goto SB_L_0889C380; + } + +SB_L_0889C380: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(604))); + tier2_mem.aot_store32(tier2_gpr_4 + static_cast(0), tier2_gpr_18); + goto SB_L_0889C388; + +SB_L_0889C388: + tier2_gpr_4 = (tier2_mem.aot_load8(tier2_gpr_29 + static_cast(624))); + { const bool branch_taken = tier2_gpr_4 == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C394; + } + +SB_L_0889C394: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_18 + static_cast(92))); + tier2_gpr_5 = (tier2_gpr_4 + static_cast(336)); + tier2_gpr_4 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(tier2_gpr_5 + static_cast(0)))))); + tier2_gpr_4 = (tier2_gpr_18 + tier2_gpr_4); + tier2_gpr_6 = (tier2_mem.aot_load32(tier2_gpr_5 + static_cast(4))); + jump_target = tier2_gpr_6; + ctx.gpr[31] = (0x0889C3B0u); + tier2_gpr_5 = (tier2_gpr_29 + static_cast(64)); + ctx.pc = jump_target; + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_call(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C3B0u) goto SB_L_0889C3B0; + TIER2_SB_RETURN(); + +SB_L_0889C3B0: + { const bool branch_taken = ctx.gpr[2] == 0u; + // nop + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C3B8; + } + +SB_L_0889C3B8: + tier2_gpr_16 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(612))); + tier2_gpr_16 = (tier2_gpr_16 & 255u); + ctx.gpr[17] = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(600))); + tier2_gpr_4 = (ctx.gpr[17] | 0u); + tier2_gpr_6 = (tier2_gpr_29 + static_cast(80)); + ctx.gpr[19] = (tier2_gpr_29 + static_cast(544)); + tier2_gpr_5 = (tier2_gpr_18 | 0u); + ctx.gpr[31] = (0x0889C3DCu); + ctx.gpr[7] = (ctx.gpr[19] | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0043_entry, 43u, 207u, 0x088B1820u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C3DCu) goto SB_L_0889C3DC; + TIER2_SB_RETURN(); + +SB_L_0889C3DC: + { const bool branch_taken = ctx.gpr[2] != 0u; + ctx.gpr[8] = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C3EC; + } + goto SB_L_0889C3E4; + } + +SB_L_0889C3E4: + { const bool branch_taken = 0u == 0u; + tier2_gpr_4 = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C4B8; + } + goto SB_L_0889C3EC; + } + +SB_L_0889C3EC: + tier2_gpr_5 = (tier2_gpr_29 + static_cast(64)); + tier2_gpr_6 = (tier2_gpr_29 + static_cast(32)); + tier2_gpr_4 = (ctx.gpr[19] | 0u); + ctx.gpr[7] = (tier2_gpr_29 + static_cast(336)); + ctx.gpr[31] = (0x0889C404u); + ctx.gpr[9] = (tier2_gpr_16 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0043_entry, 43u, 484u, 0x088B3CECu>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C404u) goto SB_L_0889C404; + TIER2_SB_RETURN(); + +SB_L_0889C404: + if (ctx.gpr[2] != 0u) { + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(32))); + goto SB_L_0889C414; + } + goto SB_L_0889C40C; + +SB_L_0889C40C: + { const bool branch_taken = 0u == 0u; + tier2_gpr_4 = (0u | 0u); + if (branch_taken) { + goto SB_L_0889C4B8; + } + goto SB_L_0889C414; + } + +SB_L_0889C414: + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(528), std::bit_cast(ctx.fpr[12])); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(36))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(532), std::bit_cast(ctx.fpr[12])); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(40))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(536), std::bit_cast(ctx.fpr[12])); + tier2_gpr_16 = (tier2_gpr_29 + static_cast(528)); + tier2_gpr_4 = (ctx.gpr[22] | 0u); + tier2_gpr_5 = (tier2_gpr_18 | 0u); + ctx.gpr[31] = (0x0889C43Cu); + tier2_gpr_6 = (tier2_gpr_16 | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0035_entry, 35u, 194u, 0x08891710u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C43Cu) goto SB_L_0889C43C; + TIER2_SB_RETURN(); + +SB_L_0889C43C: + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[22] + static_cast(0))); + tier2_gpr_4 = (std::bit_cast(ctx.fpr[12])); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[22] + static_cast(4))); + tier2_gpr_5 = (std::bit_cast(ctx.fpr[13])); + ctx.fpr[14] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[22] + static_cast(8))); + tier2_gpr_6 = (std::bit_cast(ctx.fpr[14])); + { const std::uint32_t tier2_words[3]{tier2_gpr_4, tier2_gpr_5, tier2_gpr_6}; + tier2_mem.aot_store32_block(tier2_gpr_29 + static_cast(32), tier2_words); } + ctx.fpr[15] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(48))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(528), std::bit_cast(ctx.fpr[15])); + ctx.fpr[15] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(52))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(532), std::bit_cast(ctx.fpr[15])); + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(56))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(536), std::bit_cast(ctx.fpr[12])); + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<4u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(16); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<5u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(32); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<6u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_16 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<7u, 4u>(vfpu_value); } + { float vfpu_matrix[16]{}, vfpu_target_raw[4]{}, vfpu_target[4]{}, vfpu_result[4]{}; + ctx.read_vfpu_matrix(vfpu_matrix, 36u, 3u); + ctx.read_vfpu_vector_ct<7u, 3u>(vfpu_target_raw); + constexpr std::uint32_t vfpu_side = 3u; + constexpr std::uint32_t vfpu_input_length = 3u; + for (std::uint32_t i = 0; i < 4u; ++i) vfpu_target[i] = i < vfpu_input_length ? vfpu_target_raw[i] : 0.0f; + if (vfpu_side - 1u >= vfpu_input_length) vfpu_target[vfpu_side - 1u] = 1.0f; + if constexpr (vfpu_side == 4u) { + psprecomp::vcs_tier2_mat4_vec_first3_ordered(vfpu_matrix, vfpu_target, vfpu_result); + } else { + for (std::uint32_t row = 0; row + 1u < vfpu_side; ++row) { + float sum = 0.0f; + for (std::uint32_t column = 0; column < vfpu_side; ++column) sum += vfpu_matrix[row * 4u + column] * vfpu_target[column]; + vfpu_result[row] = sum; + } + } + float vfpu_final_row[4]{vfpu_matrix[(vfpu_side - 1u) * 4u + 0u], vfpu_matrix[(vfpu_side - 1u) * 4u + 1u], + vfpu_matrix[(vfpu_side - 1u) * 4u + 2u], vfpu_matrix[(vfpu_side - 1u) * 4u + 3u]}; + ctx.apply_vfpu_source_prefix_ct<4u, 0u>(vfpu_final_row); + ctx.apply_vfpu_source_prefix_ct<4u, 1u>(vfpu_target); + for (std::uint32_t column = 0; column < 4u; ++column) vfpu_result[vfpu_side - 1u] += vfpu_final_row[column] * vfpu_target[column]; + const std::uint32_t vfpu_destination_prefix = ctx.vfpu_ctrl[2]; + const std::uint32_t vfpu_last_lane = vfpu_side - 1u; + ctx.vfpu_ctrl[2] = ((vfpu_destination_prefix & (1u << 8u)) << vfpu_last_lane) | + ((vfpu_destination_prefix & 3u) << (vfpu_last_lane * 2u)); + ctx.write_vfpu_vector_with_destination_prefix(vfpu_result, 0u, vfpu_side); } + { float vfpu_value[4]{}; ctx.read_vfpu_vector_ct<0u, 4u>(vfpu_value); + const std::uint32_t vfpu_address = ctx.gpr[22] + static_cast(0); + const std::uint32_t tier2_vfpu_words[4]{std::bit_cast(vfpu_value[0]), std::bit_cast(vfpu_value[1]), std::bit_cast(vfpu_value[2]), std::bit_cast(vfpu_value[3])}; + tier2_mem.aot_store32_block(vfpu_address, tier2_vfpu_words); } + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[22] + static_cast(0))); + tier2_gpr_4 = (std::bit_cast(ctx.fpr[12])); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[22] + static_cast(4))); + tier2_gpr_5 = (std::bit_cast(ctx.fpr[13])); + ctx.fpr[14] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[22] + static_cast(8))); + tier2_gpr_6 = (std::bit_cast(ctx.fpr[14])); + { const std::uint32_t tier2_words[3]{tier2_gpr_4, tier2_gpr_5, tier2_gpr_6}; + tier2_mem.aot_store32_block(tier2_gpr_29 + static_cast(48), tier2_words); } + tier2_gpr_4 = (0u | 1u); + goto SB_L_0889C4B8; + +SB_L_0889C4B8: + { const bool branch_taken = tier2_gpr_4 == 0u; + tier2_gpr_5 = (tier2_gpr_29 + static_cast(32)); + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C4C0; + } + +SB_L_0889C4C0: + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(16))); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(336))); + ctx.fcr31 = (ctx.fcr31 & ~0x00800000u) | (((ctx.fpr[12] <= ctx.fpr[13])) ? 0x00800000u : 0u); + // nop + { const bool branch_taken = ((ctx.fcr31 & 0x00800000u) != 0u); + // nop + if (branch_taken) { + goto SB_L_0889C4F4; + } + goto SB_L_0889C4D8; + } + +SB_L_0889C4D8: + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(336))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(16), std::bit_cast(ctx.fpr[12])); + ctx.gpr[31] = (0x0889C4E8u); + tier2_gpr_4 = (ctx.gpr[20] | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0000_entry, 0u, 157u, 0x08805288u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C4E8u) goto SB_L_0889C4E8; + TIER2_SB_RETURN(); + +SB_L_0889C4E8: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(604))); + { const bool branch_taken = 0u == 0u; + tier2_mem.aot_store32(tier2_gpr_4 + static_cast(0), tier2_gpr_18); + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C4F4; + } + +SB_L_0889C4F4: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(616))); + { const std::uint32_t vfpu_address = tier2_gpr_4 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<0u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = ctx.gpr[17] + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<1u, 4u>(vfpu_value); } + { float vfpu_s[4]{}, vfpu_t[4]{}, vfpu_d[4]{}; + ctx.read_vfpu_vector_with_source_prefix_ct<0u, 3u, 0u>(vfpu_s); + ctx.read_vfpu_vector_with_source_prefix_ct<1u, 3u, 1u>(vfpu_t); + for (std::uint32_t i = 0; i < 3u; ++i) vfpu_d[i] = vfpu_s[i] - vfpu_t[i]; + ctx.write_vfpu_vector_with_destination_prefix_ct<0u, 3u>(vfpu_d); } + { float vfpu_value[4]{}; ctx.read_vfpu_vector_ct<0u, 4u>(vfpu_value); + const std::uint32_t vfpu_address = ctx.gpr[21] + static_cast(0); + const std::uint32_t tier2_vfpu_words[4]{std::bit_cast(vfpu_value[0]), std::bit_cast(vfpu_value[1]), std::bit_cast(vfpu_value[2]), std::bit_cast(vfpu_value[3])}; + tier2_mem.aot_store32_block(vfpu_address, tier2_vfpu_words); } + { const std::uint32_t vfpu_address = ctx.gpr[21] + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<0u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<1u, 4u>(vfpu_value); } + ctx.execute_vfpu_vdot_ct<28u, 0u, 1u, 3u>(); + tier2_gpr_4 = (ctx.vfpu_scalar_bits_ct<28u>()); + ctx.fpr[12] = std::bit_cast(tier2_gpr_4); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(0))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(368), std::bit_cast(ctx.fpr[13])); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(4))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(372), std::bit_cast(ctx.fpr[13])); + ctx.fpr[13] = std::bit_cast(tier2_mem.aot_load32(ctx.gpr[20] + static_cast(8))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(376), std::bit_cast(ctx.fpr[13])); + tier2_gpr_4 = (tier2_gpr_29 + static_cast(368)); + { const std::uint32_t vfpu_address = tier2_gpr_4 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<0u, 4u>(vfpu_value); } + tier2_gpr_4 = (tier2_gpr_18 + static_cast(48)); + { const std::uint32_t vfpu_address = tier2_gpr_4 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<1u, 4u>(vfpu_value); } + { float vfpu_s[4]{}, vfpu_t[4]{}, vfpu_d[4]{}; + ctx.read_vfpu_vector_with_source_prefix_ct<0u, 3u, 0u>(vfpu_s); + ctx.read_vfpu_vector_with_source_prefix_ct<1u, 3u, 1u>(vfpu_t); + for (std::uint32_t i = 0; i < 3u; ++i) vfpu_d[i] = vfpu_s[i] - vfpu_t[i]; + ctx.write_vfpu_vector_with_destination_prefix_ct<0u, 3u>(vfpu_d); } + { float vfpu_value[4]{}; ctx.read_vfpu_vector_ct<0u, 4u>(vfpu_value); + const std::uint32_t vfpu_address = ctx.gpr[21] + static_cast(0); + const std::uint32_t tier2_vfpu_words[4]{std::bit_cast(vfpu_value[0]), std::bit_cast(vfpu_value[1]), std::bit_cast(vfpu_value[2]), std::bit_cast(vfpu_value[3])}; + tier2_mem.aot_store32_block(vfpu_address, tier2_vfpu_words); } + { const std::uint32_t vfpu_address = ctx.gpr[21] + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<0u, 4u>(vfpu_value); } + { const std::uint32_t vfpu_address = tier2_gpr_18 + static_cast(0); + std::uint32_t tier2_vfpu_words[4]{}; tier2_mem.aot_load32_block(vfpu_address, tier2_vfpu_words); + float vfpu_value[4]{ + std::bit_cast(tier2_vfpu_words[0]), + std::bit_cast(tier2_vfpu_words[1]), + std::bit_cast(tier2_vfpu_words[2]), + std::bit_cast(tier2_vfpu_words[3])}; + ctx.write_vfpu_vector_ct<1u, 4u>(vfpu_value); } + ctx.execute_vfpu_vdot_ct<28u, 0u, 1u, 3u>(); + tier2_gpr_4 = (ctx.vfpu_scalar_bits_ct<28u>()); + ctx.fpr[13] = std::bit_cast(tier2_gpr_4); + ctx.fcr31 = (ctx.fcr31 & ~0x00800000u) | (((ctx.fpr[12] < ctx.fpr[20])) ? 0x00800000u : 0u); + // nop + { const bool branch_taken = !((ctx.fcr31 & 0x00800000u) != 0u); + // nop + if (branch_taken) { + goto SB_L_0889C580; + } + goto SB_L_0889C570; + } + +SB_L_0889C570: + ctx.fcr31 = (ctx.fcr31 & ~0x00800000u) | (((ctx.fpr[13] <= ctx.fpr[22])) ? 0x00800000u : 0u); + // nop + { const bool branch_taken = !((ctx.fcr31 & 0x00800000u) != 0u); + // nop + if (branch_taken) { + goto SB_L_0889C5A0; + } + goto SB_L_0889C580; + } + +SB_L_0889C580: + ctx.fcr31 = (ctx.fcr31 & ~0x00800000u) | (((ctx.fpr[12] <= ctx.fpr[24])) ? 0x00800000u : 0u); + // nop + { const bool branch_taken = ((ctx.fcr31 & 0x00800000u) != 0u); + // nop + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C590; + } + +SB_L_0889C590: + ctx.fcr31 = (ctx.fcr31 & ~0x00800000u) | (((ctx.fpr[13] < ctx.fpr[22])) ? 0x00800000u : 0u); + // nop + { const bool branch_taken = !((ctx.fcr31 & 0x00800000u) != 0u); + // nop + if (branch_taken) { + goto SB_L_0889C5B8; + } + goto SB_L_0889C5A0; + } + +SB_L_0889C5A0: + ctx.fpr[12] = std::bit_cast(tier2_mem.aot_load32(tier2_gpr_29 + static_cast(336))); + tier2_mem.aot_store32(tier2_gpr_29 + static_cast(16), std::bit_cast(ctx.fpr[12])); + ctx.gpr[31] = (0x0889C5B0u); + tier2_gpr_4 = (ctx.gpr[20] | 0u); + if (([&]() { TIER2_GPR_SYNC_OUT(); const bool tier2_same_ = (rt.invoke_chained_direct<&recomp_unit_0000_entry, 0u, 157u, 0x08805288u>(ctx, &aot_mem)); if (tier2_same_) TIER2_GPR_SYNC_IN(); else tier2_gpr_shadow_valid = false; return tier2_same_; }()) && ctx.pc == 0x0889C5B0u) goto SB_L_0889C5B0; + TIER2_SB_RETURN(); + +SB_L_0889C5B0: + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(604))); + tier2_mem.aot_store32(tier2_gpr_4 + static_cast(0), tier2_gpr_18); + goto SB_L_0889C5B8; + +SB_L_0889C5B8: + { const bool branch_taken = ctx.gpr[30] != 0u; + // nop + if (branch_taken) { + if (!rt.tier2_enter_fused_transfer<37u, 0x0889BFC0u>(ctx)) { + ctx.pc = 0x0889BFC0u; + TIER2_SB_RETURN(); + } + ++tier2_pending_transfers; + ++tier2_stats.fused_tail_edges; + goto SB_L_0889BFC0; + } + ++tier2_stats.cold_exits; tier2_scope.finish(); TIER2_GPR_BEFORE_COLD(); psprecomp::recomp_unit_0038_entry(rt, ctx, 76u, aot_mem); TIER2_SB_RETURN(); + } +// TIER2_GPR_BODY_END + +#undef TIER2_SB_RETURN +#undef TIER2_GPR_BEFORE_COLD +#undef TIER2_GPR_SYNC_IN +#undef TIER2_GPR_SYNC_OUT +} + +} // namespace vcs diff --git a/profiles/vcs/host/vcs_tier2_cluster_edge43.cpp b/profiles/vcs/host/vcs_tier2_cluster_edge43.cpp index a429871..8194acd 100644 --- a/profiles/vcs/host/vcs_tier2_cluster_edge43.cpp +++ b/profiles/vcs/host/vcs_tier2_cluster_edge43.cpp @@ -67,6 +67,7 @@ TIER2_FUSED_RETURN_DISPATCH: case 0x088B1C2Cu: goto SB_L_088B1C2C; case 0x088B1C40u: goto SB_L_088B1C40; case 0x088B3FCCu: goto SB_L_088B3FCC; + case 0x088B3FFCu: goto SB_L_088B3FFC; case 0x088B4004u: goto SB_L_088B4004; case 0x088B4018u: goto SB_L_088B4018; case 0x088B4020u: goto SB_L_088B4020; @@ -142,6 +143,7 @@ TIER2_LOCAL_DISPATCH_U0043: case 0x088B1C2Cu: goto SB_L_088B1C2C; case 0x088B1C40u: goto SB_L_088B1C40; case 0x088B3FCCu: goto SB_L_088B3FCC; + case 0x088B3FFCu: goto SB_L_088B3FFC; default: ctx.pc = local_pc; TIER2_SB_RETURN(); @@ -209,6 +211,7 @@ TIER2_LOCAL_DISPATCH_U0044: TIER2_ENTRY_DISPATCH: switch (entry_pc) { case 0x088B3FCCu: goto SB_L_088B3FCC; + case 0x088B3FFCu: goto SB_L_088B3FFC; case 0x088B4004u: goto SB_L_088B4004; case 0x088B40F8u: goto SB_L_088B40F8; default: @@ -584,6 +587,24 @@ SB_L_088B3FCC: tier2_gpr_4 = (ctx.gpr[20] | 0u); goto SB_L_088B1780; +SB_L_088B3FFC: + if (ctx.gpr[2] == 0u) { + tier2_gpr_4 = (tier2_mem.aot_load32(tier2_gpr_29 + static_cast(48))); + if (!rt.tier2_enter_fused_transfer<44u, 0x088B40F8u>(ctx)) { + ctx.pc = 0x088B40F8u; + TIER2_SB_RETURN(); + } + ++tier2_pending_transfers; + ++tier2_stats.fused_tail_edges; + goto SB_L_088B40F8; + } + if (!rt.tier2_enter_fused_transfer<44u, 0x088B4004u>(ctx)) { + ctx.pc = 0x088B4004u; + TIER2_SB_RETURN(); + } + ++tier2_pending_transfers; + ++tier2_stats.fused_tail_edges; + goto SB_L_088B4004; SB_L_088B4004: tier2_gpr_17 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(ctx.gpr[18] + static_cast(6)))))); tier2_gpr_4 = (static_cast(static_cast(static_cast(tier2_mem.aot_load16(ctx.gpr[18] + static_cast(14)))))); diff --git a/profiles/vcs/host/vcs_tier2_superblocks.cpp b/profiles/vcs/host/vcs_tier2_superblocks.cpp index 4b3fba3..a5d4ef7 100644 --- a/profiles/vcs/host/vcs_tier2_superblocks.cpp +++ b/profiles/vcs/host/vcs_tier2_superblocks.cpp @@ -63,6 +63,7 @@ const char *tier2_cluster_name(Tier2ClusterId id) noexcept { case Tier2ClusterId::Physics: return "physics"; case Tier2ClusterId::World: return "world"; case Tier2ClusterId::Edge43: return "edge43"; + case Tier2ClusterId::CollisionLoop: return "collisionloop"; default: return "unknown"; } } diff --git a/profiles/vcs/host/vcs_tier2_superblocks.hpp b/profiles/vcs/host/vcs_tier2_superblocks.hpp index 3a1e4ff..552f355 100644 --- a/profiles/vcs/host/vcs_tier2_superblocks.hpp +++ b/profiles/vcs/host/vcs_tier2_superblocks.hpp @@ -22,7 +22,8 @@ enum class Tier2ClusterId : std::uint32_t { Physics = 4u, // 0129 hot transform/physics function World = 5u, // 0157/0158 dominant world/streaming hot functions Edge43 = 6u, // 0043/0044 cross-unit boundary - Count = 7u, + CollisionLoop = 7u, // 0037/0038 measured generated-boundary loop + Count = 8u, }; constexpr std::size_t kTier2ClusterCount = static_cast(Tier2ClusterId::Count); @@ -135,5 +136,7 @@ void tier2_superblock_world(psprecomp::Runtime &, psprecomp::AllegrexContext &, psprecomp::GuestMemory::AotFastView &, std::uint32_t entry_pc); void tier2_superblock_edge43(psprecomp::Runtime &, psprecomp::AllegrexContext &, psprecomp::GuestMemory::AotFastView &, std::uint32_t entry_pc); +void tier2_superblock_collisionloop(psprecomp::Runtime &, psprecomp::AllegrexContext &, + psprecomp::GuestMemory::AotFastView &, std::uint32_t entry_pc); } // namespace vcs diff --git a/profiles/vcs/tests/check_v827_save_thread_lifecycle.py b/profiles/vcs/tests/check_v827_save_thread_lifecycle.py index bd346d0..8a68fdd 100644 --- a/profiles/vcs/tests/check_v827_save_thread_lifecycle.py +++ b/profiles/vcs/tests/check_v827_save_thread_lifecycle.py @@ -18,16 +18,16 @@ def need(cond, msg): raise SystemExit(1) print('PASS:', msg) -need(('stage=correctness-v8.2.7-save-thread-lifecycle-fix-2026-08-18' in log) or ('stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18' in log), 'V8.2.7/V8.2.7A runtime stage') -need(('correctness_revision=827 ' in log) or ('correctness_revision=8271 ' in log), 'V8.2.7/V8.2.7A correctness revision') +need(any(stage in log for stage in ('stage=correctness-v8.2.7-save-thread-lifecycle-fix-2026-08-18', 'stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18', 'stage=perf-v8.3-cpu-boundary-fusion-2026-08-18')), 'V8.2.7 lifecycle fix preserved in current runtime stage') +need(('correctness_revision=827 ' in log) or ('correctness_revision=8271 ' in log), 'V8.2.7/V8.2.7A correctness revision preserved') need('save_exitdelete_semantics=1' in log and 'save_repro_legacy_exitdelete_repair=1' in log and 'save_partition_reuse=1' in log, 'ExitDelete/partition fix and migration metadata') need('atrac_stream_resident_status=1' in log and 'atrac_nonloop_resident=-2' in log and 'atrac_loop_resident=-3' in log and 'news_atrac_v825_guard=1' in log, 'working V8.2.5 NEWS semantics preserved') need('output2_late_catchup=0' in log, 'rejected Output2 pacing experiment remains disabled') -need('hot_blocks=1060' in log and 'static_fused_calls=36' in log and 'geometry_fusion_rollback=1' in log, - 'V8.2 CPU/Tier2 shape preserved') +need('static_fused_calls=36' in log and 'geometry_fusion_rollback=1' in log and 'geometry_inline_leaf_sites=0' in log, + 'V8.2 Geometry rollback and conservative fusion shape preserved') # Core correctness: ExitThread remains dormant/Completed, ExitDelete actually # destroys the object and releases its stack. diff --git a/profiles/vcs/tests/check_v827a_internal_save_repro_gate.py b/profiles/vcs/tests/check_v827a_internal_save_repro_gate.py index 4c73879..6fecc1a 100644 --- a/profiles/vcs/tests/check_v827a_internal_save_repro_gate.py +++ b/profiles/vcs/tests/check_v827a_internal_save_repro_gate.py @@ -19,8 +19,9 @@ def need(cond, msg): raise SystemExit(1) print('PASS:', msg) -need('stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18' in log, - 'V8.2.7A runtime stage') +need(any(stage in log for stage in ('stage=correctness-v8.2.7a-internal-save-repro-gate-2026-08-18', + 'stage=perf-v8.3-cpu-boundary-fusion-2026-08-18')), + 'V8.2.7A gate preserved in current runtime stage') need('correctness_revision=8271' in log, 'V8.2.7A correctness revision') need('save_repro_internal_ini_gate=1' in log and 'save_repro_default_enabled=0' in log, 'internal-only gate metadata') @@ -56,7 +57,7 @@ for token, label in [ ('atrac_nonloop_resident=-2', 'NEWS non-loop ATRAC sentinel preserved'), ('atrac_loop_resident=-3', 'NEWS loop ATRAC sentinel preserved'), ('output2_late_catchup=0', 'rejected Output2 pacing remains off'), - ('hot_blocks=1060', 'V8.2 CPU shape preserved'), + ('geometry_fusion_rollback=1', 'V8.2 Geometry rollback preserved'), ('geometry_fusion_rollback=1', 'Geometry rollback preserved'), ]: need(token in log, label) diff --git a/profiles/vcs/tests/check_v83_cpu_boundary_fusion.py b/profiles/vcs/tests/check_v83_cpu_boundary_fusion.py new file mode 100644 index 0000000..118b33d --- /dev/null +++ b/profiles/vcs/tests/check_v83_cpu_boundary_fusion.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python3 +from pathlib import Path + +root = Path(__file__).resolve().parents[3] +profile = root / 'profiles' / 'vcs' +host = profile / 'host' +tools = profile / 'tools' +gen = profile / 'generated' + +generator = (tools / 'build_tier2_superblocks.py').read_text(encoding='utf-8') +hpp = (host / 'vcs_tier2_superblocks.hpp').read_text(encoding='utf-8') +common = (host / 'vcs_tier2_superblocks.cpp').read_text(encoding='utf-8') +cmake = (profile / 'CMakeLists.txt').read_text(encoding='utf-8') +log = (host / 'vcs_runtime_log.cpp').read_text(encoding='utf-8') +collision = (host / 'vcs_tier2_cluster_collisionloop.cpp').read_text(encoding='utf-8') +edge = (host / 'vcs_tier2_cluster_edge43.cpp').read_text(encoding='utf-8') +u37 = (gen / 'generated_unit_0037.cpp').read_text(encoding='utf-8') +u38 = (gen / 'generated_unit_0038.cpp').read_text(encoding='utf-8') +u43 = (gen / 'generated_unit_0043.cpp').read_text(encoding='utf-8') +geometry = (host / 'vcs_tier2_cluster_geometry.cpp').read_text(encoding='utf-8') +world = (host / 'vcs_tier2_cluster_world.cpp').read_text(encoding='utf-8') +runtime_hpp = (root / 'include' / 'psprecomp' / 'runtime.hpp').read_text(encoding='utf-8') + +def need(cond, msg): + if not cond: + print('FAIL:', msg) + raise SystemExit(1) + print('PASS:', msg) + +need('stage=perf-v8.3-cpu-boundary-fusion-2026-08-18' in log, 'V8.3 runtime stage') +need('perf_layer=9 cpu_lean_revision=3 correctness_revision=8271' in log, + 'performance revision advances without changing protected correctness revision') +need('clusters=8' in log and 'hot_blocks=1139' in log and 'static_fused_calls=36' in log and + 'static_fused_tail=18' in log and 'static_pc_fused=1' in log, + 'generated Tier-2 V8.3 shape matches audited generator output') +need('cpu_boundary_fusion=1' in log and 'edge43_continuation_fused=1' in log and + 'collisionloop_blocks=78' in log and 'collisionloop_static_pc_fused=1' in log and 'collisionloop_scheduler_accounting=1' in log, + 'boundary-fusion metadata present') + +need('fuse_static_pc_returns: bool = False' in generator and 'STATIC_PC_RETURN_RE' in generator, + 'static PC return fusion is explicit and opt-in') +need("key='collisionloop'" in generator and 'fuse_static_pc_returns=True' in generator, + 'only dedicated collision-loop cluster opts into generated-boundary fusion') +need(generator.count('fuse_static_pc_returns=True') == 1, + 'legacy Tier-2 clusters cannot silently change boundary semantics') +need('37: [(0x0889BFC0, 0x0889C000)]' in generator and + '38: [(0x0889C000, 0x0889C5C0)]' in generator, + 'collision-loop window remains narrowly bounded to units 0037/0038') +need('seeds={43: [0x088B3FCC, 0x088B3FFC]' in generator, + 'Edge43 includes measured missing continuation 0x088B3FFC') + +need('account_inlined_dispatch_boundary' in runtime_hpp and 'return account_inlined_dispatch_boundary(ctx);' in runtime_hpp, + 'generic inlined-dispatch accounting preserves starvation cadence and backs leaf accounting') + +need('CollisionLoop = 7u' in hpp and 'Count = 8u' in hpp and + 'tier2_superblock_collisionloop' in hpp, + 'eighth cluster is registered in Tier-2 ABI') +need('case Tier2ClusterId::CollisionLoop: return "collisionloop";' in common, + 'collision-loop cluster has runtime identity') +need('host/vcs_tier2_cluster_collisionloop.cpp' in cmake, + 'collision-loop translation unit is compiled') + +need('SB_L_0889BFC0:' in collision and 'SB_L_0889C000:' in collision and + 'account_inlined_dispatch_boundary(ctx)' in collision and 'goto SB_L_0889C000;' in collision, + 'unit0037 -> unit0038 boundary is local while retaining outer-dispatch scheduler accounting') +need('goto SB_L_0889BFC0;' in collision, + 'hot loop closes back into unit0037 without outer Runtime dispatch') +need('tier2_enter_fused_transfer<37u, 0x0889BFC0u>' in collision and + 'tier2_complete_shadow(tier2_static_pending_)' in collision, + 'real tail-call frames unwind before the fused outer boundary, preserving accounting order') +need('tier2_superblock_collisionloop(rt, ctx, aot_mem, 0x0889BFC0u)' in u37 and + 'tier2_superblock_collisionloop(rt, ctx, aot_mem, 0x0889C000u)' in u38 and + 'tier2_superblock_collisionloop(rt, ctx, aot_mem, 0x0889C5B8u)' in u38, + 'measured loop entry hooks are installed') + +need('SB_L_088B3FFC:' in edge and 'case 0x088B3FFCu: goto SB_L_088B3FFC;' in edge, + 'Edge43 local-return dispatch owns the missing continuation') +need('tier2_enter_fused_transfer<44u, 0x088B40F8u>' in edge and + 'tier2_enter_fused_transfer<44u, 0x088B4004u>' in edge, + 'Edge43 continuation flows directly into selected unit0044 targets') +need('tier2_superblock_edge43(rt, ctx, aot_mem, 0x088B3FFCu)' in u43, + '0x088B3FFC outer-entry hook is installed for measured fallback cases') + +# Guard against repeating V8 broad geometry/world expansion. +need(geometry.count('\nSB_L_') == 379, 'Geometry remains exactly 379 selected blocks') +need(world.count('\nSB_L_') == 402, 'World remains exactly 402 selected blocks') +need(len(collision.splitlines()) == 1363, 'new collision-loop body stays small (1363 lines)') +need(len(edge.splitlines()) == 949, 'Edge43 expansion stays small (949 lines)') + +# Current correctness regression guards. +for token, label in [ + ('correctness_revision=8271', 'Save lifecycle correctness revision'), + ('save_exitdelete_semantics=1', 'ExitDelete lifecycle fix'), + ('save_partition_reuse=1', 'partition-memory reuse fix'), + ('save_repro_internal_ini_gate=1', 'internal SAVE_REPRO gate'), + ('save_repro_default_enabled=0', 'SAVE_REPRO disabled by default'), + ('atrac_nonloop_resident=-2', 'NEWS non-loop ATRAC resident sentinel'), + ('atrac_loop_resident=-3', 'NEWS loop ATRAC resident sentinel'), + ('output2_late_catchup=0', 'rejected Output2 pacing remains off'), + ('geometry_fusion_rollback=1', 'rejected V8 Geometry expansion remains rolled back'), + ('ge_async_default=0', 'GE async remains quarantined'), + ('parallel_vertex_decode_default=0', 'parallel vertex decode remains quarantined'), +]: + need(token in log, label) + +print('V8.3 CPU BOUNDARY FUSION audit PASS') diff --git a/profiles/vcs/tools/build_tier2_superblocks.py b/profiles/vcs/tools/build_tier2_superblocks.py index a1edd7a..9a24dd9 100644 --- a/profiles/vcs/tools/build_tier2_superblocks.py +++ b/profiles/vcs/tools/build_tier2_superblocks.py @@ -39,6 +39,11 @@ TAIL_CALL_RE = re.compile( r'(?P[ \t]*)\(void\)rt\.invoke_chained_direct<&recomp_unit_(?P\d+)_entry, ' r'(?P\d+)u, (?P\d+)u, (?P0x[0-9A-F]+)u>' r'\(ctx, &aot_mem\); return;') +# Artificial generated-unit partition boundaries are not guest calls. +STATIC_PC_RETURN_RE = re.compile( + r'(?P[ \t]*)ctx\.pc = (?P0x[0-9A-F]+)u; return;') + + LOCAL_DISPATCH_SEQUENCE_RE = re.compile( r'(?P[ \t]*)local_pc = (?P[^;]+);\n' r'(?P=indent)if \(\+\+local_transfers < 256u\) \{ entry_id = 0u; goto LOCAL_DISPATCH; \}\n' @@ -132,6 +137,10 @@ class Cluster: expand_cross_units: bool = False hooks: Dict[int, List[int]] = dataclasses.field(default_factory=dict) max_blocks: int = 700 + # Opt-in fusion for plain generated corpus boundaries of the form + # `ctx.pc = constant; return;`. Disabled for all legacy clusters. + # These boundaries are not guest calls and therefore add no scheduler frame. + fuse_static_pc_returns: bool = False CLUSTERS: List[Cluster] = [ @@ -190,10 +199,26 @@ CLUSTERS: List[Cluster] = [ ), Cluster( key='edge43', enum_name='Edge43', function='tier2_superblock_edge43', - seeds={43: [0x088B3FCC], 44: [0x088B4004, 0x088B40F8]}, + # Include the measured $ra continuation; omitting 0x088B3FFC forced an + # outer Runtime dispatch immediately before unit 0044. + seeds={43: [0x088B3FCC, 0x088B3FFC], 44: [0x088B4004, 0x088B40F8]}, expand_cross_units=True, - hooks={43: [0x088B3FCC], 44: [0x088B4004, 0x088B40F8]}, - max_blocks=100, + hooks={43: [0x088B3FCC, 0x088B3FFC], 44: [0x088B4004, 0x088B40F8]}, + max_blocks=110, + ), + Cluster( + key='collisionloop', enum_name='CollisionLoop', function='tier2_superblock_collisionloop', + seeds={}, + # Small measured loop straddling generated units 0037/0038. Keep the + # footprint intentionally bounded to avoid the rejected V8 Geometry bloat. + windows={ + 37: [(0x0889BFC0, 0x0889C000)], + 38: [(0x0889C000, 0x0889C5C0)], + }, + expand_cross_units=True, + hooks={37: [0x0889BFC0], 38: [0x0889C000, 0x0889C5B8]}, + max_blocks=140, + fuse_static_pc_returns=True, ), ] @@ -640,7 +665,8 @@ def selected_pc_owner(selected: Mapping[int, Set[int]]) -> Dict[int, int]: def transform_block(block: str, source_unit: int, selected: Mapping[int, Set[int]], sources: Mapping[int, UnitSource], stats: MutableMapping[str, int], - fused_continuations: MutableMapping[Tuple[int, int], int]) -> str: + fused_continuations: MutableMapping[Tuple[int, int], int], + fuse_static_pc_returns: bool = False) -> str: pc_owner = selected_pc_owner(selected) selected_all = set(pc_owner) text = re.sub(r'\bL_([0-9A-F]{8})\b', r'SB_L_\1', block) @@ -754,6 +780,37 @@ def transform_block(block: str, source_unit: int, selected: Mapping[int, Set[int text = TAIL_CALL_RE.sub(tail_repl, text) + # Fuse only opted-in plain constant-PC returns whose destination is already + # selected in the same superblock. No tier2_enter/complete call is needed: + # the original edge is merely an artificial generated-file boundary. + if fuse_static_pc_returns: + def static_pc_repl(m: re.Match[str]) -> str: + target = int(m.group('target'), 16) + if target not in selected_all: + return m.group(0) + stats['static_pc_fused'] += 1 + indent = m.group('indent') + return ( + f'{indent}// Generated corpus boundary: unwind any logical tail-call frames first,\n' + f'{indent}// then account the outer dispatch that this local edge removes.\n' + f'{indent}if (tier2_pending_transfers != 0u) {{\n' + f'{indent} const std::uint32_t tier2_static_pending_ = tier2_pending_transfers;\n' + f'{indent} tier2_pending_transfers = 0u;\n' + f'{indent} if (!tier2_complete_shadow(tier2_static_pending_)) {{\n' + f'{indent} tier2_gpr_shadow_valid = false;\n' + f'{indent} TIER2_SB_RETURN();\n' + f'{indent} }}\n' + f'{indent}}}\n' + f'{indent}ctx.pc = 0x{target:08X}u;\n' + f'{indent}TIER2_GPR_SYNC_OUT();\n' + f'{indent}if (!rt.account_inlined_dispatch_boundary(ctx)) {{\n' + f'{indent} tier2_gpr_shadow_valid = false;\n' + f'{indent} TIER2_SB_RETURN();\n' + f'{indent}}}\n' + f'{indent}TIER2_GPR_SYNC_IN();\n' + f'{indent}goto SB_L_{target:08X};') + text = STATIC_PC_RETURN_RE.sub(static_pc_repl, text) + # Standard generated indirect/local return path. The shared unit-specific # dispatcher below recognizes a fused-call continuation and performs exactly # one logical chain unwind before resuming the caller. @@ -798,7 +855,8 @@ def emit_cluster(cluster: Cluster, selected: Mapping[int, Set[int]], for pc in src.ordered_pcs: if pc not in selected[unit]: continue - chunks.append(transform_block(src.blocks[pc], unit, selected, sources, stats, continuations)) + chunks.append(transform_block(src.blocks[pc], unit, selected, sources, stats, continuations, + cluster.fuse_static_pc_returns)) # Entry hooks are intentionally narrower than the selected closure: only # measured roots pay the extra branch into Tier-2. @@ -998,6 +1056,8 @@ TIER2_ENTRY_DISPATCH: stats['lines'] = len(cpp.splitlines()) stats['units'] = len(selected) stats['hooks'] = sum(len(v) for v in cluster.hooks.values()) + if cluster.fuse_static_pc_returns and stats.get('fused_calls', 0) != 0: + raise RuntimeError(f'{cluster.key}: static PC-return fusion currently requires zero fused JAL calls') return path, stats