mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-08-19 06:52:36 +00:00
821 lines
32 KiB
C++
821 lines
32 KiB
C++
#include "common/assert.h"
|
|
#include "graphics/shader/recompiler/BufferFormat.h"
|
|
#include "graphics/shader/recompiler/ir/ShaderIR.h"
|
|
#include "graphics/shader/recompiler/ir/ShaderIRInternal.h"
|
|
|
|
#include <algorithm>
|
|
#include <fmt/format.h>
|
|
#include <utility>
|
|
|
|
namespace Libs::Graphics::ShaderRecompiler::IR {
|
|
namespace {
|
|
|
|
Opcode BufferLoadOpcode(const Decoder::Instruction& decoded) {
|
|
switch (decoded.data_bits) {
|
|
case 8u: return decoded.data_signed ? Opcode::BufferLoadSbyte : Opcode::BufferLoadUbyte;
|
|
case 16u: return decoded.data_signed ? Opcode::BufferLoadSshort : Opcode::BufferLoadUshort;
|
|
default: return Opcode::BufferLoadDword;
|
|
}
|
|
}
|
|
|
|
Opcode BufferStoreOpcode(uint32_t data_bits) {
|
|
switch (data_bits) {
|
|
case 8u: return Opcode::BufferStoreByte;
|
|
case 16u: return Opcode::BufferStoreShort;
|
|
default: return Opcode::BufferStoreDword;
|
|
}
|
|
}
|
|
|
|
Opcode DsReadOpcode(const Decoder::Instruction& decoded) {
|
|
switch (decoded.data_bits) {
|
|
case 8u: return decoded.data_signed ? Opcode::DsReadSbyte : Opcode::DsReadUbyte;
|
|
case 16u: return decoded.data_signed ? Opcode::DsReadSshort : Opcode::DsReadUshort;
|
|
default: return Opcode::DsReadB32;
|
|
}
|
|
}
|
|
|
|
Opcode FlatLoadOpcode(const Decoder::Instruction& decoded) {
|
|
switch (decoded.data_bits) {
|
|
case 8u: return decoded.data_signed ? Opcode::FlatLoadSbyte : Opcode::FlatLoadUbyte;
|
|
case 16u: return decoded.data_signed ? Opcode::FlatLoadSshort : Opcode::FlatLoadUshort;
|
|
default: return Opcode::FlatLoadDword;
|
|
}
|
|
}
|
|
|
|
Opcode FlatStoreOpcode(uint32_t data_bits) {
|
|
switch (data_bits) {
|
|
case 8u: return Opcode::FlatStoreByte;
|
|
case 16u: return Opcode::FlatStoreShort;
|
|
default: return Opcode::FlatStoreDword;
|
|
}
|
|
}
|
|
|
|
Opcode DsWriteOpcode(uint32_t data_bits) {
|
|
switch (data_bits) {
|
|
case 8u: return Opcode::DsWriteByte;
|
|
case 16u: return Opcode::DsWriteShort;
|
|
default: return Opcode::DsWriteB32;
|
|
}
|
|
}
|
|
|
|
Opcode LoweredImageOpcode(Decoder::Opcode opcode) {
|
|
switch (opcode) {
|
|
case Decoder::Opcode::ImageGetResinfo: return Opcode::ImageGetResinfo;
|
|
case Decoder::Opcode::ImageGetLod: return Opcode::ImageGetLod;
|
|
case Decoder::Opcode::ImageLoad:
|
|
case Decoder::Opcode::ImageLoadMip: return Opcode::ImageLoad;
|
|
case Decoder::Opcode::ImageGather4Lz:
|
|
case Decoder::Opcode::ImageGather4C:
|
|
case Decoder::Opcode::ImageGather4CLz:
|
|
case Decoder::Opcode::ImageGather4LzO:
|
|
case Decoder::Opcode::ImageGather4CO:
|
|
case Decoder::Opcode::ImageGather4CLzO:
|
|
case Decoder::Opcode::ImageGather4H: return Opcode::ImageGather4;
|
|
default: return Opcode::ImageSample;
|
|
}
|
|
}
|
|
|
|
bool LowerScalarBufferLoadDword(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op,
|
|
std::string* error) {
|
|
for (uint32_t i = 0; i < decoded.data_dwords; i++) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = op;
|
|
inst.src_count = 1;
|
|
inst.memory = OffsetMemoryInfo(decoded, ResourceKind::ScalarBuffer, i);
|
|
// Raw s_load uses a two-SGPR pointer base; s_buffer_load uses a four-SGPR
|
|
// descriptor resource index.
|
|
inst.memory.resource = op == Opcode::SLoadDword ? RawScalarLoadBase(decoded.src0)
|
|
: ResourceIndexFromOperand(decoded.src0);
|
|
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) ||
|
|
!LowerSourceOperand(decoded.src1, inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerBufferAddressSources(const Decoder::Instruction& decoded, Instruction& inst,
|
|
uint32_t first_src, std::string* error) {
|
|
uint32_t src = first_src;
|
|
if (decoded.idxen) {
|
|
if (!LowerSourceOperand(decoded.src0, inst.src[src++], error)) {
|
|
return false;
|
|
}
|
|
}
|
|
if (decoded.offen) {
|
|
const auto offset_source =
|
|
decoded.idxen ? OffsetDecodedRegister(decoded.src0, 1) : decoded.src0;
|
|
if (!LowerSourceOperand(offset_source, inst.src[src++], error)) {
|
|
return false;
|
|
}
|
|
}
|
|
if (!LowerSourceOperand(decoded.src2, inst.src[src++], error)) {
|
|
return false;
|
|
}
|
|
inst.src_count = src;
|
|
return true;
|
|
}
|
|
|
|
bool LowerBufferLoad(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
|
const auto ir_op = BufferLoadOpcode(decoded);
|
|
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
|
const auto typed_format_components = TypedBufferFormatComponentCount(decoded);
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
if (i >= typed_format_components) {
|
|
if (!LowerMoveImmediateU32(decoded.pc, OffsetDecodedRegister(decoded.dst, i), 0, block,
|
|
error)) {
|
|
return false;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ir_op;
|
|
inst.memory = OffsetBufferMemoryInfo(decoded, i);
|
|
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) ||
|
|
!LowerBufferAddressSources(decoded, inst, 0, error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerBufferStore(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
|
const auto ir_op = BufferStoreOpcode(decoded.data_bits);
|
|
auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
|
if (decoded.data_bits == 32u) {
|
|
const auto typed_format_components = TypedBufferFormatComponentCount(decoded);
|
|
if (typed_format_components < count) {
|
|
count = typed_format_components;
|
|
}
|
|
}
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ir_op;
|
|
inst.memory = OffsetBufferMemoryInfo(decoded, i);
|
|
inst.dst.kind = OperandKind::Null;
|
|
if (!LowerSourceOperand(OffsetDecodedRegister(decoded.dst, i), inst.src[0], error) ||
|
|
!LowerBufferAddressSources(decoded, inst, 1, error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerBufferAtomicDword(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op,
|
|
std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = op;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::Buffer);
|
|
inst.dst.kind = OperandKind::Null;
|
|
if ((decoded.glc && !LowerRegisterOperand(decoded.dst, inst.dst, error)) ||
|
|
!LowerSourceOperand(decoded.dst, inst.src[0], error) ||
|
|
!LowerBufferAddressSources(decoded, inst, 1, error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
ResourceKind DsMemoryKind(const Decoder::Instruction& decoded) {
|
|
return decoded.gds ? ResourceKind::Gds : ResourceKind::Lds;
|
|
}
|
|
|
|
bool LowerDsRead(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
|
const auto ir_op = DsReadOpcode(decoded);
|
|
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ir_op;
|
|
inst.src_count = 1;
|
|
inst.memory = OffsetMemoryInfo(decoded, DsMemoryKind(decoded), i);
|
|
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsRead2(const Decoder::Instruction& decoded, BasicBlock& block, uint32_t dwords_per_read,
|
|
std::string* error) {
|
|
const uint32_t offsets[] = {decoded.offset, decoded.secondary_offset};
|
|
for (uint32_t read = 0; read < 2u; read++) {
|
|
for (uint32_t dword = 0; dword < dwords_per_read; dword++) {
|
|
const auto index = read * dwords_per_read + dword;
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = Opcode::DsReadB32;
|
|
inst.src_count = 1;
|
|
inst.memory =
|
|
ByteOffsetMemoryInfo(decoded, DsMemoryKind(decoded), offsets[read] + dword * 4u);
|
|
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, index), inst.dst, error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsAtomicU32(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op,
|
|
bool return_old, std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = op;
|
|
inst.src_count = 2;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
|
|
inst.dst.kind = return_old ? OperandKind::Register : OperandKind::Null;
|
|
if ((return_old && !LowerRegisterOperand(decoded.dst, inst.dst, error)) ||
|
|
!LowerSourceOperand(decoded.src1, inst.src[0], error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsSwizzleB32(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = Opcode::DsSwizzleB32;
|
|
inst.src_count = 2;
|
|
inst.src[1].kind = OperandKind::ImmediateU32;
|
|
inst.src[1].imm = decoded.offset & 0xffffu;
|
|
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsFloatMinMaxF32(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op,
|
|
std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = op;
|
|
inst.src_count = 2;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
|
|
inst.memory.resource = 0;
|
|
inst.dst.kind = OperandKind::Null;
|
|
if (!LowerSourceOperand(decoded.src1, inst.src[0], error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[1], error) ||
|
|
!LowerSourceOperand(decoded.src2, inst.src[2], error)) {
|
|
return false;
|
|
}
|
|
inst.src_count = 3;
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsWriteAddtidB32(const Decoder::Instruction& decoded, BasicBlock& block,
|
|
std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = Opcode::DsWriteAddtidB32;
|
|
inst.src_count = 2;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
|
|
inst.memory.resource = 0;
|
|
inst.dst.kind = OperandKind::Null;
|
|
const auto m0 = M0Operand();
|
|
if (!LowerSourceOperand(decoded.src1, inst.src[0], error) ||
|
|
!LowerSourceOperand(m0, inst.src[1], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsReadAddtidB32(const Decoder::Instruction& decoded, BasicBlock& block,
|
|
std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = Opcode::DsReadAddtidB32;
|
|
inst.src_count = 1;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
|
|
inst.memory.resource = 0;
|
|
const auto m0 = M0Operand();
|
|
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
|
|
!LowerSourceOperand(m0, inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsAppendConsume(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op,
|
|
std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = op;
|
|
inst.src_count = 1;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, DsMemoryKind(decoded));
|
|
const auto m0 = M0Operand();
|
|
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
|
|
!LowerSourceOperand(m0, inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
Opcode ImageAtomicIrOpcode(Decoder::Opcode opcode) {
|
|
switch (opcode) {
|
|
case Decoder::Opcode::ImageAtomicAdd: return Opcode::AtomicAddU32;
|
|
case Decoder::Opcode::ImageAtomicUMin: return Opcode::AtomicUMinU32;
|
|
case Decoder::Opcode::ImageAtomicUMax: return Opcode::AtomicUMaxU32;
|
|
case Decoder::Opcode::ImageAtomicAnd: return Opcode::AtomicAndU32;
|
|
case Decoder::Opcode::ImageAtomicOr: return Opcode::AtomicOrU32;
|
|
case Decoder::Opcode::ImageAtomicXor: return Opcode::AtomicXorU32;
|
|
default: return Opcode::AtomicAddU32;
|
|
}
|
|
}
|
|
|
|
bool LowerImageAtomicU32(const Decoder::Instruction& decoded, BasicBlock& block,
|
|
std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ImageAtomicIrOpcode(decoded.opcode);
|
|
inst.src_count = 2;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::StorageImageUint);
|
|
inst.memory.sampler = 0;
|
|
inst.dst.kind = OperandKind::Null;
|
|
if ((decoded.glc && !LowerRegisterOperand(decoded.dst, inst.dst, error)) ||
|
|
!LowerSourceOperand(decoded.dst, inst.src[0], error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
bool LowerFlatLoad(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
|
const auto kind = FlatSegmentResourceKind(decoded.memory_segment);
|
|
const auto ir_op = FlatLoadOpcode(decoded);
|
|
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
|
if (decoded.data_bits == 32u && count > 1u) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ir_op;
|
|
inst.src_count = decoded.src_count;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, kind);
|
|
inst.memory.resource = 0;
|
|
if (!LowerRegisterOperand(decoded.dst, inst.dst, error)) {
|
|
return false;
|
|
}
|
|
for (uint32_t i = 0; i < decoded.src_count && i < 3u; i++) {
|
|
if (!LowerSourceOperand(DecodedSourceAt(decoded, i), inst.src[i], error)) {
|
|
return false;
|
|
}
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
for (uint32_t dword = 0; dword < count; dword++) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ir_op;
|
|
inst.src_count = decoded.src_count;
|
|
inst.memory = OffsetMemoryInfo(decoded, kind, dword);
|
|
inst.memory.resource = 0;
|
|
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, dword), inst.dst, error)) {
|
|
return false;
|
|
}
|
|
for (uint32_t i = 0; i < decoded.src_count && i < 3u; i++) {
|
|
if (!LowerSourceOperand(DecodedSourceAt(decoded, i), inst.src[i], error)) {
|
|
return false;
|
|
}
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerFlatStore(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
|
const auto kind = FlatSegmentResourceKind(decoded.memory_segment);
|
|
const auto ir_op = FlatStoreOpcode(decoded.data_bits);
|
|
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
|
for (uint32_t dword = 0; dword < count; dword++) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ir_op;
|
|
inst.src_count = decoded.src_count + 1u;
|
|
inst.memory = OffsetMemoryInfo(decoded, kind, dword);
|
|
inst.memory.resource = 0;
|
|
inst.dst.kind = OperandKind::Null;
|
|
if (!LowerSourceOperand(OffsetDecodedRegister(decoded.dst, dword), inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
for (uint32_t i = 0; i < decoded.src_count && i + 1u < 3u; i++) {
|
|
if (!LowerSourceOperand(DecodedSourceAt(decoded, i), inst.src[i + 1u], error)) {
|
|
return false;
|
|
}
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsWrite(const Decoder::Instruction& decoded, BasicBlock& block, std::string* error) {
|
|
const auto ir_op = DsWriteOpcode(decoded.data_bits);
|
|
const auto count = decoded.data_bits == 32u ? decoded.data_dwords : 1u;
|
|
for (uint32_t i = 0; i < count; i++) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = ir_op;
|
|
inst.src_count = 2;
|
|
inst.memory = OffsetMemoryInfo(decoded, DsMemoryKind(decoded), i);
|
|
inst.dst.kind = OperandKind::Null;
|
|
if (!LowerSourceOperand(OffsetDecodedRegister(decoded.src1, i), inst.src[0], error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerDsWrite2(const Decoder::Instruction& decoded, BasicBlock& block,
|
|
uint32_t dwords_per_write, std::string* error) {
|
|
const Decoder::Operand* data[] = {&decoded.src1, &decoded.src2};
|
|
const uint32_t offsets[] = {decoded.offset, decoded.secondary_offset};
|
|
for (uint32_t write = 0; write < 2u; write++) {
|
|
for (uint32_t dword = 0; dword < dwords_per_write; dword++) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
inst.op = Opcode::DsWriteB32;
|
|
inst.src_count = 2;
|
|
inst.memory =
|
|
ByteOffsetMemoryInfo(decoded, DsMemoryKind(decoded), offsets[write] + dword * 4u);
|
|
inst.dst.kind = OperandKind::Null;
|
|
if (!LowerSourceOperand(OffsetDecodedRegister(*data[write], dword), inst.src[0],
|
|
error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool LowerImageOperation(const Decoder::Instruction& decoded, BasicBlock& block,
|
|
std::string* error) {
|
|
Instruction inst;
|
|
inst.pc = decoded.pc;
|
|
if (decoded.opcode == Decoder::Opcode::ImageStore ||
|
|
decoded.opcode == Decoder::Opcode::ImageStoreMip) {
|
|
inst.op = Opcode::ImageStore;
|
|
inst.src_count = 2;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::StorageImage);
|
|
inst.memory.sampler = 0;
|
|
inst.dst.kind = OperandKind::Null;
|
|
if (!LowerSourceOperand(decoded.dst, inst.src[0], error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[1], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
inst.op = LoweredImageOpcode(decoded.opcode);
|
|
inst.src_count = 1;
|
|
inst.memory = MemoryInfoFromDecoded(decoded, ResourceKind::Image);
|
|
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
|
|
!LowerSourceOperand(decoded.src0, inst.src[0], error)) {
|
|
return false;
|
|
}
|
|
block.instructions.push_back(inst);
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
bool LowerMemoryInstruction(const Decoder::Instruction& decoded, BasicBlock& block,
|
|
std::string* error) {
|
|
switch (decoded.opcode) {
|
|
case Decoder::Opcode::SLoadDword:
|
|
case Decoder::Opcode::SLoadDwordx2:
|
|
case Decoder::Opcode::SLoadDwordx4:
|
|
case Decoder::Opcode::SLoadDwordx8:
|
|
case Decoder::Opcode::SLoadDwordx16:
|
|
return LowerScalarBufferLoadDword(decoded, block, Opcode::SLoadDword, error);
|
|
case Decoder::Opcode::SBufferLoadDword:
|
|
case Decoder::Opcode::SBufferLoadDwordx2:
|
|
case Decoder::Opcode::SBufferLoadDwordx4:
|
|
case Decoder::Opcode::SBufferLoadDwordx8:
|
|
case Decoder::Opcode::SBufferLoadDwordx16:
|
|
return LowerScalarBufferLoadDword(decoded, block, Opcode::SBufferLoadDword, error);
|
|
case Decoder::Opcode::BufferLoadUbyte:
|
|
case Decoder::Opcode::BufferLoadSbyte:
|
|
case Decoder::Opcode::BufferLoadUshort:
|
|
case Decoder::Opcode::BufferLoadSshort:
|
|
case Decoder::Opcode::BufferLoadDword:
|
|
case Decoder::Opcode::BufferLoadDwordx2:
|
|
case Decoder::Opcode::BufferLoadDwordx3:
|
|
case Decoder::Opcode::BufferLoadDwordx4:
|
|
case Decoder::Opcode::BufferLoadFormatX:
|
|
case Decoder::Opcode::BufferLoadFormatXy:
|
|
case Decoder::Opcode::BufferLoadFormatXyz:
|
|
case Decoder::Opcode::BufferLoadFormatXyzw:
|
|
case Decoder::Opcode::TBufferLoadFormatX:
|
|
case Decoder::Opcode::TBufferLoadFormatXy:
|
|
case Decoder::Opcode::TBufferLoadFormatXyz:
|
|
case Decoder::Opcode::TBufferLoadFormatXyzw: return LowerBufferLoad(decoded, block, error);
|
|
case Decoder::Opcode::BufferStoreDword:
|
|
case Decoder::Opcode::BufferStoreDwordx2:
|
|
case Decoder::Opcode::BufferStoreDwordx3:
|
|
case Decoder::Opcode::BufferStoreDwordx4:
|
|
case Decoder::Opcode::BufferStoreByte:
|
|
case Decoder::Opcode::BufferStoreShort:
|
|
case Decoder::Opcode::BufferStoreFormatX:
|
|
case Decoder::Opcode::BufferStoreFormatXy:
|
|
case Decoder::Opcode::BufferStoreFormatXyz:
|
|
case Decoder::Opcode::BufferStoreFormatXyzw:
|
|
case Decoder::Opcode::TBufferStoreFormatX:
|
|
case Decoder::Opcode::TBufferStoreFormatXy:
|
|
case Decoder::Opcode::TBufferStoreFormatXyz:
|
|
case Decoder::Opcode::TBufferStoreFormatXyzw:
|
|
return LowerBufferStore(decoded, block, error);
|
|
case Decoder::Opcode::BufferAtomicSwap:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicSwapU32, error);
|
|
case Decoder::Opcode::BufferAtomicAdd:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicAddU32, error);
|
|
case Decoder::Opcode::BufferAtomicSub:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicSubU32, error);
|
|
case Decoder::Opcode::BufferAtomicSMin:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicSMinI32, error);
|
|
case Decoder::Opcode::BufferAtomicUMin:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicUMinU32, error);
|
|
case Decoder::Opcode::BufferAtomicSMax:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicSMaxI32, error);
|
|
case Decoder::Opcode::BufferAtomicUMax:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicUMaxU32, error);
|
|
case Decoder::Opcode::BufferAtomicAnd:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicAndU32, error);
|
|
case Decoder::Opcode::BufferAtomicOr:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicOrU32, error);
|
|
case Decoder::Opcode::BufferAtomicXor:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicXorU32, error);
|
|
case Decoder::Opcode::BufferAtomicFMin:
|
|
return LowerBufferAtomicDword(decoded, block, Opcode::AtomicFMinF32, error);
|
|
case Decoder::Opcode::FlatLoadUbyte:
|
|
case Decoder::Opcode::FlatLoadSbyte:
|
|
case Decoder::Opcode::FlatLoadUshort:
|
|
case Decoder::Opcode::FlatLoadSshort:
|
|
case Decoder::Opcode::FlatLoadDword:
|
|
case Decoder::Opcode::FlatLoadDwordx2:
|
|
case Decoder::Opcode::FlatLoadDwordx3:
|
|
case Decoder::Opcode::FlatLoadDwordx4: return LowerFlatLoad(decoded, block, error);
|
|
case Decoder::Opcode::FlatStoreByte:
|
|
case Decoder::Opcode::FlatStoreShort:
|
|
case Decoder::Opcode::FlatStoreDword:
|
|
case Decoder::Opcode::FlatStoreDwordx2:
|
|
case Decoder::Opcode::FlatStoreDwordx3:
|
|
case Decoder::Opcode::FlatStoreDwordx4: return LowerFlatStore(decoded, block, error);
|
|
case Decoder::Opcode::DsAddU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicAddU32, false, error);
|
|
case Decoder::Opcode::DsAddRtnU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicAddU32, true, error);
|
|
case Decoder::Opcode::DsSubU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicSubU32, false, error);
|
|
case Decoder::Opcode::DsSubRtnU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicSubU32, true, error);
|
|
case Decoder::Opcode::DsMinI32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicSMinI32, false, error);
|
|
case Decoder::Opcode::DsMinRtnI32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicSMinI32, true, error);
|
|
case Decoder::Opcode::DsMaxI32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicSMaxI32, false, error);
|
|
case Decoder::Opcode::DsMaxRtnI32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicSMaxI32, true, error);
|
|
case Decoder::Opcode::DsMinU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicUMinU32, false, error);
|
|
case Decoder::Opcode::DsMinRtnU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicUMinU32, true, error);
|
|
case Decoder::Opcode::DsMaxU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicUMaxU32, false, error);
|
|
case Decoder::Opcode::DsMaxRtnU32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicUMaxU32, true, error);
|
|
case Decoder::Opcode::DsAndB32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicAndU32, false, error);
|
|
case Decoder::Opcode::DsAndRtnB32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicAndU32, true, error);
|
|
case Decoder::Opcode::DsOrB32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicOrU32, false, error);
|
|
case Decoder::Opcode::DsOrRtnB32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicOrU32, true, error);
|
|
case Decoder::Opcode::DsXorB32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicXorU32, false, error);
|
|
case Decoder::Opcode::DsXorRtnB32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicXorU32, true, error);
|
|
case Decoder::Opcode::DsWrxchgRtnB32:
|
|
return LowerDsAtomicU32(decoded, block, Opcode::AtomicSwapU32, true, error);
|
|
case Decoder::Opcode::DsMinF32:
|
|
return LowerDsFloatMinMaxF32(decoded, block, Opcode::DsMinF32, error);
|
|
case Decoder::Opcode::DsMaxF32:
|
|
return LowerDsFloatMinMaxF32(decoded, block, Opcode::DsMaxF32, error);
|
|
case Decoder::Opcode::DsSwizzleB32: return LowerDsSwizzleB32(decoded, block, error);
|
|
case Decoder::Opcode::DsConsume:
|
|
return LowerDsAppendConsume(decoded, block, Opcode::DsConsume, error);
|
|
case Decoder::Opcode::DsAppend:
|
|
return LowerDsAppendConsume(decoded, block, Opcode::DsAppend, error);
|
|
case Decoder::Opcode::DsWriteAddtidB32: return LowerDsWriteAddtidB32(decoded, block, error);
|
|
case Decoder::Opcode::DsReadAddtidB32: return LowerDsReadAddtidB32(decoded, block, error);
|
|
case Decoder::Opcode::DsRead2B32: return LowerDsRead2(decoded, block, 1, error);
|
|
case Decoder::Opcode::DsRead2B64:
|
|
case Decoder::Opcode::DsRead2St64B64: return LowerDsRead2(decoded, block, 2, error);
|
|
case Decoder::Opcode::DsReadSbyte:
|
|
case Decoder::Opcode::DsReadUbyte:
|
|
case Decoder::Opcode::DsReadSshort:
|
|
case Decoder::Opcode::DsReadUshort:
|
|
case Decoder::Opcode::DsReadB32:
|
|
case Decoder::Opcode::DsReadB64:
|
|
case Decoder::Opcode::DsReadB96:
|
|
case Decoder::Opcode::DsReadB128: return LowerDsRead(decoded, block, error);
|
|
case Decoder::Opcode::DsWrite2B32:
|
|
case Decoder::Opcode::DsWrite2St64B32: return LowerDsWrite2(decoded, block, 1, error);
|
|
case Decoder::Opcode::DsWrite2B64:
|
|
case Decoder::Opcode::DsWrite2St64B64: return LowerDsWrite2(decoded, block, 2, error);
|
|
case Decoder::Opcode::DsWriteByte:
|
|
case Decoder::Opcode::DsWriteShort:
|
|
case Decoder::Opcode::DsWriteB32:
|
|
case Decoder::Opcode::DsWriteB64:
|
|
case Decoder::Opcode::DsWriteB96:
|
|
case Decoder::Opcode::DsWriteB128: return LowerDsWrite(decoded, block, error);
|
|
case Decoder::Opcode::ImageGetResinfo:
|
|
case Decoder::Opcode::ImageGetLod:
|
|
case Decoder::Opcode::ImageLoad:
|
|
case Decoder::Opcode::ImageLoadMip:
|
|
case Decoder::Opcode::ImageStore:
|
|
case Decoder::Opcode::ImageStoreMip:
|
|
case Decoder::Opcode::ImageGather4Lz:
|
|
case Decoder::Opcode::ImageGather4C:
|
|
case Decoder::Opcode::ImageGather4CLz:
|
|
case Decoder::Opcode::ImageGather4LzO:
|
|
case Decoder::Opcode::ImageGather4CO:
|
|
case Decoder::Opcode::ImageGather4CLzO:
|
|
case Decoder::Opcode::ImageGather4H:
|
|
case Decoder::Opcode::ImageSample: return LowerImageOperation(decoded, block, error);
|
|
case Decoder::Opcode::ImageAtomicAdd:
|
|
case Decoder::Opcode::ImageAtomicUMin:
|
|
case Decoder::Opcode::ImageAtomicUMax:
|
|
case Decoder::Opcode::ImageAtomicAnd:
|
|
case Decoder::Opcode::ImageAtomicOr:
|
|
case Decoder::Opcode::ImageAtomicXor: return LowerImageAtomicU32(decoded, block, error);
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
bool IsMemoryOpcode(Decoder::Opcode opcode) {
|
|
switch (opcode) {
|
|
case Decoder::Opcode::SLoadDword:
|
|
case Decoder::Opcode::SLoadDwordx2:
|
|
case Decoder::Opcode::SLoadDwordx4:
|
|
case Decoder::Opcode::SLoadDwordx8:
|
|
case Decoder::Opcode::SLoadDwordx16:
|
|
case Decoder::Opcode::SBufferLoadDword:
|
|
case Decoder::Opcode::SBufferLoadDwordx2:
|
|
case Decoder::Opcode::SBufferLoadDwordx4:
|
|
case Decoder::Opcode::SBufferLoadDwordx8:
|
|
case Decoder::Opcode::SBufferLoadDwordx16:
|
|
case Decoder::Opcode::BufferLoadUbyte:
|
|
case Decoder::Opcode::BufferLoadSbyte:
|
|
case Decoder::Opcode::BufferLoadUshort:
|
|
case Decoder::Opcode::BufferLoadSshort:
|
|
case Decoder::Opcode::BufferLoadDword:
|
|
case Decoder::Opcode::BufferLoadDwordx2:
|
|
case Decoder::Opcode::BufferLoadDwordx3:
|
|
case Decoder::Opcode::BufferLoadDwordx4:
|
|
case Decoder::Opcode::BufferLoadFormatX:
|
|
case Decoder::Opcode::BufferLoadFormatXy:
|
|
case Decoder::Opcode::BufferLoadFormatXyz:
|
|
case Decoder::Opcode::BufferLoadFormatXyzw:
|
|
case Decoder::Opcode::TBufferLoadFormatX:
|
|
case Decoder::Opcode::TBufferLoadFormatXy:
|
|
case Decoder::Opcode::TBufferLoadFormatXyz:
|
|
case Decoder::Opcode::TBufferLoadFormatXyzw:
|
|
case Decoder::Opcode::BufferStoreDword:
|
|
case Decoder::Opcode::BufferStoreDwordx2:
|
|
case Decoder::Opcode::BufferStoreDwordx3:
|
|
case Decoder::Opcode::BufferStoreDwordx4:
|
|
case Decoder::Opcode::BufferStoreByte:
|
|
case Decoder::Opcode::BufferStoreShort:
|
|
case Decoder::Opcode::BufferStoreFormatX:
|
|
case Decoder::Opcode::BufferStoreFormatXy:
|
|
case Decoder::Opcode::BufferStoreFormatXyz:
|
|
case Decoder::Opcode::BufferStoreFormatXyzw:
|
|
case Decoder::Opcode::TBufferStoreFormatX:
|
|
case Decoder::Opcode::TBufferStoreFormatXy:
|
|
case Decoder::Opcode::TBufferStoreFormatXyz:
|
|
case Decoder::Opcode::TBufferStoreFormatXyzw:
|
|
case Decoder::Opcode::BufferAtomicSwap:
|
|
case Decoder::Opcode::BufferAtomicAdd:
|
|
case Decoder::Opcode::BufferAtomicSub:
|
|
case Decoder::Opcode::BufferAtomicSMin:
|
|
case Decoder::Opcode::BufferAtomicUMin:
|
|
case Decoder::Opcode::BufferAtomicSMax:
|
|
case Decoder::Opcode::BufferAtomicUMax:
|
|
case Decoder::Opcode::BufferAtomicAnd:
|
|
case Decoder::Opcode::BufferAtomicOr:
|
|
case Decoder::Opcode::BufferAtomicXor:
|
|
case Decoder::Opcode::BufferAtomicFMin:
|
|
case Decoder::Opcode::FlatLoadUbyte:
|
|
case Decoder::Opcode::FlatLoadSbyte:
|
|
case Decoder::Opcode::FlatLoadUshort:
|
|
case Decoder::Opcode::FlatLoadSshort:
|
|
case Decoder::Opcode::FlatLoadDword:
|
|
case Decoder::Opcode::FlatLoadDwordx2:
|
|
case Decoder::Opcode::FlatLoadDwordx3:
|
|
case Decoder::Opcode::FlatLoadDwordx4:
|
|
case Decoder::Opcode::FlatStoreByte:
|
|
case Decoder::Opcode::FlatStoreShort:
|
|
case Decoder::Opcode::FlatStoreDword:
|
|
case Decoder::Opcode::FlatStoreDwordx2:
|
|
case Decoder::Opcode::FlatStoreDwordx3:
|
|
case Decoder::Opcode::FlatStoreDwordx4:
|
|
case Decoder::Opcode::DsAddU32:
|
|
case Decoder::Opcode::DsAddRtnU32:
|
|
case Decoder::Opcode::DsSubU32:
|
|
case Decoder::Opcode::DsSubRtnU32:
|
|
case Decoder::Opcode::DsMinI32:
|
|
case Decoder::Opcode::DsMinRtnI32:
|
|
case Decoder::Opcode::DsMaxI32:
|
|
case Decoder::Opcode::DsMaxRtnI32:
|
|
case Decoder::Opcode::DsMinU32:
|
|
case Decoder::Opcode::DsMinRtnU32:
|
|
case Decoder::Opcode::DsMaxU32:
|
|
case Decoder::Opcode::DsMaxRtnU32:
|
|
case Decoder::Opcode::DsAndB32:
|
|
case Decoder::Opcode::DsAndRtnB32:
|
|
case Decoder::Opcode::DsOrB32:
|
|
case Decoder::Opcode::DsOrRtnB32:
|
|
case Decoder::Opcode::DsXorB32:
|
|
case Decoder::Opcode::DsXorRtnB32:
|
|
case Decoder::Opcode::DsWrxchgRtnB32:
|
|
case Decoder::Opcode::DsMinF32:
|
|
case Decoder::Opcode::DsMaxF32:
|
|
case Decoder::Opcode::DsSwizzleB32:
|
|
case Decoder::Opcode::DsConsume:
|
|
case Decoder::Opcode::DsAppend:
|
|
case Decoder::Opcode::DsReadSbyte:
|
|
case Decoder::Opcode::DsReadUbyte:
|
|
case Decoder::Opcode::DsReadSshort:
|
|
case Decoder::Opcode::DsReadUshort:
|
|
case Decoder::Opcode::DsRead2B32:
|
|
case Decoder::Opcode::DsReadB32:
|
|
case Decoder::Opcode::DsReadB64:
|
|
case Decoder::Opcode::DsRead2B64:
|
|
case Decoder::Opcode::DsRead2St64B64:
|
|
case Decoder::Opcode::DsReadB96:
|
|
case Decoder::Opcode::DsReadB128:
|
|
case Decoder::Opcode::DsWriteByte:
|
|
case Decoder::Opcode::DsWriteShort:
|
|
case Decoder::Opcode::DsWrite2B32:
|
|
case Decoder::Opcode::DsWrite2St64B32:
|
|
case Decoder::Opcode::DsWrite2B64:
|
|
case Decoder::Opcode::DsWrite2St64B64:
|
|
case Decoder::Opcode::DsWriteB32:
|
|
case Decoder::Opcode::DsWriteB64:
|
|
case Decoder::Opcode::DsWriteB96:
|
|
case Decoder::Opcode::DsWriteB128:
|
|
case Decoder::Opcode::DsWriteAddtidB32:
|
|
case Decoder::Opcode::DsReadAddtidB32:
|
|
case Decoder::Opcode::ImageGetResinfo:
|
|
case Decoder::Opcode::ImageGetLod:
|
|
case Decoder::Opcode::ImageLoad:
|
|
case Decoder::Opcode::ImageLoadMip:
|
|
case Decoder::Opcode::ImageStore:
|
|
case Decoder::Opcode::ImageStoreMip:
|
|
case Decoder::Opcode::ImageAtomicAdd:
|
|
case Decoder::Opcode::ImageAtomicUMin:
|
|
case Decoder::Opcode::ImageAtomicUMax:
|
|
case Decoder::Opcode::ImageAtomicAnd:
|
|
case Decoder::Opcode::ImageAtomicOr:
|
|
case Decoder::Opcode::ImageAtomicXor:
|
|
case Decoder::Opcode::ImageGather4Lz:
|
|
case Decoder::Opcode::ImageGather4C:
|
|
case Decoder::Opcode::ImageGather4CLz:
|
|
case Decoder::Opcode::ImageGather4LzO:
|
|
case Decoder::Opcode::ImageGather4CO:
|
|
case Decoder::Opcode::ImageGather4CLzO:
|
|
case Decoder::Opcode::ImageGather4H:
|
|
case Decoder::Opcode::ImageSample: return true;
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
} // namespace Libs::Graphics::ShaderRecompiler::IR
|