recompiler: tail-transfer image-edge fallthroughs

This commit is contained in:
Matthew Stanley
2026-08-23 13:20:50 -07:00
parent 13a56626d3
commit 48bc21f08d
+35
View File
@@ -2788,6 +2788,24 @@ GeneratedFunction CodeGenerator::generate_function(
fallthrough_name);
}
}
} else if (!cfg.block_order.empty()) {
// No in-image fallthrough function exists (region/image boundary): a
// reachable final block that runs off the end must publish its
// continuation PC. Falling off the C body would return with the
// entry-switch's consumed cpu->pc == 0, which the top-level trampoline
// reads as "program ended".
const BasicBlock& last_block = cfg.blocks.at(cfg.block_order.back());
bool runs_off_end =
last_block.exit_instr.type == ControlFlowType::None ||
((last_block.exit_instr.type == ControlFlowType::Branch ||
last_block.exit_instr.type == ControlFlowType::Jump) &&
last_block.successors.empty());
bool is_reachable = last_block.is_entry || !last_block.predecessors.empty();
if (runs_off_end && is_reachable) {
body_ss << fmt::format(
" cpu->pc = 0x{:08X}u; return; /* image-edge fallthrough: tail-transfer */\n",
last_block.end_addr + 4u);
}
}
body_ss << " ; /* label compatibility: C requires a statement after the last label */\n";
body_ss << "}\n";
@@ -3017,6 +3035,23 @@ std::vector<GeneratedFunction> CodeGenerator::generate_alias_group(
body << fmt::format(" {}(cpu); /* fallthrough to next function */\n",
fallthrough_name);
}
} else if (!cfg.block_order.empty() &&
live_blocks.count(cfg.block_order.back())) {
// Image-edge fallthrough (mirrors generate_function): no in-image next
// function exists, so a live final block that runs off the end must
// tail-transfer to its continuation PC instead of falling off the C
// body with cpu->pc still consumed to 0.
const BasicBlock& last_block = cfg.blocks.at(cfg.block_order.back());
bool runs_off_end =
(last_block.exit_instr.type == ControlFlowType::None) ||
((last_block.exit_instr.type == ControlFlowType::Branch ||
last_block.exit_instr.type == ControlFlowType::Jump) &&
last_block.successors.empty());
if (runs_off_end) {
body << fmt::format(
" cpu->pc = 0x{:08X}u; return; /* image-edge fallthrough: tail-transfer */\n",
last_block.end_addr + 4u);
}
}
body << " ; /* label compatibility */\n";
body << "}\n";