From 8a6fc529a968e007f01464abadd32f9b5eb0a26c Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 24 Jun 2019 21:25:38 -0400 Subject: shader_ir: Implement BRX & BRA.CC --- src/video_core/shader/control_flow.cpp | 3 +++ src/video_core/shader/decode/other.cpp | 42 ++++++++++++++++++++++++++++++---- src/video_core/shader/node.h | 1 + 3 files changed, 42 insertions(+), 4 deletions(-) (limited to 'src/video_core/shader') diff --git a/src/video_core/shader/control_flow.cpp b/src/video_core/shader/control_flow.cpp index fcf22c7f2..a9de8f814 100644 --- a/src/video_core/shader/control_flow.cpp +++ b/src/video_core/shader/control_flow.cpp @@ -284,6 +284,9 @@ ParseResult ParseCode(CFGRebuildState& state, u32 address, ParseInfo& parse_info state.pbk_labels.emplace(offset, target); break; } + case OpCode::Id::BRX: { + return ParseResult::AbnormalFlow; + } default: break; } diff --git a/src/video_core/shader/decode/other.cpp b/src/video_core/shader/decode/other.cpp index d46a8ab82..ed3c63781 100644 --- a/src/video_core/shader/decode/other.cpp +++ b/src/video_core/shader/decode/other.cpp @@ -91,11 +91,45 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) { break; } case OpCode::Id::BRA: { - UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, - "BRA with constant buffers are not implemented"); + Node branch; + 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 Node branch = Operation(OperationCode::Branch, Immediate(target)); + const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; + 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; if (cc != Tegra::Shader::ConditionCode::T) { diff --git a/src/video_core/shader/node.h b/src/video_core/shader/node.h index 0ac83fcf0..e468758a6 100644 --- a/src/video_core/shader/node.h +++ b/src/video_core/shader/node.h @@ -149,6 +149,7 @@ enum class OperationCode { ImageStore, /// (MetaImage, float[N] coords) -> void Branch, /// (uint branch_target) -> void + BranchIndirect,/// (uint branch_target) -> void PushFlowStack, /// (uint branch_target) -> void PopFlowStack, /// () -> void Exit, /// () -> void -- cgit v1.2.3