shader recompiler: add 64 bits version to get register / GetSrc

This commit is contained in:
Vinicius Rangel 2024-07-23 14:03:18 -03:00
parent e23749bf0e
commit 510072b4f4
No known key found for this signature in database
GPG key ID: A5B154D904B761D9
5 changed files with 157 additions and 59 deletions

View file

@ -2392,10 +2392,10 @@ enum class OperandField : u32 {
ConstFloatPos_4_0,
ConstFloatNeg_4_0,
VccZ = 251,
ExecZ,
Scc,
LdsDirect,
LiteralConst,
ExecZ = 252,
Scc = 253,
LdsDirect = 254,
LiteralConst = 255,
VectorGPR,
Undefined = 0xFFFFFFFF,

View file

@ -75,6 +75,7 @@ void Translator::EmitPrologue() {
}
}
template <>
IR::U32F32 Translator::GetSrc(const InstOperand& operand, bool force_flt) {
// Input modifiers work on float values.
force_flt |= operand.input_modifier.abs | operand.input_modifier.neg;
@ -172,6 +173,127 @@ IR::U32F32 Translator::GetSrc(const InstOperand& operand, bool force_flt) {
return value;
}
template <>
IR::U32 Translator::GetSrc(const InstOperand& operand, bool force_flt) {
return GetSrc<IR::U32F32>(operand, force_flt);
}
template <>
IR::F32 Translator::GetSrc(const InstOperand& operand, bool) {
return GetSrc<IR::U32F32>(operand, true);
}
template <>
IR::U64F64 Translator::GetSrc64(const InstOperand& operand, bool force_flt) {
// Input modifiers work on float values.
force_flt |= operand.input_modifier.abs | operand.input_modifier.neg;
IR::U64F64 value{};
switch (operand.field) {
case OperandField::ScalarGPR:
if (operand.type == ScalarType::Float64 || force_flt) {
value = ir.GetScalarReg<IR::F64>(IR::ScalarReg(operand.code));
} else if (operand.type == ScalarType::Uint64 || operand.type == ScalarType::Sint64) {
value = ir.GetScalarReg<IR::U64>(IR::ScalarReg(operand.code));
} else {
UNREACHABLE();
}
break;
case OperandField::VectorGPR:
if (operand.type == ScalarType::Float64 || force_flt) {
value = ir.GetVectorReg<IR::F64>(IR::VectorReg(operand.code));
} else if (operand.type == ScalarType::Uint64 || operand.type == ScalarType::Sint64) {
value = ir.GetVectorReg<IR::U64>(IR::VectorReg(operand.code));
} else {
UNREACHABLE();
}
break;
case OperandField::ConstZero:
if (force_flt) {
value = ir.Imm64(0.0);
} else {
value = ir.Imm64(u64(0U));
}
break;
case OperandField::SignedConstIntPos:
ASSERT(!force_flt);
value = ir.Imm64(s64(operand.code) - SignedConstIntPosMin + 1);
break;
case OperandField::SignedConstIntNeg:
ASSERT(!force_flt);
value = ir.Imm64(-s64(operand.code) + SignedConstIntNegMin - 1);
break;
case OperandField::LiteralConst:
if (force_flt) {
UNREACHABLE(); // There is a literal double?
} else {
value = ir.Imm64(u64(operand.code));
}
break;
case OperandField::ConstFloatPos_1_0:
if (force_flt) {
value = ir.Imm64(1.0);
} else {
value = ir.Imm64(std::bit_cast<u64>(double(1.0)));
}
break;
case OperandField::ConstFloatPos_0_5:
value = ir.Imm64(0.5);
break;
case OperandField::ConstFloatPos_2_0:
value = ir.Imm64(2.0);
break;
case OperandField::ConstFloatPos_4_0:
value = ir.Imm64(4.0);
break;
case OperandField::ConstFloatNeg_0_5:
value = ir.Imm64(-0.5);
break;
case OperandField::ConstFloatNeg_1_0:
value = ir.Imm64(-1.0);
break;
case OperandField::ConstFloatNeg_2_0:
value = ir.Imm64(-2.0);
break;
case OperandField::ConstFloatNeg_4_0:
value = ir.Imm64(-4.0);
break;
case OperandField::VccLo:
if (force_flt) {
value = ir.BitCast<IR::F64>(IR::U64(ir.UConvert(64, ir.GetVccLo())));
} else {
value = ir.UConvert(64, ir.GetVccLo());
}
break;
case OperandField::VccHi:
if (force_flt) {
value = ir.BitCast<IR::F64>(IR::U64(ir.UConvert(64, ir.GetVccHi())));
} else {
value = ir.UConvert(64, ir.GetVccHi());
}
break;
default:
UNREACHABLE();
}
if (operand.input_modifier.abs) {
value = ir.FPAbs(value);
}
if (operand.input_modifier.neg) {
value = ir.FPNeg(value);
}
return value;
}
template <>
IR::U64 Translator::GetSrc64(const InstOperand& operand, bool force_flt) {
return GetSrc64<IR::U64F64>(operand, force_flt);
}
template <>
IR::F64 Translator::GetSrc64(const InstOperand& operand, bool) {
return GetSrc64<IR::U64F64>(operand, true);
}
void Translator::SetDst(const InstOperand& operand, const IR::U32F32& value) {
IR::U32F32 result = value;
if (operand.output_modifier.multiplier != 0.f) {

View file

@ -188,7 +188,10 @@ public:
void EXP(const GcnInst& inst);
private:
IR::U32F32 GetSrc(const InstOperand& operand, bool flt_zero = false);
template <typename T = IR::U32F32>
[[nodiscard]] T GetSrc(const InstOperand& operand, bool flt_zero = false);
template <typename T = IR::U64F64>
[[nodiscard]] T GetSrc64(const InstOperand& operand, bool flt_zero = false);
void SetDst(const InstOperand& operand, const IR::U32F32& value);
private:

View file

@ -93,31 +93,15 @@ void Translator::V_ADD_I32(const GcnInst& inst) {
}
void Translator::V_ADDC_U32(const GcnInst& inst) {
IR::U32 src0;
const IR::Value src0_0{GetSrc(inst.src[0])};
if (src0_0.Type() == IR::Type::F32 || src0_0.Type() == IR::Type::F64) {
src0 = ir.ConvertFToU(32, IR::F32F64(src0_0));
} else if (src0_0.Type() == IR::Type::U32) {
src0 = IR::U32U64(src0_0);
} else {
UNREACHABLE();
}
IR::U32 src1;
const IR::Value src1_0{GetSrc(inst.src[1])};
if (src1_0.Type() == IR::Type::F32 || src1_0.Type() == IR::Type::F64) {
src1 = ir.ConvertFToU(32, IR::F32F64(src1_0));
} else if (src1_0.Type() == IR::Type::U32) {
src1 = IR::U32U64(src1_0);
} else {
UNREACHABLE();
}
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
IR::U32 scarry;
if (inst.src_count == 3) { // VOP3
scarry = {GetSrc(inst.src[2])};
scarry = GetSrc<IR::U32>(inst.src[2]);
} else { // VOP2
scarry = {ir.GetVccLo()};
scarry = ir.GetVccLo();
}
IR::U32 result = ir.IAdd(ir.IAdd(src0, src1), scarry);
@ -330,41 +314,10 @@ void Translator::V_SUBREV_I32(const GcnInst& inst) {
}
void Translator::V_MAD_U64_U32(const GcnInst& inst) {
IR::U32 src0;
const IR::Value src0_0{GetSrc(inst.src[0])};
if (src0_0.Type() == IR::Type::F32 || src0_0.Type() == IR::Type::F64) {
src0 = ir.ConvertFToU(32, IR::F32F64(src0_0));
} else if (src0_0.Type() == IR::Type::U64) {
src0 = ir.UConvert(32, IR::U64(src0_0));
} else if (src0_0.Type() == IR::Type::U32) {
src0 = IR::U32(src0_0);
} else {
UNREACHABLE();
}
IR::U32 src1;
const IR::Value src1_0{GetSrc(inst.src[1])};
if (src1_0.Type() == IR::Type::F32 || src1_0.Type() == IR::Type::F64) {
src1 = ir.ConvertFToU(32, IR::F32F64(src1_0));
} else if (src1_0.Type() == IR::Type::U64) {
src1 = ir.UConvert(32, IR::U64(src1_0));
} else if (src1_0.Type() == IR::Type::U32) {
src1 = IR::U32(src1_0);
} else {
UNREACHABLE();
}
IR::U64 src2;
const IR::Value src2_0{GetSrc(inst.src[2])};
if (src2_0.Type() == IR::Type::F32 || src2_0.Type() == IR::Type::F64) {
src2 = ir.ConvertFToU(64, IR::F32F64(src2_0));
} else if (src2_0.Type() == IR::Type::U64) {
src2 = IR::U64(src2_0);
} else if (src2_0.Type() == IR::Type::U32) {
src2 = ir.UConvert(64, IR::U32(src2_0));
} else {
UNREACHABLE();
}
const auto src0 = GetSrc<IR::U32>(inst.src[0]);
const auto src1 = GetSrc<IR::U32>(inst.src[1]);
const auto src2 = GetSrc64<IR::U64>(inst.src[2]);
IR::U64 result;
result = ir.IMul(src0, src1);

View file

@ -153,6 +153,16 @@ F32 IREmitter::GetScalarReg(IR::ScalarReg reg) {
return BitCast<F32>(GetScalarReg<U32>(reg));
}
template <>
U64 IREmitter::GetScalarReg(IR::ScalarReg reg) {
return Inst<U64>(Opcode::GetScalarRegister, reg);
}
template <>
F64 IREmitter::GetScalarReg(IR::ScalarReg reg) {
return BitCast<F64>(GetScalarReg<U64>(reg));
}
template <>
U32 IREmitter::GetVectorReg(IR::VectorReg reg) {
return Inst<U32>(Opcode::GetVectorRegister, reg);
@ -163,6 +173,16 @@ F32 IREmitter::GetVectorReg(IR::VectorReg reg) {
return BitCast<F32>(GetVectorReg<U32>(reg));
}
template <>
U64 IREmitter::GetVectorReg(IR::VectorReg reg) {
return Inst<U64>(Opcode::GetVectorRegister, reg);
}
template <>
F64 IREmitter::GetVectorReg(IR::VectorReg reg) {
return BitCast<F64>(GetVectorReg<U64>(reg));
}
void IREmitter::SetScalarReg(IR::ScalarReg reg, const U32F32& value) {
const U32 value_typed = value.Type() == Type::F32 ? BitCast<U32>(F32{value}) : U32{value};
Inst(Opcode::SetScalarRegister, reg, value_typed);