gl_shader_decompiler: Implement PBK and BRK

This commit is contained in:
ReinUsesLisp 2018-10-16 17:11:26 -03:00
parent 78f2a6a9e1
commit 41fb25349a
2 changed files with 43 additions and 22 deletions

View file

@ -1095,11 +1095,13 @@ public:
KIL, KIL,
SSY, SSY,
SYNC, SYNC,
BRK,
DEPBAR, DEPBAR,
BFE_C, BFE_C,
BFE_R, BFE_R,
BFE_IMM, BFE_IMM,
BRA, BRA,
PBK,
LD_A, LD_A,
LD_C, LD_C,
ST_A, ST_A,
@ -1239,7 +1241,7 @@ public:
/// conditionally executed). /// conditionally executed).
static bool IsPredicatedInstruction(Id opcode) { static bool IsPredicatedInstruction(Id opcode) {
// TODO(Subv): Add the rest of unpredicated instructions. // TODO(Subv): Add the rest of unpredicated instructions.
return opcode != Id::SSY; return opcode != Id::SSY && opcode != Id::PBK;
} }
class Matcher { class Matcher {
@ -1335,9 +1337,11 @@ private:
#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) #define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
INST("111000110011----", Id::KIL, Type::Flow, "KIL"), INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
INST("111000101001----", Id::SSY, Type::Flow, "SSY"), INST("111000101001----", Id::SSY, Type::Flow, "SSY"),
INST("111000101010----", Id::PBK, Type::Flow, "PBK"),
INST("111000100100----", Id::BRA, Type::Flow, "BRA"), INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
INST("111000110100---", Id::BRK, Type::Flow, "BRK"),
INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"), INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
INST("1111000011111---", Id::SYNC, Type::Synch, "SYNC"),
INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"), INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"),
INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
@ -1463,4 +1467,4 @@ private:
} }
}; };
} // namespace Tegra::Shader } // namespace Tegra::Shader

View file

@ -165,10 +165,11 @@ private:
const ExitMethod jmp = Scan(target, end, labels); const ExitMethod jmp = Scan(target, end, labels);
return exit_method = ParallelExit(no_jmp, jmp); return exit_method = ParallelExit(no_jmp, jmp);
} }
case OpCode::Id::SSY: { case OpCode::Id::SSY:
// The SSY instruction uses a similar encoding as the BRA instruction. case OpCode::Id::PBK: {
// The SSY and PBK use a similar encoding as the BRA instruction.
ASSERT_MSG(instr.bra.constant_buffer == 0, ASSERT_MSG(instr.bra.constant_buffer == 0,
"Constant buffer SSY is not supported"); "Constant buffer branching is not supported");
const u32 target = offset + instr.bra.GetBranchTarget(); const u32 target = offset + instr.bra.GetBranchTarget();
labels.insert(target); labels.insert(target);
// Continue scanning for an exit method. // Continue scanning for an exit method.
@ -1153,27 +1154,27 @@ private:
} }
/* /*
* Emits code to push the input target address to the SSY address stack, incrementing the stack * Emits code to push the input target address to the flow address stack, incrementing the stack
* top. * top.
*/ */
void EmitPushToSSYStack(u32 target) { void EmitPushToFlowStack(u32 target) {
shader.AddLine('{'); shader.AddLine('{');
++shader.scope; ++shader.scope;
shader.AddLine("ssy_stack[ssy_stack_top] = " + std::to_string(target) + "u;"); shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
shader.AddLine("ssy_stack_top++;"); shader.AddLine("flow_stack_top++;");
--shader.scope; --shader.scope;
shader.AddLine('}'); shader.AddLine('}');
} }
/* /*
* Emits code to pop an address from the SSY address stack, setting the jump address to the * Emits code to pop an address from the flow address stack, setting the jump address to the
* popped address and decrementing the stack top. * popped address and decrementing the stack top.
*/ */
void EmitPopFromSSYStack() { void EmitPopFromFlowStack() {
shader.AddLine('{'); shader.AddLine('{');
++shader.scope; ++shader.scope;
shader.AddLine("ssy_stack_top--;"); shader.AddLine("flow_stack_top--;");
shader.AddLine("jmp_to = ssy_stack[ssy_stack_top];"); shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
shader.AddLine("break;"); shader.AddLine("break;");
--shader.scope; --shader.scope;
shader.AddLine('}'); shader.AddLine('}');
@ -2933,16 +2934,32 @@ private:
// The SSY opcode tells the GPU where to re-converge divergent execution paths, it // The SSY opcode tells the GPU where to re-converge divergent execution paths, it
// sets the target of the jump that the SYNC instruction will make. The SSY opcode // sets the target of the jump that the SYNC instruction will make. The SSY opcode
// has a similar structure to the BRA opcode. // has a similar structure to the BRA opcode.
ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported"); ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer flow is not supported");
const u32 target = offset + instr.bra.GetBranchTarget(); const u32 target = offset + instr.bra.GetBranchTarget();
EmitPushToSSYStack(target); EmitPushToFlowStack(target);
break;
}
case OpCode::Id::PBK: {
// PBK pushes to a stack the address where BRK will jump to. This shares stack with
// SSY but using SYNC on a PBK address will kill the shader execution. We don't
// emulate this because it's very unlikely a driver will emit such invalid shader.
ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer PBK is not supported");
const u32 target = offset + instr.bra.GetBranchTarget();
EmitPushToFlowStack(target);
break; break;
} }
case OpCode::Id::SYNC: { case OpCode::Id::SYNC: {
// The SYNC opcode jumps to the address previously set by the SSY opcode // The SYNC opcode jumps to the address previously set by the SSY opcode
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
EmitPopFromSSYStack(); EmitPopFromFlowStack();
break;
}
case OpCode::Id::BRK: {
// The BRK opcode jumps to the address previously set by the PBK opcode
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
EmitPopFromFlowStack();
break; break;
} }
case OpCode::Id::DEPBAR: { case OpCode::Id::DEPBAR: {
@ -3096,11 +3113,11 @@ private:
labels.insert(subroutine.begin); labels.insert(subroutine.begin);
shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;"); shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
// TODO(Subv): Figure out the actual depth of the SSY stack, for now it seems // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
// unlikely that shaders will use 20 nested SSYs. // unlikely that shaders will use 20 nested SSYs and PBKs.
constexpr u32 SSY_STACK_SIZE = 20; constexpr u32 FLOW_STACK_SIZE = 20;
shader.AddLine("uint ssy_stack[" + std::to_string(SSY_STACK_SIZE) + "];"); shader.AddLine("uint flow_stack[" + std::to_string(FLOW_STACK_SIZE) + "];");
shader.AddLine("uint ssy_stack_top = 0u;"); shader.AddLine("uint flow_stack_top = 0u;");
shader.AddLine("while (true) {"); shader.AddLine("while (true) {");
++shader.scope; ++shader.scope;