#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 #include #include 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::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::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