rsx/cfg: Handle IF-ELSE aliasing statement as inverted condition

- If there is no IF block but ELSE block exists, treat the branch as being inverted and the ELSE block as the main IF body
- Rare but seen in some games
This commit is contained in:
kd-11 2026-03-19 01:35:05 +03:00 committed by kd-11
parent 2f3b66985e
commit d54e54b66d
3 changed files with 20 additions and 1 deletions

View File

@ -459,4 +459,12 @@ namespace rsx::assembler::FP
return result;
}
// Invert execution mask on an instruction
void invert_conditional_execution_mask(Instruction* instruction)
{
// We want to invert src0.exec_if_gt|lt|eq which should be at bit offset 18-20
constexpr u32 inv_mask = (0b111 << 18u);
instruction->bytecode[1] = instruction->bytecode[1] ^ inv_mask;
}
}

View File

@ -131,5 +131,8 @@ namespace rsx::assembler
// Compile a register file annotated blob to register references
std::vector<RegisterRef> compile_register_file(const std::array<char, 48 * 8>& file);
// Invert execution mask on an instruction
void invert_conditional_execution_mask(Instruction* instruction);
}
}

View File

@ -1,5 +1,6 @@
#include "stdafx.h"
#include "CFG.h"
#include "FPOpcodes.h"
#include "Emu/RSX/Common/simple_array.hpp"
#include "Emu/RSX/Program/RSXFragmentProgram.h"
@ -211,7 +212,14 @@ namespace rsx::assembler
auto parent = bb;
bb = safe_insert_block(parent, pc + 1u, EdgeType::IF);
if (end_addr != else_addr)
if (else_addr == pc + 1u)
{
// Empty IF block. We co-opt the ELSE block as the IF and invert the condition.
auto& inst = parent->instructions.back();
FP::invert_conditional_execution_mask(&inst);
}
else if (end_addr != else_addr)
{
else_blocks.push_back(safe_insert_block(parent, else_addr, EdgeType::ELSE));
}