#include "graphics/shader/recompiler/ir/opcodes/ValueOpcodes.h" #include namespace Libs::Graphics::ShaderRecompiler::IR { namespace { struct OpcodeMeta { std::string_view name; Type type = Type::Void; std::array args = {}; size_t num_args = 0; }; template consteval OpcodeMeta MakeMeta(std::string_view name, Type type, Args... args) { static_assert(sizeof...(Args) <= 16); OpcodeMeta meta {.name = name, .type = type, .num_args = sizeof...(Args)}; meta.args.fill(Type::Void); size_t index = 0; ((meta.args[index++] = args), ...); return meta; } constexpr Type Void = Type::Void; constexpr Type Opaque = Type::Opaque; constexpr Type ScalarReg = Type::ScalarReg; constexpr Type VectorReg = Type::VectorReg; constexpr Type U1 = Type::U1; constexpr Type U8 = Type::U8; constexpr Type U16 = Type::U16; constexpr Type U32 = Type::U32; constexpr Type U64 = Type::U64; constexpr Type F16 = Type::F16; constexpr Type F32 = Type::F32; constexpr Type F64 = Type::F64; constexpr Type U32x2 = Type::U32x2; constexpr Type U32x3 = Type::U32x3; constexpr Type U32x4 = Type::U32x4; constexpr Type F32x2 = Type::F32x2; constexpr Type SrtResource = Type::SrtResource; constexpr Type BufferResource = Type::BufferResource; constexpr Type AddressResource = Type::AddressResource; constexpr Type ImageResource = Type::ImageResource; constexpr Type SamplerResource = Type::SamplerResource; constexpr Type ImageAddress = Type::ImageAddress; constexpr std::array(ValueOpcode::Count)> MetaTable = {{ #define VALUE_OPCODE(name, ...) MakeMeta(#name __VA_OPT__(, ) __VA_ARGS__), #include "graphics/shader/recompiler/ir/opcodes/ValueOpcodes.inc" #undef VALUE_OPCODE }}; } // namespace Type TypeOf(ValueOpcode opcode) { return MetaTable[static_cast(opcode)].type; } size_t NumArgsOf(ValueOpcode opcode) { return MetaTable[static_cast(opcode)].num_args; } Type ArgTypeOf(ValueOpcode opcode, size_t index) { const auto& meta = MetaTable[static_cast(opcode)]; return meta.args.at(index); } std::string_view ValueOpcodeName(ValueOpcode opcode) { return MetaTable[static_cast(opcode)].name; } bool HasSideEffects(ValueOpcode opcode) { const auto buffer_access = BufferAccessOf(opcode); if (buffer_access == BufferAccess::Write || buffer_access == BufferAccess::Atomic) { return true; } const auto shared_access = SharedAccessOf(opcode); if (shared_access == SharedAccess::Write || shared_access == SharedAccess::Atomic || shared_access == SharedAccess::Append || shared_access == SharedAccess::Consume) { return true; } if (AddressOpcodeInfoOf(opcode).access == AddressAccess::Write) { return true; } const auto image_info = ImageOpcodeInfoOf(opcode); if (image_info.access == ImageAccess::Write || image_info.access == ImageAccess::Atomic) { return true; } switch (opcode) { case ValueOpcode::Reference: case ValueOpcode::ReferenceU32: case ValueOpcode::SetAttribute: case ValueOpcode::SetTessellationAttribute: case ValueOpcode::MeshAllocate: case ValueOpcode::StoreCompletion: case ValueOpcode::Barrier: return true; default: return false; } } BufferAccess BufferAccessOf(ValueOpcode opcode) { switch (opcode) { case ValueOpcode::ReadConstBuffer: case ValueOpcode::LoadBufferU8: case ValueOpcode::LoadBufferU16: case ValueOpcode::LoadBufferU32: case ValueOpcode::LoadBufferU32x2: case ValueOpcode::LoadBufferU32x3: case ValueOpcode::LoadBufferU32x4: return BufferAccess::Read; case ValueOpcode::StoreBufferU8: case ValueOpcode::StoreBufferU16: case ValueOpcode::StoreBufferU32: case ValueOpcode::StoreBufferU32x2: case ValueOpcode::StoreBufferU32x3: case ValueOpcode::StoreBufferU32x4: return BufferAccess::Write; case ValueOpcode::BufferAtomicSwap32: case ValueOpcode::BufferAtomicCmpSwap32: case ValueOpcode::BufferAtomicSwap64: case ValueOpcode::BufferAtomicIAdd32: case ValueOpcode::BufferAtomicIAdd64: case ValueOpcode::BufferAtomicISub32: case ValueOpcode::BufferAtomicSMin32: case ValueOpcode::BufferAtomicUMin32: case ValueOpcode::BufferAtomicSMax32: case ValueOpcode::BufferAtomicUMax32: case ValueOpcode::BufferAtomicAnd32: case ValueOpcode::BufferAtomicAnd64: case ValueOpcode::BufferAtomicOr32: case ValueOpcode::BufferAtomicOr64: case ValueOpcode::BufferAtomicXor32: case ValueOpcode::BufferAtomicFMin32: case ValueOpcode::BufferAtomicFMax32: return BufferAccess::Atomic; default: return BufferAccess::None; } } uint32_t BufferComponentCount(ValueOpcode opcode) { switch (opcode) { case ValueOpcode::BufferAtomicSwap64: case ValueOpcode::BufferAtomicIAdd64: case ValueOpcode::BufferAtomicAnd64: case ValueOpcode::BufferAtomicOr64: case ValueOpcode::LoadBufferU32x2: case ValueOpcode::StoreBufferU32x2: return 2u; case ValueOpcode::LoadBufferU32x3: case ValueOpcode::StoreBufferU32x3: return 3u; case ValueOpcode::LoadBufferU32x4: case ValueOpcode::StoreBufferU32x4: return 4u; default: return BufferAccessOf(opcode) == BufferAccess::None ? 0u : 1u; } } SharedAccess SharedAccessOf(ValueOpcode opcode) { switch (opcode) { case ValueOpcode::LoadSharedU8: case ValueOpcode::LoadSharedU16: case ValueOpcode::LoadSharedU32: case ValueOpcode::LoadSharedU32x2: case ValueOpcode::LoadSharedU32x3: case ValueOpcode::LoadSharedU32x4: return SharedAccess::Read; case ValueOpcode::WriteSharedU8: case ValueOpcode::WriteSharedU16: case ValueOpcode::WriteSharedU32: case ValueOpcode::WriteSharedU32x2: case ValueOpcode::WriteSharedU32x3: case ValueOpcode::WriteSharedU32x4: return SharedAccess::Write; case ValueOpcode::SharedAtomicFMin32: case ValueOpcode::SharedAtomicFMax32: case ValueOpcode::SharedAtomicSwap32: case ValueOpcode::SharedAtomicIAdd32: case ValueOpcode::SharedAtomicIAdd64: case ValueOpcode::SharedAtomicISub32: case ValueOpcode::SharedAtomicInc32: case ValueOpcode::SharedAtomicDec32: case ValueOpcode::SharedAtomicSMin32: case ValueOpcode::SharedAtomicUMin32: case ValueOpcode::SharedAtomicSMax32: case ValueOpcode::SharedAtomicUMax32: case ValueOpcode::SharedAtomicUMax64: case ValueOpcode::SharedAtomicCmpSwap32: case ValueOpcode::SharedAtomicCmpSwap64: case ValueOpcode::SharedAtomicAnd32: case ValueOpcode::SharedAtomicOr32: case ValueOpcode::SharedAtomicOr64: case ValueOpcode::SharedAtomicXor32: case ValueOpcode::SharedAtomicMaskedOr32: return SharedAccess::Atomic; case ValueOpcode::DataAppend: return SharedAccess::Append; case ValueOpcode::DataConsume: return SharedAccess::Consume; default: return SharedAccess::None; } } uint32_t SharedComponentCount(ValueOpcode opcode) { switch (opcode) { case ValueOpcode::SharedAtomicIAdd64: case ValueOpcode::SharedAtomicOr64: case ValueOpcode::SharedAtomicUMax64: case ValueOpcode::SharedAtomicCmpSwap64: case ValueOpcode::LoadSharedU32x2: case ValueOpcode::WriteSharedU32x2: return 2u; case ValueOpcode::LoadSharedU32x3: case ValueOpcode::WriteSharedU32x3: return 3u; case ValueOpcode::LoadSharedU32x4: case ValueOpcode::WriteSharedU32x4: return 4u; default: return SharedAccessOf(opcode) == SharedAccess::None ? 0u : 1u; } } AddressOpcodeInfo AddressOpcodeInfoOf(ValueOpcode opcode) { switch (opcode) { case ValueOpcode::LoadAddressU8: return {AddressAccess::Read, 8u}; case ValueOpcode::LoadAddressU16: return {AddressAccess::Read, 16u}; case ValueOpcode::LoadAddressU32: return {AddressAccess::Read, 32u}; case ValueOpcode::StoreAddressU8: return {AddressAccess::Write, 8u}; case ValueOpcode::StoreAddressU16: return {AddressAccess::Write, 16u}; case ValueOpcode::StoreAddressU32: return {AddressAccess::Write, 32u}; default: return {}; } } ImageOpcodeInfo ImageOpcodeInfoOf(ValueOpcode opcode) { switch (opcode) { case ValueOpcode::ImageQueryDimensions: case ValueOpcode::ImageRead: return {ImageAccess::Read, ImageResourceClass::Sampled, false}; case ValueOpcode::ImageQueryLod: case ValueOpcode::ImageSampleRaw: case ValueOpcode::ImageGatherRaw: return {ImageAccess::Read, ImageResourceClass::Sampled, true}; case ValueOpcode::ImageWrite: return {ImageAccess::Write, ImageResourceClass::Storage, false}; case ValueOpcode::ImageAtomicCompareSwap32: case ValueOpcode::ImageAtomicSwap32: case ValueOpcode::ImageAtomicSwap64: case ValueOpcode::ImageAtomicIAdd32: case ValueOpcode::ImageAtomicIAdd64: case ValueOpcode::ImageAtomicSMin32: case ValueOpcode::ImageAtomicUMin32: case ValueOpcode::ImageAtomicUMin64: case ValueOpcode::ImageAtomicSMax32: case ValueOpcode::ImageAtomicUMax32: case ValueOpcode::ImageAtomicUMax64: case ValueOpcode::ImageAtomicAnd32: case ValueOpcode::ImageAtomicAnd64: case ValueOpcode::ImageAtomicOr32: case ValueOpcode::ImageAtomicOr64: case ValueOpcode::ImageAtomicXor32: case ValueOpcode::ImageAtomicXor64: case ValueOpcode::ImageAtomicFMin32: case ValueOpcode::ImageAtomicFMax32: return {ImageAccess::Atomic, ImageResourceClass::Storage, false}; default: return {}; } } } // namespace Libs::Graphics::ShaderRecompiler::IR