|
|
@ -163,10 +163,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.
|
|
|
@ -1233,27 +1234,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('}');
|
|
|
@ -3265,16 +3266,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: {
|
|
|
@ -3428,11 +3445,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;
|
|
|
|