|
|
|
@ -9,6 +9,7 @@ |
|
|
|
|
|
|
|
namespace VideoCommon::Shader { |
|
|
|
|
|
|
|
using Tegra::Shader::IAdd3Height; |
|
|
|
using Tegra::Shader::Instruction; |
|
|
|
using Tegra::Shader::OpCode; |
|
|
|
using Tegra::Shader::Register; |
|
|
|
@ -42,6 +43,66 @@ u32 ShaderIR::DecodeArithmeticInteger(BasicBlock& bb, u32 pc) { |
|
|
|
SetRegister(bb, instr.gpr0, Operation(OperationCode::IAdd, PRECISE, op_a, op_b)); |
|
|
|
break; |
|
|
|
} |
|
|
|
case OpCode::Id::IADD3_C: |
|
|
|
case OpCode::Id::IADD3_R: |
|
|
|
case OpCode::Id::IADD3_IMM: { |
|
|
|
UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
|
|
|
"Condition codes generation in IADD3 is not implemented"); |
|
|
|
|
|
|
|
Node op_c = GetRegister(instr.gpr39); |
|
|
|
|
|
|
|
const auto ApplyHeight = [&](IAdd3Height height, Node value) { |
|
|
|
switch (height) { |
|
|
|
case IAdd3Height::None: |
|
|
|
return value; |
|
|
|
case IAdd3Height::LowerHalfWord: |
|
|
|
return Operation(OperationCode::IBitwiseAnd, NO_PRECISE, value, Immediate(0xffff)); |
|
|
|
case IAdd3Height::UpperHalfWord: |
|
|
|
return Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, value, |
|
|
|
Immediate(16)); |
|
|
|
default: |
|
|
|
UNIMPLEMENTED_MSG("Unhandled IADD3 height: {}", static_cast<u32>(height)); |
|
|
|
return Immediate(0); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
if (opcode->get().GetId() == OpCode::Id::IADD3_R) { |
|
|
|
op_a = ApplyHeight(instr.iadd3.height_a, op_a); |
|
|
|
op_b = ApplyHeight(instr.iadd3.height_b, op_b); |
|
|
|
op_c = ApplyHeight(instr.iadd3.height_c, op_c); |
|
|
|
} |
|
|
|
|
|
|
|
op_a = GetOperandAbsNegInteger(op_a, false, instr.iadd3.neg_a, true); |
|
|
|
op_b = GetOperandAbsNegInteger(op_b, false, instr.iadd3.neg_b, true); |
|
|
|
op_c = GetOperandAbsNegInteger(op_c, false, instr.iadd3.neg_c, true); |
|
|
|
|
|
|
|
const Node value = [&]() { |
|
|
|
const Node add_ab = Operation(OperationCode::IAdd, NO_PRECISE, op_a, op_b); |
|
|
|
if (opcode->get().GetId() != OpCode::Id::IADD3_R) { |
|
|
|
return Operation(OperationCode::IAdd, NO_PRECISE, add_ab, op_c); |
|
|
|
} |
|
|
|
const Node shifted = [&]() { |
|
|
|
switch (instr.iadd3.mode) { |
|
|
|
case Tegra::Shader::IAdd3Mode::RightShift: |
|
|
|
// TODO(tech4me): According to
|
|
|
|
// https://envytools.readthedocs.io/en/latest/hw/graph/maxwell/cuda/int.html?highlight=iadd3
|
|
|
|
// The addition between op_a and op_b should be done in uint33, more
|
|
|
|
// investigation required
|
|
|
|
return Operation(OperationCode::ILogicalShiftRight, NO_PRECISE, add_ab, |
|
|
|
Immediate(16)); |
|
|
|
case Tegra::Shader::IAdd3Mode::LeftShift: |
|
|
|
return Operation(OperationCode::ILogicalShiftLeft, NO_PRECISE, add_ab, |
|
|
|
Immediate(16)); |
|
|
|
default: |
|
|
|
return add_ab; |
|
|
|
} |
|
|
|
}(); |
|
|
|
return Operation(OperationCode::IAdd, NO_PRECISE, shifted, op_c); |
|
|
|
}(); |
|
|
|
|
|
|
|
SetRegister(bb, instr.gpr0, value); |
|
|
|
break; |
|
|
|
} |
|
|
|
case OpCode::Id::ISCADD_C: |
|
|
|
case OpCode::Id::ISCADD_R: |
|
|
|
case OpCode::Id::ISCADD_IMM: { |
|
|
|
|