64 bits OP, impl V_ADDC_U32 & V_MAD_U64_U32 (#310)

* impl V_ADDC_U32 & V_MAD_U64_U32

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

* fix V_ADDC_U32 carry

* shader recompiler: removed automatic conversion to force_flt in GetSRc

* shader recompiler: auto cast between u32 and u64 during ssa pass

* shader recompiler: fix SetVectorReg64 & standardize switches-case

* shader translate: fix overflow detection in V_ADD_I32

use vcc lo instead of vcc thread bit

* shader recompiler: more 64-bit work

- removed bit_size parameter from Get[Scalar/Vector]Register
- add BitwiseOr64
- add SetDst64 as a replacement for SetScalarReg64 & SetVectorReg64
- add GetSrc64 for 64-bit value

* shader recompiler: add V_MAD_U64_U32 vcc output

- add V_MAD_U64_U32 vcc output
- ILessThan for 64-bits

* shader recompiler: removed unnecessary changes & missing consts

* shader_recompiler: Add s64 type in constant propagation
This commit is contained in:
Vinicius Rangel 2024-07-27 11:23:59 -03:00 committed by GitHub
parent d84b4adc83
commit 680192a0c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 361 additions and 40 deletions

View file

@ -964,8 +964,18 @@ IR::Value IREmitter::IMulExt(const U32& a, const U32& b, bool is_signed) {
return Inst(is_signed ? Opcode::SMulExt : Opcode::UMulExt, a, b);
}
U32 IREmitter::IMul(const U32& a, const U32& b) {
return Inst<U32>(Opcode::IMul32, a, b);
U32U64 IREmitter::IMul(const U32U64& a, const U32U64& b) {
if (a.Type() != b.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", a.Type(), b.Type());
}
switch (a.Type()) {
case Type::U32:
return Inst<U32>(Opcode::IMul32, a, b);
case Type::U64:
return Inst<U64>(Opcode::IMul64, a, b);
default:
ThrowInvalidType(a.Type());
}
}
U32 IREmitter::IDiv(const U32& a, const U32& b, bool is_signed) {
@ -1024,8 +1034,18 @@ U32 IREmitter::BitwiseAnd(const U32& a, const U32& b) {
return Inst<U32>(Opcode::BitwiseAnd32, a, b);
}
U32 IREmitter::BitwiseOr(const U32& a, const U32& b) {
return Inst<U32>(Opcode::BitwiseOr32, a, b);
U32U64 IREmitter::BitwiseOr(const U32U64& a, const U32U64& b) {
if (a.Type() != b.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", a.Type(), b.Type());
}
switch (a.Type()) {
case Type::U32:
return Inst<U32>(Opcode::BitwiseOr32, a, b);
case Type::U64:
return Inst<U64>(Opcode::BitwiseOr64, a, b);
default:
ThrowInvalidType(a.Type());
}
}
U32 IREmitter::BitwiseXor(const U32& a, const U32& b) {
@ -1095,8 +1115,18 @@ U32 IREmitter::UClamp(const U32& value, const U32& min, const U32& max) {
return Inst<U32>(Opcode::UClamp32, value, min, max);
}
U1 IREmitter::ILessThan(const U32& lhs, const U32& rhs, bool is_signed) {
return Inst<U1>(is_signed ? Opcode::SLessThan : Opcode::ULessThan, lhs, rhs);
U1 IREmitter::ILessThan(const U32U64& lhs, const U32U64& rhs, bool is_signed) {
if (lhs.Type() != rhs.Type()) {
UNREACHABLE_MSG("Mismatching types {} and {}", lhs.Type(), rhs.Type());
}
switch (lhs.Type()) {
case Type::U32:
return Inst<U1>(is_signed ? Opcode::SLessThan32 : Opcode::ULessThan32, lhs, rhs);
case Type::U64:
return Inst<U1>(is_signed ? Opcode::SLessThan64 : Opcode::ULessThan64, lhs, rhs);
default:
ThrowInvalidType(lhs.Type());
}
}
U1 IREmitter::IEqual(const U32U64& lhs, const U32U64& rhs) {
@ -1155,8 +1185,9 @@ U32U64 IREmitter::ConvertFToS(size_t bitsize, const F32F64& value) {
ThrowInvalidType(value.Type());
}
default:
UNREACHABLE_MSG("Invalid destination bitsize {}", bitsize);
break;
}
throw NotImplementedException("Invalid destination bitsize {}", bitsize);
}
U32U64 IREmitter::ConvertFToU(size_t bitsize, const F32F64& value) {
@ -1183,13 +1214,17 @@ F32F64 IREmitter::ConvertSToF(size_t dest_bitsize, size_t src_bitsize, const Val
switch (src_bitsize) {
case 32:
return Inst<F32>(Opcode::ConvertF32S32, value);
default:
break;
}
break;
case 64:
switch (src_bitsize) {
case 32:
return Inst<F64>(Opcode::ConvertF64S32, value);
default:
break;
}
default:
break;
}
UNREACHABLE_MSG("Invalid bit size combination dst={} src={}", dest_bitsize, src_bitsize);
@ -1203,13 +1238,17 @@ F32F64 IREmitter::ConvertUToF(size_t dest_bitsize, size_t src_bitsize, const Val
return Inst<F32>(Opcode::ConvertF32U16, value);
case 32:
return Inst<F32>(Opcode::ConvertF32U32, value);
default:
break;
}
break;
case 64:
switch (src_bitsize) {
case 32:
return Inst<F64>(Opcode::ConvertF64U32, value);
default:
break;
}
default:
break;
}
UNREACHABLE_MSG("Invalid bit size combination dst={} src={}", dest_bitsize, src_bitsize);
@ -1227,7 +1266,11 @@ U16U32U64 IREmitter::UConvert(size_t result_bitsize, const U16U32U64& value) {
switch (value.Type()) {
case Type::U32:
return Inst<U16>(Opcode::ConvertU16U32, value);
default:
break;
}
default:
break;
}
throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize);
}
@ -1238,13 +1281,17 @@ F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) {
switch (value.Type()) {
case Type::F32:
return Inst<F16>(Opcode::ConvertF16F32, value);
default:
break;
}
break;
case 32:
switch (value.Type()) {
case Type::F16:
return Inst<F32>(Opcode::ConvertF32F16, value);
default:
break;
}
default:
break;
}
throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize);

View file

@ -159,7 +159,7 @@ public:
[[nodiscard]] Value IAddCary(const U32& a, const U32& b);
[[nodiscard]] U32U64 ISub(const U32U64& a, const U32U64& b);
[[nodiscard]] Value IMulExt(const U32& a, const U32& b, bool is_signed = false);
[[nodiscard]] U32 IMul(const U32& a, const U32& b);
[[nodiscard]] U32U64 IMul(const U32U64& a, const U32U64& b);
[[nodiscard]] U32 IDiv(const U32& a, const U32& b, bool is_signed = false);
[[nodiscard]] U32U64 INeg(const U32U64& value);
[[nodiscard]] U32 IAbs(const U32& value);
@ -167,7 +167,7 @@ public:
[[nodiscard]] U32U64 ShiftRightLogical(const U32U64& base, const U32& shift);
[[nodiscard]] U32U64 ShiftRightArithmetic(const U32U64& base, const U32& shift);
[[nodiscard]] U32 BitwiseAnd(const U32& a, const U32& b);
[[nodiscard]] U32 BitwiseOr(const U32& a, const U32& b);
[[nodiscard]] U32U64 BitwiseOr(const U32U64& a, const U32U64& b);
[[nodiscard]] U32 BitwiseXor(const U32& a, const U32& b);
[[nodiscard]] U32 BitFieldInsert(const U32& base, const U32& insert, const U32& offset,
const U32& count);
@ -188,7 +188,7 @@ public:
[[nodiscard]] U32 SClamp(const U32& value, const U32& min, const U32& max);
[[nodiscard]] U32 UClamp(const U32& value, const U32& min, const U32& max);
[[nodiscard]] U1 ILessThan(const U32& lhs, const U32& rhs, bool is_signed);
[[nodiscard]] U1 ILessThan(const U32U64& lhs, const U32U64& rhs, bool is_signed);
[[nodiscard]] U1 IEqual(const U32U64& lhs, const U32U64& rhs);
[[nodiscard]] U1 ILessThanEqual(const U32& lhs, const U32& rhs, bool is_signed);
[[nodiscard]] U1 IGreaterThan(const U32& lhs, const U32& rhs, bool is_signed);

View file

@ -227,6 +227,7 @@ OPCODE(IAddCary32, U32x2, U32,
OPCODE(ISub32, U32, U32, U32, )
OPCODE(ISub64, U64, U64, U64, )
OPCODE(IMul32, U32, U32, U32, )
OPCODE(IMul64, U64, U64, U64, )
OPCODE(SMulExt, U32x2, U32, U32, )
OPCODE(UMulExt, U32x2, U32, U32, )
OPCODE(SDiv32, U32, U32, U32, )
@ -242,6 +243,7 @@ OPCODE(ShiftRightArithmetic32, U32, U32,
OPCODE(ShiftRightArithmetic64, U64, U64, U32, )
OPCODE(BitwiseAnd32, U32, U32, U32, )
OPCODE(BitwiseOr32, U32, U32, U32, )
OPCODE(BitwiseOr64, U64, U64, U64, )
OPCODE(BitwiseXor32, U32, U32, U32, )
OPCODE(BitFieldInsert, U32, U32, U32, U32, U32, )
OPCODE(BitFieldSExtract, U32, U32, U32, U32, )
@ -258,8 +260,10 @@ OPCODE(SMax32, U32, U32,
OPCODE(UMax32, U32, U32, U32, )
OPCODE(SClamp32, U32, U32, U32, U32, )
OPCODE(UClamp32, U32, U32, U32, U32, )
OPCODE(SLessThan, U1, U32, U32, )
OPCODE(ULessThan, U1, U32, U32, )
OPCODE(SLessThan32, U1, U32, U32, )
OPCODE(SLessThan64, U1, U64, U64, )
OPCODE(ULessThan32, U1, U32, U32, )
OPCODE(ULessThan64, U1, U64, U64, )
OPCODE(IEqual, U1, U32, U32, )
OPCODE(SLessThanEqual, U1, U32, U32, )
OPCODE(ULessThanEqual, U1, U32, U32, )

View file

@ -21,6 +21,8 @@ template <typename T>
return value.F32();
} else if constexpr (std::is_same_v<T, u64>) {
return value.U64();
} else if constexpr (std::is_same_v<T, s64>) {
return static_cast<s64>(value.U64());
}
}
@ -281,12 +283,18 @@ void ConstantPropagation(IR::Block& block, IR::Inst& inst) {
return FoldLogicalOr(inst);
case IR::Opcode::LogicalNot:
return FoldLogicalNot(inst);
case IR::Opcode::SLessThan:
case IR::Opcode::SLessThan32:
FoldWhenAllImmediates(inst, [](s32 a, s32 b) { return a < b; });
return;
case IR::Opcode::ULessThan:
case IR::Opcode::SLessThan64:
FoldWhenAllImmediates(inst, [](s64 a, s64 b) { return a < b; });
return;
case IR::Opcode::ULessThan32:
FoldWhenAllImmediates(inst, [](u32 a, u32 b) { return a < b; });
return;
case IR::Opcode::ULessThan64:
FoldWhenAllImmediates(inst, [](u64 a, u64 b) { return a < b; });
return;
case IR::Opcode::SLessThanEqual:
FoldWhenAllImmediates(inst, [](s32 a, s32 b) { return a <= b; });
return;

View file

@ -348,13 +348,15 @@ void VisitInst(Pass& pass, IR::Block* block, IR::Inst& inst) {
case IR::Opcode::GetThreadBitScalarReg:
case IR::Opcode::GetScalarRegister: {
const IR::ScalarReg reg{inst.Arg(0).ScalarReg()};
inst.ReplaceUsesWith(
pass.ReadVariable(reg, block, opcode == IR::Opcode::GetThreadBitScalarReg));
const bool thread_bit = opcode == IR::Opcode::GetThreadBitScalarReg;
const IR::Value value = pass.ReadVariable(reg, block, thread_bit);
inst.ReplaceUsesWith(value);
break;
}
case IR::Opcode::GetVectorRegister: {
const IR::VectorReg reg{inst.Arg(0).VectorReg()};
inst.ReplaceUsesWith(pass.ReadVariable(reg, block));
const IR::Value value = pass.ReadVariable(reg, block);
inst.ReplaceUsesWith(value);
break;
}
case IR::Opcode::GetGotoVariable:

View file

@ -220,6 +220,7 @@ using F16 = TypedValue<Type::F16>;
using F32 = TypedValue<Type::F32>;
using F64 = TypedValue<Type::F64>;
using U32F32 = TypedValue<Type::U32 | Type::F32>;
using U64F64 = TypedValue<Type::U64 | Type::F64>;
using U32U64 = TypedValue<Type::U32 | Type::U64>;
using U16U32U64 = TypedValue<Type::U16 | Type::U32 | Type::U64>;
using F32F64 = TypedValue<Type::F32 | Type::F64>;