shader_ir: Implement BRX & BRA.CC

master
Fernando Sahmkow 2019-06-24 21:25:38 +07:00 committed by FernandoS27
parent c218ae4b02
commit 8a6fc529a9
6 changed files with 76 additions and 4 deletions

@ -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