mirror of
https://gitlab.com/suyu-emu/suyu.git
synced 2024-03-15 23:15:44 +00:00
shader_ir: Implement BRX & BRA.CC
This commit is contained in:
parent
c218ae4b02
commit
8a6fc529a9
|
@ -1367,6 +1367,20 @@ union Instruction {
|
||||||
}
|
}
|
||||||
} bra;
|
} bra;
|
||||||
|
|
||||||
|
union {
|
||||||
|
BitField<20, 24, u64> target;
|
||||||
|
BitField<5, 1, u64> constant_buffer;
|
||||||
|
|
||||||
|
s32 GetBranchExtend() const {
|
||||||
|
// Sign extend the branch target offset
|
||||||
|
u32 mask = 1U << (24 - 1);
|
||||||
|
u32 value = static_cast<u32>(target);
|
||||||
|
// The branch offset is relative to the next instruction and is stored in bytes, so
|
||||||
|
// divide it by the size of an instruction and add 1 to it.
|
||||||
|
return static_cast<s32>((value ^ mask) - mask) / sizeof(Instruction) + 1;
|
||||||
|
}
|
||||||
|
} brx;
|
||||||
|
|
||||||
union {
|
union {
|
||||||
BitField<39, 1, u64> emit; // EmitVertex
|
BitField<39, 1, u64> emit; // EmitVertex
|
||||||
BitField<40, 1, u64> cut; // EndPrimitive
|
BitField<40, 1, u64> cut; // EndPrimitive
|
||||||
|
@ -1464,6 +1478,7 @@ public:
|
||||||
BFE_IMM,
|
BFE_IMM,
|
||||||
BFI_IMM_R,
|
BFI_IMM_R,
|
||||||
BRA,
|
BRA,
|
||||||
|
BRX,
|
||||||
PBK,
|
PBK,
|
||||||
LD_A,
|
LD_A,
|
||||||
LD_L,
|
LD_L,
|
||||||
|
@ -1738,6 +1753,7 @@ private:
|
||||||
INST("111000101001----", Id::SSY, Type::Flow, "SSY"),
|
INST("111000101001----", Id::SSY, Type::Flow, "SSY"),
|
||||||
INST("111000101010----", Id::PBK, Type::Flow, "PBK"),
|
INST("111000101010----", Id::PBK, Type::Flow, "PBK"),
|
||||||
INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
|
INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
|
||||||
|
INST("111000100101----", Id::BRX, Type::Flow, "BRX"),
|
||||||
INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
|
INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
|
||||||
INST("111000110100---", Id::BRK, Type::Flow, "BRK"),
|
INST("111000110100---", Id::BRK, Type::Flow, "BRK"),
|
||||||
INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"),
|
INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"),
|
||||||
|
|
|
@ -1555,6 +1555,14 @@ private:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string BranchIndirect(Operation operation) {
|
||||||
|
const std::string op_a = VisitOperand(operation, 0, Type::Uint);
|
||||||
|
|
||||||
|
code.AddLine("jmp_to = {};", op_a);
|
||||||
|
code.AddLine("break;");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
std::string PushFlowStack(Operation operation) {
|
std::string PushFlowStack(Operation operation) {
|
||||||
const auto stack = std::get<MetaStackClass>(operation.GetMeta());
|
const auto stack = std::get<MetaStackClass>(operation.GetMeta());
|
||||||
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
||||||
|
@ -1789,6 +1797,7 @@ private:
|
||||||
&GLSLDecompiler::ImageStore,
|
&GLSLDecompiler::ImageStore,
|
||||||
|
|
||||||
&GLSLDecompiler::Branch,
|
&GLSLDecompiler::Branch,
|
||||||
|
&GLSLDecompiler::BranchIndirect,
|
||||||
&GLSLDecompiler::PushFlowStack,
|
&GLSLDecompiler::PushFlowStack,
|
||||||
&GLSLDecompiler::PopFlowStack,
|
&GLSLDecompiler::PopFlowStack,
|
||||||
&GLSLDecompiler::Exit,
|
&GLSLDecompiler::Exit,
|
||||||
|
|
|
@ -949,6 +949,14 @@ private:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Id BranchIndirect(Operation operation) {
|
||||||
|
const Id op_a = VisitOperand<Type::Uint>(operation, 0);
|
||||||
|
|
||||||
|
Emit(OpStore(jmp_to, op_a));
|
||||||
|
BranchingOp([&]() { Emit(OpBranch(continue_label)); });
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
Id PushFlowStack(Operation operation) {
|
Id PushFlowStack(Operation operation) {
|
||||||
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
const auto target = std::get_if<ImmediateNode>(&*operation[0]);
|
||||||
ASSERT(target);
|
ASSERT(target);
|
||||||
|
@ -1334,6 +1342,7 @@ private:
|
||||||
&SPIRVDecompiler::ImageStore,
|
&SPIRVDecompiler::ImageStore,
|
||||||
|
|
||||||
&SPIRVDecompiler::Branch,
|
&SPIRVDecompiler::Branch,
|
||||||
|
&SPIRVDecompiler::BranchIndirect,
|
||||||
&SPIRVDecompiler::PushFlowStack,
|
&SPIRVDecompiler::PushFlowStack,
|
||||||
&SPIRVDecompiler::PopFlowStack,
|
&SPIRVDecompiler::PopFlowStack,
|
||||||
&SPIRVDecompiler::Exit,
|
&SPIRVDecompiler::Exit,
|
||||||
|
|
|
@ -284,6 +284,9 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info
|
||||||
state.pbk_labels.emplace(offset, target);
|
state.pbk_labels.emplace(offset, target);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case OpCode::Id::BRX: {
|
||||||
|
return ParseResult::AbnormalFlow;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,11 +91,45 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case OpCode::Id::BRA: {
|
case OpCode::Id::BRA: {
|
||||||
UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0,
|
Node branch;
|
||||||
"BRA with constant buffers are not implemented");
|
if (instr.bra.constant_buffer == 0) {
|
||||||
|
const u32 target = pc + instr.bra.GetBranchTarget();
|
||||||
|
branch = Operation(OperationCode::Branch, Immediate(target));
|
||||||
|
} else {
|
||||||
|
const u32 target = pc + 1;
|
||||||
|
const Node op_a = GetConstBuffer(instr.cbuf36.index, instr.cbuf36.GetOffset());
|
||||||
|
const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight,
|
||||||
|
true, PRECISE, op_a, Immediate(3));
|
||||||
|
const Node operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
|
||||||
|
branch = Operation(OperationCode::BranchIndirect, convert);
|
||||||
|
}
|
||||||
|
|
||||||
const u32 target = pc + instr.bra.GetBranchTarget();
|
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
||||||
const Node branch = Operation(OperationCode::Branch, Immediate(target));
|
if (cc != Tegra::Shader::ConditionCode::T) {
|
||||||
|
bb.push_back(Conditional(GetConditionCode(cc), {branch}));
|
||||||
|
} else {
|
||||||
|
bb.push_back(branch);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case OpCode::Id::BRX: {
|
||||||
|
Node operand;
|
||||||
|
if (instr.brx.constant_buffer != 0) {
|
||||||
|
const s32 target = pc + 1;
|
||||||
|
const Node index = GetRegister(instr.gpr8);
|
||||||
|
const Node op_a =
|
||||||
|
GetConstBufferIndirect(instr.cbuf36.index, instr.cbuf36.GetOffset() + 0, index);
|
||||||
|
const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight,
|
||||||
|
true, PRECISE, op_a, Immediate(3));
|
||||||
|
operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
|
||||||
|
} else {
|
||||||
|
const s32 target = pc + instr.brx.GetBranchExtend();
|
||||||
|
const Node op_a = GetRegister(instr.gpr8);
|
||||||
|
const Node convert = SignedOperation(OperationCode::IArithmeticShiftRight,
|
||||||
|
true, PRECISE, op_a, Immediate(3));
|
||||||
|
operand = Operation(OperationCode::IAdd, PRECISE, convert, Immediate(target));
|
||||||
|
}
|
||||||
|
const Node branch = Operation(OperationCode::BranchIndirect, operand);
|
||||||
|
|
||||||
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
const Tegra::Shader::ConditionCode cc = instr.flow_condition_code;
|
||||||
if (cc != Tegra::Shader::ConditionCode::T) {
|
if (cc != Tegra::Shader::ConditionCode::T) {
|
||||||
|
|
|
@ -149,6 +149,7 @@ enum class OperationCode {
|
||||||
ImageStore, /// (MetaImage, float[N] coords) -> void
|
ImageStore, /// (MetaImage, float[N] coords) -> void
|
||||||
|
|
||||||
Branch, /// (uint branch_target) -> void
|
Branch, /// (uint branch_target) -> void
|
||||||
|
BranchIndirect,/// (uint branch_target) -> void
|
||||||
PushFlowStack, /// (uint branch_target) -> void
|
PushFlowStack, /// (uint branch_target) -> void
|
||||||
PopFlowStack, /// () -> void
|
PopFlowStack, /// () -> void
|
||||||
Exit, /// () -> void
|
Exit, /// () -> void
|
||||||
|
|
Loading…
Reference in a new issue