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