shader_decode: Implement LOP3
This commit is contained in:
parent
b184ca9089
commit
a40fd07516
2 changed files with 62 additions and 0 deletions
|
@ -11,6 +11,7 @@ namespace VideoCommon::Shader {
|
|||
|
||||
using Tegra::Shader::Instruction;
|
||||
using Tegra::Shader::OpCode;
|
||||
using Tegra::Shader::Register;
|
||||
|
||||
u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) {
|
||||
const Instruction instr = {program_code[pc]};
|
||||
|
@ -79,6 +80,24 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) {
|
|||
instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::LOP3_C:
|
||||
case OpCode::Id::LOP3_R:
|
||||
case OpCode::Id::LOP3_IMM: {
|
||||
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
|
||||
"Condition codes generation in LOP3 is not implemented");
|
||||
|
||||
const Node op_c = GetRegister(instr.gpr39);
|
||||
const Node lut = [&]() {
|
||||
if (opcode->get().GetId() == OpCode::Id::LOP3_R) {
|
||||
return Immediate(instr.alu.lop3.GetImmLut28());
|
||||
} else {
|
||||
return Immediate(instr.alu.lop3.GetImmLut48());
|
||||
}
|
||||
}();
|
||||
|
||||
WriteLop3Instruction(bb, instr.gpr0, op_a, op_b, op_c, lut);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::IMNMX_C:
|
||||
case OpCode::Id::IMNMX_R:
|
||||
case OpCode::Id::IMNMX_IMM: {
|
||||
|
@ -102,4 +121,45 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) {
|
|||
return pc;
|
||||
}
|
||||
|
||||
void ShaderIR::WriteLop3Instruction(BasicBlock& bb, Register dest, Node op_a, Node op_b, Node op_c,
|
||||
Node imm_lut) {
|
||||
constexpr u32 lop_iterations = 32;
|
||||
const Node one = Immediate(1);
|
||||
const Node two = Immediate(2);
|
||||
|
||||
Node value{};
|
||||
for (u32 i = 0; i < lop_iterations; ++i) {
|
||||
const Node shift_amount = Immediate(i);
|
||||
|
||||
const Node a = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_c, shift_amount);
|
||||
const Node pack_0 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, a, one);
|
||||
|
||||
const Node b = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_b, shift_amount);
|
||||
const Node c = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, b, one);
|
||||
const Node pack_1 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, c, one);
|
||||
|
||||
const Node d = Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, op_a, shift_amount);
|
||||
const Node e = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, d, one);
|
||||
const Node pack_2 = Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, e, two);
|
||||
|
||||
const Node pack_01 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_0, pack_1);
|
||||
const Node pack_012 = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, pack_01, pack_2);
|
||||
|
||||
const Node shifted_bit =
|
||||
Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, imm_lut, pack_012);
|
||||
const Node bit = Operation(OperationCode::IBitwiseAnd, NO_PRECISE, shifted_bit, one);
|
||||
|
||||
const Node right =
|
||||
Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, bit, shift_amount);
|
||||
|
||||
if (i > 0) {
|
||||
value = Operation(OperationCode::IBitwiseOr, NO_PRECISE, value, right);
|
||||
} else {
|
||||
value = right;
|
||||
}
|
||||
}
|
||||
|
||||
SetRegister(bb, dest, value);
|
||||
}
|
||||
|
||||
} // namespace VideoCommon::Shader
|
|
@ -701,6 +701,8 @@ private:
|
|||
Tegra::Shader::LogicOperation logic_op, Node op_a, Node op_b,
|
||||
Tegra::Shader::PredicateResultMode predicate_mode,
|
||||
Tegra::Shader::Pred predicate);
|
||||
void WriteLop3Instruction(BasicBlock& bb, Tegra::Shader::Register dest, Node op_a, Node op_b,
|
||||
Node op_c, Node imm_lut);
|
||||
|
||||
template <typename... T>
|
||||
inline Node Operation(OperationCode code, const T*... operands) {
|
||||
|
|
Loading…
Reference in a new issue