mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-21 03:54:45 +00:00
impl V_ADDC_U32 & V_MAD_U64_U32
This commit is contained in:
parent
bfe3322977
commit
e23749bf0e
9 changed files with 138 additions and 3 deletions
|
@ -258,6 +258,7 @@ Id EmitISub64(EmitContext& ctx, Id a, Id b);
|
|||
Id EmitSMulExt(EmitContext& ctx, Id a, Id b);
|
||||
Id EmitUMulExt(EmitContext& ctx, Id a, Id b);
|
||||
Id EmitIMul32(EmitContext& ctx, Id a, Id b);
|
||||
Id EmitIMul64(EmitContext& ctx, Id a, Id b);
|
||||
Id EmitSDiv32(EmitContext& ctx, Id a, Id b);
|
||||
Id EmitUDiv32(EmitContext& ctx, Id a, Id b);
|
||||
Id EmitINeg32(EmitContext& ctx, Id value);
|
||||
|
|
|
@ -84,6 +84,10 @@ Id EmitIMul32(EmitContext& ctx, Id a, Id b) {
|
|||
return ctx.OpIMul(ctx.U32[1], a, b);
|
||||
}
|
||||
|
||||
Id EmitIMul64(EmitContext& ctx, Id a, Id b) {
|
||||
return ctx.OpIMul(ctx.U64, a, b);
|
||||
}
|
||||
|
||||
Id EmitSDiv32(EmitContext& ctx, Id a, Id b) {
|
||||
return ctx.OpSDiv(ctx.U32[1], a, b);
|
||||
}
|
||||
|
|
|
@ -319,6 +319,9 @@ void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_l
|
|||
case Opcode::V_ADD_I32:
|
||||
translator.V_ADD_I32(inst);
|
||||
break;
|
||||
case Opcode::V_ADDC_U32:
|
||||
translator.V_ADDC_U32(inst);
|
||||
break;
|
||||
case Opcode::V_CVT_F32_I32:
|
||||
translator.V_CVT_F32_I32(inst);
|
||||
break;
|
||||
|
@ -469,6 +472,9 @@ void Translate(IR::Block* block, u32 block_base, std::span<const GcnInst> inst_l
|
|||
case Opcode::IMAGE_LOAD:
|
||||
translator.IMAGE_LOAD(false, inst);
|
||||
break;
|
||||
case Opcode::V_MAD_U64_U32:
|
||||
translator.V_MAD_U64_U32(inst);
|
||||
break;
|
||||
case Opcode::V_CMP_GE_I32:
|
||||
translator.V_CMP_U32(ConditionOp::GE, true, false, inst);
|
||||
break;
|
||||
|
|
|
@ -100,6 +100,7 @@ public:
|
|||
void V_AND_B32(const GcnInst& inst);
|
||||
void V_LSHLREV_B32(const GcnInst& inst);
|
||||
void V_ADD_I32(const GcnInst& inst);
|
||||
void V_ADDC_U32(const GcnInst& inst);
|
||||
void V_CVT_F32_I32(const GcnInst& inst);
|
||||
void V_CVT_F32_U32(const GcnInst& inst);
|
||||
void V_MAD_F32(const GcnInst& inst);
|
||||
|
@ -129,6 +130,7 @@ public:
|
|||
void V_CVT_U32_F32(const GcnInst& inst);
|
||||
void V_SUBREV_F32(const GcnInst& inst);
|
||||
void V_SUBREV_I32(const GcnInst& inst);
|
||||
void V_MAD_U64_U32(const GcnInst& inst);
|
||||
void V_CMP_U32(ConditionOp op, bool is_signed, bool set_exec, const GcnInst& inst);
|
||||
void V_LSHRREV_B32(const GcnInst& inst);
|
||||
void V_MUL_HI_U32(bool is_signed, const GcnInst& inst);
|
||||
|
|
|
@ -92,6 +92,41 @@ void Translator::V_ADD_I32(const GcnInst& inst) {
|
|||
// TODO: Carry
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
IR::U32 scarry;
|
||||
if (inst.src_count == 3) { // VOP3
|
||||
scarry = {GetSrc(inst.src[2])};
|
||||
} else { // VOP2
|
||||
scarry = {ir.GetVccLo()};
|
||||
}
|
||||
|
||||
IR::U32 result = ir.IAdd(ir.IAdd(src0, src1), scarry);
|
||||
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg(dst_reg, result);
|
||||
ir.SetVcc(ir.IGreaterThan(result, ir.Imm32(0xFFFFFFFF), false));
|
||||
}
|
||||
|
||||
void Translator::V_CVT_F32_I32(const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
|
@ -294,6 +329,51 @@ void Translator::V_SUBREV_I32(const GcnInst& inst) {
|
|||
// TODO: Carry-out
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
IR::U64 result;
|
||||
result = ir.IMul(src0, src1);
|
||||
result = ir.IAdd(ir.UConvert(64, result), src2);
|
||||
|
||||
const IR::VectorReg dst_reg{inst.dst[0].code};
|
||||
ir.SetVectorReg64(dst_reg, result);
|
||||
}
|
||||
|
||||
void Translator::V_CMP_U32(ConditionOp op, bool is_signed, bool set_exec, const GcnInst& inst) {
|
||||
const IR::U32 src0{GetSrc(inst.src[0])};
|
||||
const IR::U32 src1{GetSrc(inst.src[1])};
|
||||
|
|
|
@ -168,11 +168,21 @@ void IREmitter::SetScalarReg(IR::ScalarReg reg, const U32F32& value) {
|
|||
Inst(Opcode::SetScalarRegister, reg, value_typed);
|
||||
}
|
||||
|
||||
void IREmitter::SetScalarReg64(IR::ScalarReg reg, const U64F64& value) {
|
||||
const U64 value_typed = value.Type() == Type::F64 ? BitCast<U64>(F64{value}) : U64{value};
|
||||
Inst(Opcode::SetScalarRegister, reg, value_typed);
|
||||
}
|
||||
|
||||
void IREmitter::SetVectorReg(IR::VectorReg reg, const U32F32& value) {
|
||||
const U32 value_typed = value.Type() == Type::F32 ? BitCast<U32>(F32{value}) : U32{value};
|
||||
Inst(Opcode::SetVectorRegister, reg, value_typed);
|
||||
}
|
||||
|
||||
void IREmitter::SetVectorReg64(IR::VectorReg reg, const U64F64& value) {
|
||||
const U64 value_typed = value.Type() == Type::F64 ? BitCast<U64>(F64{value}) : U64{value};
|
||||
Inst(Opcode::SetVectorRegister, reg, value);
|
||||
}
|
||||
|
||||
U1 IREmitter::GetGotoVariable(u32 id) {
|
||||
return Inst<U1>(Opcode::GetGotoVariable, id);
|
||||
}
|
||||
|
@ -964,8 +974,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) {
|
||||
|
@ -1168,6 +1188,13 @@ U32U64 IREmitter::ConvertFToU(size_t bitsize, const F32F64& value) {
|
|||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
case 64:
|
||||
switch (value.Type()) {
|
||||
case Type::F32:
|
||||
return Inst<U64>(Opcode::ConvertU64F32, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
default:
|
||||
UNREACHABLE_MSG("Invalid destination bitsize {}", bitsize);
|
||||
}
|
||||
|
@ -1227,6 +1254,15 @@ U16U32U64 IREmitter::UConvert(size_t result_bitsize, const U16U32U64& value) {
|
|||
switch (value.Type()) {
|
||||
case Type::U32:
|
||||
return Inst<U16>(Opcode::ConvertU16U32, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
case 64:
|
||||
switch (value.Type()) {
|
||||
case Type::U32:
|
||||
return Inst<U64>(Opcode::ConvertU64U32, value);
|
||||
default:
|
||||
ThrowInvalidType(value.Type());
|
||||
}
|
||||
}
|
||||
throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize);
|
||||
|
|
|
@ -57,7 +57,9 @@ public:
|
|||
template <typename T = U32>
|
||||
[[nodiscard]] T GetVectorReg(IR::VectorReg reg);
|
||||
void SetScalarReg(IR::ScalarReg reg, const U32F32& value);
|
||||
void SetScalarReg64(IR::ScalarReg reg, const U64F64& value);
|
||||
void SetVectorReg(IR::VectorReg reg, const U32F32& value);
|
||||
void SetVectorReg64(IR::VectorReg reg, const U64F64& value);
|
||||
|
||||
[[nodiscard]] U1 GetGotoVariable(u32 id);
|
||||
void SetGotoVariable(u32 id, const U1& value);
|
||||
|
@ -159,7 +161,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);
|
||||
|
|
|
@ -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, )
|
||||
|
@ -289,6 +290,8 @@ OPCODE(ConvertF64S32, F64, U32,
|
|||
OPCODE(ConvertF64U32, F64, U32, )
|
||||
OPCODE(ConvertF32U16, F32, U16, )
|
||||
OPCODE(ConvertU16U32, U16, U32, )
|
||||
OPCODE(ConvertU64U32, U64, U32, )
|
||||
OPCODE(ConvertU64F32, U64, F32, )
|
||||
|
||||
// Image operations
|
||||
OPCODE(ImageSampleImplicitLod, F32x4, Opaque, Opaque, Opaque, Opaque, )
|
||||
|
|
|
@ -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>;
|
||||
|
|
Loading…
Add table
Reference in a new issue