Do some corrections in conversion shader instructions.

Corrects encodings for I2F, F2F, I2I and F2I
Implements Immediate variants of all four conversion types.
Add assertions to unimplemented stuffs.
master
Fernando Sahmkow 2019-04-15 19:04:33 +07:00 committed by FernandoS27
parent 1f4dfb3998
commit aa471274d9
2 changed files with 73 additions and 23 deletions

@ -917,21 +917,34 @@ union Instruction {
} iset;
union {
BitField<8, 2, Register::Size> dest_size;
BitField<10, 2, Register::Size> src_size;
BitField<12, 1, u64> is_output_signed;
BitField<13, 1, u64> is_input_signed;
BitField<41, 2, u64> selector;
BitField<41, 2, u64> selector; // i2i and i2f only
BitField<45, 1, u64> negate_a;
BitField<49, 1, u64> abs_a;
BitField<10, 2, Register::Size> src_size;
BitField<13, 1, u64> is_input_signed;
BitField<8, 2, Register::Size> dst_size;
BitField<12, 1, u64> is_output_signed;
union {
BitField<39, 2, u64> tab5cb8_2;
} i2f;
union {
BitField<39, 2, F2iRoundingOp> rounding;
} f2i;
union {
BitField<39, 4, F2fRoundingOp> rounding;
BitField<8, 2, Register::Size> src_size;
BitField<10, 2, Register::Size> dst_size;
BitField<39, 4, u64> rounding;
// H0, H1 extract for F16 missing
BitField<41, 1, u64> selector; // Guessed as some games set it, TODO: reverse this value
F2fRoundingOp GetRoundingMode() const {
constexpr u64 rounding_mask = 0x0B;
return static_cast<F2fRoundingOp>(rounding.Value() & rounding_mask);
}
} f2f;
} conversion;
union {
@ -1678,7 +1691,7 @@ private:
INST("0011100-00101---", Id::SHR_IMM, Type::Shift, "SHR_IMM"),
INST("0100110011100---", Id::I2I_C, Type::Conversion, "I2I_C"),
INST("0101110011100---", Id::I2I_R, Type::Conversion, "I2I_R"),
INST("01110001-1000---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
INST("0011101-11100---", Id::I2I_IMM, Type::Conversion, "I2I_IMM"),
INST("0100110010111---", Id::I2F_C, Type::Conversion, "I2F_C"),
INST("0101110010111---", Id::I2F_R, Type::Conversion, "I2F_R"),
INST("0011100-10111---", Id::I2F_IMM, Type::Conversion, "I2F_IMM"),

@ -18,13 +18,29 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
const auto opcode = OpCode::Decode(instr);
switch (opcode->get().GetId()) {
case OpCode::Id::I2I_R: {
case OpCode::Id::I2I_R:
case OpCode::Id::I2I_C:
case OpCode::Id::I2I_IMM: {
UNIMPLEMENTED_IF(instr.conversion.selector);
UNIMPLEMENTED_IF(instr.conversion.dst_size != Register::Size::Word);
UNIMPLEMENTED_IF(instr.alu.saturate_d);
const bool input_signed = instr.conversion.is_input_signed;
const bool output_signed = instr.conversion.is_output_signed;
Node value = GetRegister(instr.gpr20);
Node value = [&]() {
switch (opcode->get().GetId()) {
case OpCode::Id::I2I_R:
return GetRegister(instr.gpr20);
case OpCode::Id::I2I_C:
return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
case OpCode::Id::I2I_IMM:
return Immediate(instr.alu.GetSignedImm20_20());
default:
UNREACHABLE();
return Immediate(0);
}
}();
value = ConvertIntegerSize(value, instr.conversion.src_size, input_signed);
value = GetOperandAbsNegInteger(value, instr.conversion.abs_a, instr.conversion.negate_a,
@ -38,17 +54,24 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
break;
}
case OpCode::Id::I2F_R:
case OpCode::Id::I2F_C: {
UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
case OpCode::Id::I2F_C:
case OpCode::Id::I2F_IMM: {
UNIMPLEMENTED_IF(instr.conversion.dst_size != Register::Size::Word);
UNIMPLEMENTED_IF(instr.conversion.selector);
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in I2F is not implemented");
Node value = [&]() {
if (instr.is_b_gpr) {
switch (opcode->get().GetId()) {
case OpCode::Id::I2F_R:
return GetRegister(instr.gpr20);
} else {
case OpCode::Id::I2F_C:
return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
case OpCode::Id::I2F_IMM:
return Immediate(instr.alu.GetSignedImm20_20());
default:
UNREACHABLE();
return Immediate(0);
}
}();
const bool input_signed = instr.conversion.is_input_signed;
@ -62,24 +85,31 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
break;
}
case OpCode::Id::F2F_R:
case OpCode::Id::F2F_C: {
UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word);
UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
case OpCode::Id::F2F_C:
case OpCode::Id::F2F_IMM: {
UNIMPLEMENTED_IF(instr.conversion.f2f.dst_size != Register::Size::Word);
UNIMPLEMENTED_IF(instr.conversion.f2f.src_size != Register::Size::Word);
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in F2F is not implemented");
Node value = [&]() {
if (instr.is_b_gpr) {
switch (opcode->get().GetId()) {
case OpCode::Id::F2F_R:
return GetRegister(instr.gpr20);
} else {
case OpCode::Id::F2F_C:
return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
case OpCode::Id::F2F_IMM:
return GetImmediate19(instr);
default:
UNREACHABLE();
return Immediate(0);
}
}();
value = GetOperandAbsNegFloat(value, instr.conversion.abs_a, instr.conversion.negate_a);
value = [&]() {
switch (instr.conversion.f2f.rounding) {
switch (instr.conversion.f2f.GetRoundingMode()) {
case Tegra::Shader::F2fRoundingOp::None:
return value;
case Tegra::Shader::F2fRoundingOp::Round:
@ -102,15 +132,22 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
break;
}
case OpCode::Id::F2I_R:
case OpCode::Id::F2I_C: {
case OpCode::Id::F2I_C:
case OpCode::Id::F2I_IMM: {
UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word);
UNIMPLEMENTED_IF_MSG(instr.generates_cc,
"Condition codes generation in F2I is not implemented");
Node value = [&]() {
if (instr.is_b_gpr) {
switch (opcode->get().GetId()) {
case OpCode::Id::F2I_R:
return GetRegister(instr.gpr20);
} else {
case OpCode::Id::F2I_C:
return GetConstBuffer(instr.cbuf34.index, instr.cbuf34.GetOffset());
case OpCode::Id::F2I_IMM:
return GetImmediate19(instr);
default:
UNREACHABLE();
return Immediate(0);
}
}();
@ -134,7 +171,7 @@ u32 ShaderIR::DecodeConversion(NodeBlock& bb, u32 pc) {
}();
const bool is_signed = instr.conversion.is_output_signed;
value = SignedOperation(OperationCode::ICastFloat, is_signed, PRECISE, value);
value = ConvertIntegerSize(value, instr.conversion.dest_size, is_signed);
value = ConvertIntegerSize(value, instr.conversion.dst_size, is_signed);
SetRegister(bb, instr.gpr0, value);
break;