mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-07-22 18:15:14 +00:00
implement loads/store instructions for types smaller than dwords
This commit is contained in:
parent
b403e1be33
commit
d7a45554ad
@ -271,4 +271,16 @@ Id EmitConvertU32U8(EmitContext& ctx, Id value) {
|
||||
return ctx.OpUConvert(ctx.U32[1], value);
|
||||
}
|
||||
|
||||
Id EmitConvertS32S8(EmitContext& ctx, Id value) {
|
||||
const Id as_s8 = ctx.OpBitcast(ctx.S8, value);
|
||||
const Id as_s32 = ctx.OpSConvert(ctx.S32[1], as_s8);
|
||||
return ctx.OpBitcast(ctx.U32[1], as_s32);
|
||||
}
|
||||
|
||||
Id EmitConvertS32S16(EmitContext& ctx, Id value) {
|
||||
const Id as_s16 = ctx.OpBitcast(ctx.S16, value);
|
||||
const Id as_s32 = ctx.OpSConvert(ctx.S32[1], as_s16);
|
||||
return ctx.OpBitcast(ctx.U32[1], as_s32);
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::SPIRV
|
||||
|
@ -488,6 +488,8 @@ Id EmitConvertU16U32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertU32U16(EmitContext& ctx, Id value);
|
||||
Id EmitConvertU8U32(EmitContext& ctx, Id value);
|
||||
Id EmitConvertU32U8(EmitContext& ctx, Id value);
|
||||
Id EmitConvertS32S8(EmitContext& ctx, Id value);
|
||||
Id EmitConvertS32S16(EmitContext& ctx, Id value);
|
||||
|
||||
Id EmitImageSampleRaw(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address1, Id address2,
|
||||
Id address3, Id address4);
|
||||
|
@ -280,9 +280,10 @@ public:
|
||||
|
||||
// Buffer Memory
|
||||
// MUBUF / MTBUF
|
||||
void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst);
|
||||
void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed,
|
||||
const GcnInst& inst);
|
||||
void BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst,
|
||||
u32 scalar_width = 32, bool is_signed = false);
|
||||
void BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed, const GcnInst& inst,
|
||||
u32 scalar_width = 32);
|
||||
template <typename T = IR::U32>
|
||||
void BUFFER_ATOMIC(AtomicOp op, const GcnInst& inst);
|
||||
|
||||
|
@ -28,6 +28,15 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
|
||||
case Opcode::BUFFER_LOAD_FORMAT_XYZW:
|
||||
return BUFFER_LOAD(4, false, true, inst);
|
||||
|
||||
case Opcode::BUFFER_LOAD_UBYTE:
|
||||
return BUFFER_LOAD(1, false, false, inst, 8, false);
|
||||
case Opcode::BUFFER_LOAD_SBYTE:
|
||||
return BUFFER_LOAD(1, false, false, inst, 8, true);
|
||||
case Opcode::BUFFER_LOAD_USHORT:
|
||||
return BUFFER_LOAD(1, false, false, inst, 16, false);
|
||||
case Opcode::BUFFER_LOAD_SSHORT:
|
||||
return BUFFER_LOAD(1, false, false, inst, 16, true);
|
||||
|
||||
case Opcode::BUFFER_LOAD_DWORD:
|
||||
return BUFFER_LOAD(1, false, false, inst);
|
||||
case Opcode::BUFFER_LOAD_DWORDX2:
|
||||
@ -56,6 +65,11 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
|
||||
case Opcode::TBUFFER_STORE_FORMAT_XYZW:
|
||||
return BUFFER_STORE(4, true, false, inst);
|
||||
|
||||
case Opcode::BUFFER_STORE_BYTE:
|
||||
return BUFFER_STORE(1, false, false, inst, 8);
|
||||
case Opcode::BUFFER_STORE_SHORT:
|
||||
return BUFFER_STORE(1, false, false, inst, 16);
|
||||
|
||||
case Opcode::BUFFER_STORE_DWORD:
|
||||
return BUFFER_STORE(1, false, false, inst);
|
||||
case Opcode::BUFFER_STORE_DWORDX2:
|
||||
@ -186,7 +200,7 @@ void Translator::EmitVectorMemory(const GcnInst& inst) {
|
||||
}
|
||||
|
||||
void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed,
|
||||
const GcnInst& inst) {
|
||||
const GcnInst& inst, u32 scalar_width, bool is_signed) {
|
||||
const auto& mubuf = inst.control.mubuf;
|
||||
const bool is_ring = mubuf.glc && mubuf.slc;
|
||||
const IR::VectorReg vaddr{inst.src[0].code};
|
||||
@ -242,7 +256,28 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_
|
||||
ir.SetVectorReg(dst_reg + i, IR::F32{ir.CompositeExtract(value, i)});
|
||||
}
|
||||
} else {
|
||||
const IR::Value value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info);
|
||||
IR::Value value;
|
||||
switch (scalar_width) {
|
||||
case 8:
|
||||
value = ir.LoadBufferU8(handle, address, buffer_info);
|
||||
if (is_signed) {
|
||||
value = ir.SConvert(32, IR::U8{value});
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
value = ir.LoadBufferU16(handle, address, buffer_info);
|
||||
if (is_signed) {
|
||||
value = ir.SConvert(32, IR::U16{value});
|
||||
}
|
||||
break;
|
||||
case 32:
|
||||
value = ir.LoadBufferU32(num_dwords, handle, address, buffer_info);
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (num_dwords == 1) {
|
||||
ir.SetVectorReg(dst_reg, IR::U32{value});
|
||||
return;
|
||||
@ -254,7 +289,7 @@ void Translator::BUFFER_LOAD(u32 num_dwords, bool is_inst_typed, bool is_buffer_
|
||||
}
|
||||
|
||||
void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer_typed,
|
||||
const GcnInst& inst) {
|
||||
const GcnInst& inst, u32 scalar_width) {
|
||||
const auto& mubuf = inst.control.mubuf;
|
||||
const bool is_ring = mubuf.glc && mubuf.slc;
|
||||
const IR::VectorReg vaddr{inst.src[0].code};
|
||||
@ -314,8 +349,23 @@ void Translator::BUFFER_STORE(u32 num_dwords, bool is_inst_typed, bool is_buffer
|
||||
}
|
||||
ir.StoreBufferFormat(handle, address, ir.CompositeConstruct(comps), buffer_info);
|
||||
} else {
|
||||
const auto value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps);
|
||||
IR::Value value = num_dwords == 1 ? comps[0] : ir.CompositeConstruct(comps);
|
||||
if (scalar_width != 32) {
|
||||
value = ir.UConvert(scalar_width, IR::U32{value});
|
||||
}
|
||||
switch (scalar_width) {
|
||||
case 8:
|
||||
ir.StoreBufferU8(handle, address, IR::U8{value}, buffer_info);
|
||||
break;
|
||||
case 16:
|
||||
ir.StoreBufferU16(handle, address, IR::U16{value}, buffer_info);
|
||||
break;
|
||||
case 32:
|
||||
ir.StoreBufferU32(num_dwords, handle, address, value, buffer_info);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1979,6 +1979,24 @@ U8U16U32U64 IREmitter::UConvert(size_t result_bitsize, const U8U16U32U64& value)
|
||||
throw NotImplementedException("Conversion from {} to {} bits", value.Type(), result_bitsize);
|
||||
}
|
||||
|
||||
U8U16U32U64 IR::IREmitter::SConvert(size_t result_bitsize, const U8U16U32U64& value) {
|
||||
switch (result_bitsize) {
|
||||
case 32:
|
||||
switch (value.Type()) {
|
||||
case Type::U8:
|
||||
return Inst<U32>(Opcode::ConvertS32S8, value);
|
||||
case Type::U16:
|
||||
return Inst<U32>(Opcode::ConvertS32S16, value);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
throw NotImplementedException("Signed Conversion from {} to {} bits", value.Type(),
|
||||
result_bitsize);
|
||||
}
|
||||
|
||||
F16F32F64 IREmitter::FPConvert(size_t result_bitsize, const F16F32F64& value) {
|
||||
switch (result_bitsize) {
|
||||
case 16:
|
||||
|
@ -326,6 +326,7 @@ public:
|
||||
const Value& value);
|
||||
|
||||
[[nodiscard]] U8U16U32U64 UConvert(size_t result_bitsize, const U8U16U32U64& value);
|
||||
[[nodiscard]] U8U16U32U64 SConvert(size_t result_bitsize, const U8U16U32U64& value);
|
||||
[[nodiscard]] F16F32F64 FPConvert(size_t result_bitsize, const F16F32F64& value);
|
||||
|
||||
[[nodiscard]] Value ImageAtomicIAdd(const Value& handle, const Value& coords,
|
||||
|
@ -432,6 +432,8 @@ OPCODE(ConvertU16U32, U16, U32,
|
||||
OPCODE(ConvertU32U16, U32, U16, )
|
||||
OPCODE(ConvertU8U32, U8, U32, )
|
||||
OPCODE(ConvertU32U8, U32, U8, )
|
||||
OPCODE(ConvertS32S8, U32, U8, )
|
||||
OPCODE(ConvertS32S16, U32, U16, )
|
||||
|
||||
// Image operations
|
||||
OPCODE(ImageSampleRaw, F32x4, Opaque, F32x4, F32x4, F32x4, F32, Opaque, )
|
||||
|
Loading…
Reference in New Issue
Block a user