rsx/cfg: Fix handling of instructions with literal input
- The hardware is pretty dumb about it, it just unconditionally skips the next instruction
This commit is contained in:
@@ -165,6 +165,14 @@ namespace rsx::assembler
|
|||||||
|
|
||||||
if (opcode == RSX_FP_OPCODE_NOP)
|
if (opcode == RSX_FP_OPCODE_NOP)
|
||||||
{
|
{
|
||||||
|
if (includes_literal_constant())
|
||||||
|
{
|
||||||
|
// Verified behavior on real hardware
|
||||||
|
// If any input on a non-flow-control instruction is of literal type the next instruction is assumed to be data
|
||||||
|
// You can actually use this behavior to mask off instructions completely
|
||||||
|
pc++;
|
||||||
|
}
|
||||||
|
|
||||||
pc++;
|
pc++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -679,8 +679,7 @@ fragment_program_utils::fragment_program_metadata fragment_program_utils::analys
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rsx::assembler::FP::get_operand_count(opcode) > 0 &&
|
if (is_any_src_constant(inst))
|
||||||
is_any_src_constant(inst))
|
|
||||||
{
|
{
|
||||||
// Instruction references constant, skip one slot occupied by data
|
// Instruction references constant, skip one slot occupied by data
|
||||||
index++;
|
index++;
|
||||||
|
|||||||
@@ -251,4 +251,29 @@ namespace rsx::assembler
|
|||||||
EXPECT_EQ(SRC0{ .HEX = graph.blocks.front().instructions[0].bytecode[1] }.exec_if_gr, 1);
|
EXPECT_EQ(SRC0{ .HEX = graph.blocks.front().instructions[0].bytecode[1] }.exec_if_gr, 1);
|
||||||
EXPECT_EQ(SRC0{ .HEX = graph.blocks.front().instructions[0].bytecode[1] }.exec_if_eq, 1);
|
EXPECT_EQ(SRC0{ .HEX = graph.blocks.front().instructions[0].bytecode[1] }.exec_if_eq, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(CFG, FpToCFG_SkipOverImmediateOperand)
|
||||||
|
{
|
||||||
|
auto ir = FPIR::from_source(
|
||||||
|
"MOV R0, #{ 0.25 };" // NOP with real dst and one literal input
|
||||||
|
"MOV R0, R1;" // False merge block.
|
||||||
|
);
|
||||||
|
|
||||||
|
RSXFragmentProgram program{};
|
||||||
|
auto bytecode = ir.compile();
|
||||||
|
program.data = bytecode.data();
|
||||||
|
|
||||||
|
ASSERT_EQ(bytecode.size(), 12);
|
||||||
|
|
||||||
|
// Patch the first instruction to be a NOP with a literal as input
|
||||||
|
const u32 decoded_d0 = ((bytecode[0] & 0xFF00FF00u) >> 16u) | ((bytecode[0] & 0x00FF00FFu) << 16u);
|
||||||
|
OPDEST d0{ .HEX = decoded_d0 };
|
||||||
|
d0.opcode = RSX_FP_OPCODE_NOP;
|
||||||
|
bytecode[0] = ((d0.HEX & 0xFF00FF00u) >> 16u) | ((d0.HEX & 0x00FF00FFu) << 16u);
|
||||||
|
|
||||||
|
FlowGraph graph = deconstruct_fragment_program(program);
|
||||||
|
|
||||||
|
ASSERT_EQ(graph.blocks.size(), 1);
|
||||||
|
ASSERT_EQ(graph.blocks.front().instructions.size(), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user