#include "IntermediateRepresentation/IrOpcode.hpp" #include #include namespace ShaderRecompiler { namespace { constexpr std::size_t MaxOpcodeArgs = 13; struct OpcodeMeta { std::string_view name; IrType type = IrType::Void; std::array args{}; std::size_t argCount = 0; }; template consteval OpcodeMeta makeMeta(std::string_view name, IrType type, TArgs... args) { static_assert(sizeof...(TArgs) <= MaxOpcodeArgs); OpcodeMeta meta{.name = name, .type = type, .argCount = sizeof...(TArgs)}; meta.args.fill(IrType::Void); std::size_t index = 0; ((meta.args[index++] = args), ...); return meta; } constexpr IrType Void = IrType::Void; constexpr IrType Label = IrType::Label; constexpr IrType Opaque = IrType::Opaque; constexpr IrType ScalarReg = IrType::ScalarReg; constexpr IrType VectorReg = IrType::VectorReg; constexpr IrType U1 = IrType::U1; constexpr IrType U8 = IrType::U8; constexpr IrType U16 = IrType::U16; constexpr IrType U32 = IrType::U32; constexpr IrType S32 = IrType::S32; constexpr IrType U64 = IrType::U64; constexpr IrType F16 = IrType::F16; constexpr IrType F32 = IrType::F32; constexpr IrType U32x2 = IrType::U32x2; constexpr IrType U32x3 = IrType::U32x3; constexpr IrType U32x4 = IrType::U32x4; constexpr IrType F32x2 = IrType::F32x2; constexpr IrType SrtResource = IrType::SrtResource; constexpr IrType BufferResource = IrType::BufferResource; constexpr IrType AddressResource = IrType::AddressResource; constexpr IrType ImageResource = IrType::ImageResource; constexpr IrType SamplerResource = IrType::SamplerResource; constexpr IrType ImageAddress = IrType::ImageAddress; constexpr std::array(IrOpcode::Count)> MetaTable = {{ makeMeta("Identity", Opaque, Opaque), makeMeta("Phi", Opaque), makeMeta("GetRegister", Opaque, Opaque), makeMeta("SetRegister", Void, Opaque, Opaque), makeMeta("IAdd32", U32, U32, U32), makeMeta("ISub32", U32, U32, U32), makeMeta("IMul32", U32, U32, U32), makeMeta("IDiv32", S32, S32, S32), makeMeta("IMod32", S32, S32, S32), makeMeta("IAnd32", S32, S32, S32), makeMeta("IOr32", S32, S32, S32), makeMeta("IXor32", S32, S32, S32), makeMeta("IShiftLeft32", S32, S32, S32), makeMeta("IShiftRightLogical32", S32, S32, S32), makeMeta("IShiftRightArithmetic32", S32, S32, S32), makeMeta("INegate32", S32, S32), makeMeta("INot32", S32, S32), makeMeta("FAdd32", F32, F32, F32), makeMeta("FSub32", F32, F32, F32), makeMeta("FMul32", F32, F32, F32), makeMeta("FDiv32", F32, F32, F32), makeMeta("FNegate32", F32, F32), makeMeta("FAbs32", F32, F32), makeMeta("FFma32", F32, F32, F32, F32), makeMeta("FSqrt32", F32, F32), makeMeta("FRcp32", F32, F32), makeMeta("FRsq32", F32, F32), makeMeta("FMin32", F32, F32, F32), makeMeta("FMax32", F32, F32, F32), makeMeta("FFloor32", F32, F32), makeMeta("FCeil32", F32, F32), makeMeta("FFract32", F32, F32), makeMeta("ConvertFToI32", S32, F32), makeMeta("ConvertIToF32", F32, S32), makeMeta("ConvertFToU32", U32, F32), makeMeta("ConvertUToF32", F32, U32), makeMeta("CompareEqual", U1, S32, S32), makeMeta("CompareNotEqual", U1, S32, S32), makeMeta("CompareLessThan", U1, S32, S32), makeMeta("CompareGreaterThan", U1, S32, S32), makeMeta("Select", Opaque, U1, Opaque, Opaque), makeMeta("Branch", Void, Label), makeMeta("BranchConditional", Void, U1, Label, Label), makeMeta("Loop", Void, Label), makeMeta("LoopMerge", Void, Label, Label), makeMeta("Return", Void), makeMeta("Unreachable", Void), makeMeta("LoadBuffer", U32, BufferResource, U32), makeMeta("StoreBuffer", Void, BufferResource, U32, U32), makeMeta("LoadImage", U32x4, ImageResource, ImageAddress), makeMeta("StoreImage", Void, ImageResource, ImageAddress, U32x4), makeMeta("ImageSampleImplicitLod", U32x4, ImageResource, SamplerResource, ImageAddress), makeMeta("ImageSampleExplicitLod", U32x4, ImageResource, SamplerResource, ImageAddress, F32), makeMeta("LoadShared", U32, U32), makeMeta("StoreShared", Void, U32, U32), makeMeta("Barrier", Void), makeMeta("EmitVertex", Void), makeMeta("Discard", Void), makeMeta("ReadFirstLane", U32, U32, U1), makeMeta("ReadLane", U32, U32, U32), makeMeta("Ballot", U32x4, U1), makeMeta("Void", Void), makeMeta("Reference", Void, U1), makeMeta("ReferenceU32", Void, U32), makeMeta("GetUserData", U32, ScalarReg), makeMeta("GetShaderBase", U64), makeMeta("ShaderClock", U64), makeMeta("RealtimeClock", U64), makeMeta("MeshDrawParameter", U32, U32), makeMeta("MeshArgument", U32, U32), makeMeta("MeshAllocate", Void, U32), makeMeta("TessellationBase", U32, U32), makeMeta("GetTessellationAttribute", U32, U32, U32, U1), makeMeta("SetTessellationAttribute", Void, U32, U32, U32, U1), makeMeta("GetBuiltin", U32, U32, U32), makeMeta("GetThreadBitScalarRegister", U1, ScalarReg), makeMeta("SetThreadBitScalarRegister", Void, ScalarReg, U1), makeMeta("GetScalarMaskTag", U1, ScalarReg), makeMeta("SetScalarMaskTag", Void, ScalarReg, U1), makeMeta("GetScalarRegister", U32, ScalarReg), makeMeta("SetScalarRegister", Void, ScalarReg, U32), makeMeta("GetVectorRegister", U32, VectorReg), makeMeta("SetVectorRegister", Void, VectorReg, U32), makeMeta("GetGotoVariable", U1, U32), makeMeta("SetGotoVariable", Void, U32, U1), makeMeta("GetScc", U1), makeMeta("SetScc", Void, U1), makeMeta("GetExec", U1), makeMeta("SetExec", Void, U1), makeMeta("GetExecLo", U32), makeMeta("SetExecLo", Void, U32), makeMeta("GetExecHi", U32), makeMeta("SetExecHi", Void, U32), makeMeta("GetVcc", U1), makeMeta("SetVcc", Void, U1), makeMeta("GetVccLo", U32), makeMeta("SetVccLo", Void, U32), makeMeta("GetVccHi", U32), makeMeta("SetVccHi", Void, U32), makeMeta("GetM0", U32), makeMeta("SetM0", Void, U32), makeMeta("UndefU1", U1), makeMeta("UndefU8", U8), makeMeta("UndefU16", U16), makeMeta("UndefU32", U32), makeMeta("UndefU64", U64), makeMeta("BitCastU16F16", U16, F16), makeMeta("BitCastF16U16", F16, U16), makeMeta("BitCastU32F32", U32, F32), makeMeta("BitCastF32U32", F32, U32), makeMeta("ConvertU16U32", U16, U32), makeMeta("ConvertU32U16", U32, U16), makeMeta("ConvertU8U32", U8, U32), makeMeta("ConvertU32U8", U32, U8), makeMeta("ConvertF32F16", F32, F16), makeMeta("ConvertF16F32", F16, F32), makeMeta("ConvertS32F32", U32, F32), makeMeta("ConvertU32F32", U32, F32), makeMeta("ConvertF32S32", F32, U32), makeMeta("ConvertF32U32", F32, U32), makeMeta("CompositeConstructU64", U64, U32, U32), makeMeta("CompositeConstructU32x2", U32x2, U32, U32), makeMeta("CompositeConstructU32x3", U32x3, U32, U32, U32), makeMeta("CompositeConstructF32x2", F32x2, F32, F32), makeMeta("CompositeConstructU32x4", U32x4, U32, U32, U32, U32), makeMeta("CompositeExtractU64", U32, U64, U32), makeMeta("CompositeExtractU32x2", U32, U32x2, U32), makeMeta("CompositeExtractU32x3", U32, U32x3, U32), makeMeta("CompositeExtractU32x4", U32, U32x4, U32), makeMeta("PackHalf2x16", U32, F32x2), makeMeta("PackFloat2x16Rtz", U32, F32, F32), makeMeta("FPAbs32", F32, F32), makeMeta("FPNeg32", F32, F32), makeMeta("FPSaturate32", F32, F32), makeMeta("BitFieldInsert", U32, U32, U32, U32, U32), makeMeta("BitFieldUExtract", U32, U32, U32, U32), makeMeta("BitFieldSExtract", U32, U32, U32, U32), makeMeta("DppMoveU32", U32, U32, U1), makeMeta("DppUpdateU32", U32, U32, U32, U1), makeMeta("WqmU64", U64, U64), makeMeta("SelectU1", U1, U1, U1, U1), makeMeta("SelectF32", F32, U1, F32, F32), makeMeta("IAdd64", U64, U64, U64), makeMeta("IAddCarry32", U32x2, U32, U32), makeMeta("ISub64", U64, U64, U64), makeMeta("IMul64", U64, U64, U64), makeMeta("UDiv32", U32, U32, U32), makeMeta("SMulHi", U32, U32, U32), makeMeta("UMulHi", U32, U32, U32), makeMeta("IAbs32", U32, U32), makeMeta("ShiftLeftLogical32", U32, U32, U32), makeMeta("ShiftLeftLogical64", U64, U64, U32), makeMeta("ShiftRightLogical32", U32, U32, U32), makeMeta("ShiftRightLogical64", U64, U64, U32), makeMeta("ShiftRightArithmetic32", U32, U32, U32), makeMeta("ShiftRightArithmetic64", U64, U64, U32), makeMeta("BitwiseAnd32", U32, U32, U32), makeMeta("BitwiseAnd64", U64, U64, U64), makeMeta("BitwiseOr32", U32, U32, U32), makeMeta("BitwiseXor32", U32, U32, U32), makeMeta("BitwiseNot32", U32, U32), makeMeta("BitReverse32", U32, U32), makeMeta("BitCount32", U32, U32), makeMeta("BitCount64", U32, U64), makeMeta("FindUMsb32", U32, U32), makeMeta("FindUMsb64", U32, U64), makeMeta("FindILsb32", U32, U32), makeMeta("SMin32", U32, U32, U32), makeMeta("UMin32", U32, U32, U32), makeMeta("SMax32", U32, U32, U32), makeMeta("UMax32", U32, U32, U32), makeMeta("SMinTri32", U32, U32, U32, U32), makeMeta("UMinTri32", U32, U32, U32, U32), makeMeta("SMaxTri32", U32, U32, U32, U32), makeMeta("UMaxTri32", U32, U32, U32, U32), makeMeta("SMedTri32", U32, U32, U32, U32), makeMeta("UMedTri32", U32, U32, U32, U32), makeMeta("SLessThan32", U1, U32, U32), makeMeta("SLessThan64", U1, U64, U64), makeMeta("ULessThan32", U1, U32, U32), makeMeta("ULessThan64", U1, U64, U64), makeMeta("IEqual32", U1, U32, U32), makeMeta("IEqual64", U1, U64, U64), makeMeta("SLessThanEqual32", U1, U32, U32), makeMeta("ULessThanEqual32", U1, U32, U32), makeMeta("SGreaterThan32", U1, U32, U32), makeMeta("UGreaterThan32", U1, U32, U32), makeMeta("UGreaterThan64", U1, U64, U64), makeMeta("INotEqual32", U1, U32, U32), makeMeta("INotEqual64", U1, U64, U64), makeMeta("SGreaterThanEqual32", U1, U32, U32), makeMeta("UGreaterThanEqual32", U1, U32, U32), makeMeta("LogicalOr", U1, U1, U1), makeMeta("LogicalAnd", U1, U1, U1), makeMeta("LogicalXor", U1, U1, U1), makeMeta("LogicalNot", U1, U1), makeMeta("FPOrdEqual32", U1, F32, F32), makeMeta("FPUnordEqual32", U1, F32, F32), makeMeta("FPOrdNotEqual32", U1, F32, F32), makeMeta("FPUnordNotEqual32", U1, F32, F32), makeMeta("FPOrdLessThan32", U1, F32, F32), makeMeta("FPUnordLessThan32", U1, F32, F32), makeMeta("FPOrdGreaterThan32", U1, F32, F32), makeMeta("FPUnordGreaterThan32", U1, F32, F32), makeMeta("FPOrdLessThanEqual32", U1, F32, F32), makeMeta("FPUnordLessThanEqual32", U1, F32, F32), makeMeta("FPOrdGreaterThanEqual32", U1, F32, F32), makeMeta("FPUnordGreaterThanEqual32", U1, F32, F32), makeMeta("FPIsNan32", U1, F32), makeMeta("FPCmpClass32", U1, F32, U32), makeMeta("FPAdd32", F32, F32, F32), makeMeta("FPSub32", F32, F32, F32), makeMeta("FPFma32", F32, F32, F32, F32), makeMeta("FPMad32", F32, F32, F32, F32), makeMeta("FPMul32", F32, F32, F32), makeMeta("FPMin32", F32, F32, F32), makeMeta("FPMax32", F32, F32, F32), makeMeta("FPMinTri32", F32, F32, F32, F32), makeMeta("FPMaxTri32", F32, F32, F32, F32), makeMeta("FPMedTri32", F32, F32, F32, F32), makeMeta("FPRecip32", F32, F32), makeMeta("FPRecipIFlag32", F32, F32), makeMeta("FPRecipSqrt32", F32, F32), makeMeta("FPSqrt", F32, F32), makeMeta("FPSin", F32, F32), makeMeta("FPCos", F32, F32), makeMeta("FPExp2", F32, F32), makeMeta("FPLog2", F32, F32), makeMeta("FPRoundEven32", F32, F32), makeMeta("FPFloor32", F32, F32), makeMeta("FPCeil32", F32, F32), makeMeta("FPTrunc32", F32, F32), makeMeta("FPFract32", F32, F32), makeMeta("FPAdd64", U64, U64, U64), makeMeta("FPMul64", U64, U64, U64), makeMeta("FPFma64", U64, U64, U64, U64), makeMeta("FPFmaScale64", U64, U64, U64, U64, U32), makeMeta("FPMin64", U64, U64, U64), makeMeta("FPMax64", U64, U64, U64), makeMeta("FPSaturate64", U64, U64), makeMeta("FPLdexp64", U64, U64, U32), makeMeta("FPRoundEven64", U64, U64), makeMeta("FPFloor64", U64, U64), makeMeta("FPCeil64", U64, U64), makeMeta("FPTrunc64", U64, U64), makeMeta("FPFract64", U64, U64), makeMeta("FPFrexpMant64", U64, U64), makeMeta("FPFrexpExp64", U32, U64), makeMeta("FPRcp64", U64, U64), makeMeta("FPRsq64", U64, U64), makeMeta("FPSqrt64", U64, U64), makeMeta("FPTrigPreop64", U64, U64, U32), makeMeta("FPDot2F32F16", U32, U32, U32, U32), makeMeta("ConvertF32F64", F32, U64), makeMeta("ConvertF64F32", U64, F32), makeMeta("ConvertF64S32", U64, U32), makeMeta("ConvertF64U32", U64, U32), makeMeta("ConvertS32F64", U32, U64), makeMeta("ConvertU32F64", U32, U64), makeMeta("LaneId", U32), makeMeta("WriteLane", U32, U32, U32, U32), makeMeta("Permlane16U32", U32, U32, U32, U32, U1, U32), makeMeta("BpermuteU32", U32, U32, U32, U1), makeMeta("PermuteU32", U32, U32, U32, U1), makeMeta("GetSrtResource", SrtResource), makeMeta("GetBufferResource", BufferResource, U32, U32, U32, U32), makeMeta("GetAddressResource", AddressResource, U32, U32), makeMeta("GetScratchResource", AddressResource), makeMeta("GetImageResource", ImageResource, U32, U32, U32, U32, U32, U32, U32, U32), makeMeta("GetSamplerResource", SamplerResource, U32, U32, U32, U32), makeMeta("MakeImageAddress", ImageAddress, U32, U32, U32, U32, U32, U32, U32, U32, U32, U32, U32, U32, U32), makeMeta("ReadConst", U32, SrtResource, U32), makeMeta("ReadConstBuffer", U32, BufferResource, U32), makeMeta("LoadAddressU8", U8, AddressResource, U32, U32, U1), makeMeta("LoadAddressU16", U16, AddressResource, U32, U32, U1), makeMeta("LoadAddressU32", U32, AddressResource, U32, U32, U1), makeMeta("LoadAddressU32x2", U32x2, AddressResource, U32, U32, U1), makeMeta("LoadAddressU32x3", U32x3, AddressResource, U32, U32, U1), makeMeta("LoadAddressU32x4", U32x4, AddressResource, U32, U32, U1), makeMeta("StoreAddressU8", Void, AddressResource, U32, U32, U8, U1), makeMeta("StoreAddressU16", Void, AddressResource, U32, U32, U16, U1), makeMeta("StoreAddressU32", Void, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicSwap32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicCmpSwap32", U32, AddressResource, U32, U32, U32, U32, U1), makeMeta("AddressAtomicIAdd32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicISub32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicSMin32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicUMin32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicSMax32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicUMax32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicAnd32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicOr32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicXor32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicInc32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicDec32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicUSubSat32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicSwap64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicCmpSwap64", U64, AddressResource, U32, U32, U64, U64, U1), makeMeta("AddressAtomicIAdd64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicISub64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicSMin64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicUMin64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicSMax64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicUMax64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicAnd64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicOr64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicXor64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicFCmpSwap32", U32, AddressResource, U32, U32, U32, U32, U1), makeMeta("AddressAtomicFMin32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicFMax32", U32, AddressResource, U32, U32, U32, U1), makeMeta("AddressAtomicFCmpSwap64", U64, AddressResource, U32, U32, U64, U64, U1), makeMeta("AddressAtomicFMin64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicFMax64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicInc64", U64, AddressResource, U32, U32, U64, U1), makeMeta("AddressAtomicDec64", U64, AddressResource, U32, U32, U64, U1), makeMeta("LoadBufferU8", U8, BufferResource, U32, U32, U32, U1), makeMeta("LoadBufferU16", U16, BufferResource, U32, U32, U32, U1), makeMeta("LoadBufferU32", U32, BufferResource, U32, U32, U32, U1), makeMeta("LoadBufferU32x2", U32x2, BufferResource, U32, U32, U32, U1), makeMeta("LoadBufferU32x3", U32x3, BufferResource, U32, U32, U32, U1), makeMeta("LoadBufferU32x4", U32x4, BufferResource, U32, U32, U32, U1), makeMeta("StoreBufferU8", Void, BufferResource, U32, U32, U32, U8, U1), makeMeta("StoreBufferU16", Void, BufferResource, U32, U32, U32, U16, U1), makeMeta("StoreBufferU32", Void, BufferResource, U32, U32, U32, U32, U1), makeMeta("StoreBufferU32x2", Void, BufferResource, U32, U32, U32, U32x2, U1), makeMeta("StoreBufferU32x3", Void, BufferResource, U32, U32, U32, U32x3, U1), makeMeta("StoreBufferU32x4", Void, BufferResource, U32, U32, U32, U32x4, U1), makeMeta("BufferAtomicSwap32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicCmpSwap32", U32, BufferResource, U32, U32, U32, U32, U32, U1), makeMeta("BufferAtomicSwap64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicIAdd32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicISub32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicSMin32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicUMin32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicSMax32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicUMax32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicAnd32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicOr32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicOr64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicXor32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicFMin32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicFMax32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicInc32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicDec32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicUSubSat32", U32, BufferResource, U32, U32, U32, U32, U1), makeMeta("BufferAtomicIAdd64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicISub64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicSMin64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicUMin64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicSMax64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicUMax64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicAnd64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicXor64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicCmpSwap64", U64, BufferResource, U32, U32, U32, U64, U64, U1), makeMeta("BufferAtomicFCmpSwap32", U32, BufferResource, U32, U32, U32, U32, U32, U1), makeMeta("BufferAtomicFCmpSwap64", U64, BufferResource, U32, U32, U32, U64, U64, U1), makeMeta("BufferAtomicFMin64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicFMax64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicInc64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("BufferAtomicDec64", U64, BufferResource, U32, U32, U32, U64, U1), makeMeta("LoadSharedU8", U8, U32, U1), makeMeta("LoadSharedU16", U16, U32, U1), makeMeta("LoadSharedU32", U32, U32, U1), makeMeta("LoadSharedU32x2", U32x2, U32, U1), makeMeta("LoadSharedU32x3", U32x3, U32, U1), makeMeta("LoadSharedU32x4", U32x4, U32, U1), makeMeta("WriteSharedU8", Void, U32, U8, U1), makeMeta("WriteSharedU16", Void, U32, U16, U1), makeMeta("WriteSharedU32", Void, U32, U32, U1), makeMeta("WriteSharedU32x2", Void, U32, U32, U32, U1), makeMeta("WriteSharedU32x3", Void, U32, U32, U32, U32, U1), makeMeta("WriteSharedU32x4", Void, U32, U32, U32, U32, U32, U1), makeMeta("SharedAtomicFMin32", U32, U32, U32, U1), makeMeta("SharedAtomicFMax32", U32, U32, U32, U1), makeMeta("SharedAtomicSwap32", U32, U32, U32, U1), makeMeta("SharedAtomicIAdd32", U32, U32, U32, U1), makeMeta("SharedAtomicISub32", U32, U32, U32, U1), makeMeta("SharedAtomicInc32", U32, U32, U32, U1), makeMeta("SharedAtomicDec32", U32, U32, U32, U1), makeMeta("SharedAtomicSMin32", U32, U32, U32, U1), makeMeta("SharedAtomicUMin32", U32, U32, U32, U1), makeMeta("SharedAtomicSMax32", U32, U32, U32, U1), makeMeta("SharedAtomicUMax32", U32, U32, U32, U1), makeMeta("SharedAtomicAnd32", U32, U32, U32, U1), makeMeta("SharedAtomicOr32", U32, U32, U32, U1), makeMeta("SharedAtomicXor32", U32, U32, U32, U1), makeMeta("SharedAtomicRsub32", U32, U32, U32, U1), makeMeta("SharedAtomicFAdd32", U32, U32, U32, U1), makeMeta("SharedAtomicCmpst32", U32, U32, U32, U32, U1), makeMeta("SharedAtomicCmpstF32", U32, U32, U32, U32, U1), makeMeta("SharedAtomicMskor32", U32, U32, U32, U32, U1), makeMeta("SharedAtomicWrap32", U32, U32, U32, U32, U1), makeMeta("SharedAtomicSwap64", U64, U32, U64, U1), makeMeta("SharedAtomicIAdd64", U64, U32, U64, U1), makeMeta("SharedAtomicISub64", U64, U32, U64, U1), makeMeta("SharedAtomicRsub64", U64, U32, U64, U1), makeMeta("SharedAtomicInc64", U64, U32, U64, U1), makeMeta("SharedAtomicDec64", U64, U32, U64, U1), makeMeta("SharedAtomicSMin64", U64, U32, U64, U1), makeMeta("SharedAtomicUMin64", U64, U32, U64, U1), makeMeta("SharedAtomicSMax64", U64, U32, U64, U1), makeMeta("SharedAtomicUMax64", U64, U32, U64, U1), makeMeta("SharedAtomicAnd64", U64, U32, U64, U1), makeMeta("SharedAtomicOr64", U64, U32, U64, U1), makeMeta("SharedAtomicXor64", U64, U32, U64, U1), makeMeta("SharedAtomicFMin64", U64, U32, U64, U1), makeMeta("SharedAtomicFMax64", U64, U32, U64, U1), makeMeta("SharedAtomicCmpst64", U64, U32, U64, U64, U1), makeMeta("SharedAtomicCmpstF64", U64, U32, U64, U64, U1), makeMeta("SharedAtomicMskor64", U64, U32, U64, U64, U1), makeMeta("DataAppend", U32, U32, U1, U32, U32), makeMeta("DataConsume", U32, U32, U1, U32, U32), makeMeta("SwizzleU32", U32, U32, U32, U1), makeMeta("ImageQueryDimensions", U32x4, ImageResource, ImageAddress), makeMeta("ImageQueryLod", U32x4, ImageResource, SamplerResource, ImageAddress), makeMeta("ImageRead", U32x4, ImageResource, ImageAddress, U1), makeMeta("ImageWrite", Void, ImageResource, ImageAddress, U32x4, U1), makeMeta("ImageSampleRaw", U32x4, ImageResource, SamplerResource, ImageAddress), makeMeta("ImageGatherRaw", U32x4, ImageResource, SamplerResource, ImageAddress), makeMeta("ImageAtomicSwap32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicIAdd32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicUMin32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicUMax32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicAnd32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicOr32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicXor32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicCmpSwap32", U32, ImageResource, ImageAddress, U32, U32, U1), makeMeta("ImageAtomicISub32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicSMin32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicSMax32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicInc32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicDec32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicFCmpSwap32", U32, ImageResource, ImageAddress, U32, U32, U1), makeMeta("ImageAtomicFMin32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicFMax32", U32, ImageResource, ImageAddress, U32, U1), makeMeta("ImageAtomicSwap64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicIAdd64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicISub64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicUMin64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicUMax64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicSMin64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicSMax64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicAnd64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicOr64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicXor64", U64, ImageResource, ImageAddress, U64, U1), makeMeta("ImageAtomicCmpSwap64", U64, ImageResource, ImageAddress, U64, U64, U1), makeMeta("GetAttribute", U32, U32, U32), makeMeta("GetInterpolationParameter", U32, U32, U32, U32), makeMeta("GetInterpolationParameterF16", F32, U32, U32, U32, U32), makeMeta("SetAttribute", Void, U32x4, U1), makeMeta("ControlNop", Void), makeMeta("Waitcnt", Void), makeMeta("Sendmsg", Void), makeMeta("TtraceData", Void), makeMeta("InstPrefetch", Void), makeMeta("SelectU32", U32, U1, U32, U32), makeMeta("ImageBvhIntersectRay", U32x4, U32x4, ImageAddress, U1), }}; const OpcodeMeta& metaOf(IrOpcode opcode) { const std::size_t index = static_cast(opcode); if (index >= MetaTable.size()) { throw std::out_of_range("IrOpcode value is out of the known opcode range"); } return MetaTable[index]; } } std::size_t IrOpcodeOperandCount(IrOpcode opcode) { return metaOf(opcode).argCount; } IrType IrOpcodeType(IrOpcode opcode) { return metaOf(opcode).type; } IrType IrOpcodeArgumentType(IrOpcode opcode, std::size_t index) { const OpcodeMeta& meta = metaOf(opcode); if (index >= meta.argCount) { throw std::out_of_range("IrOpcode argument index is out of range for this opcode"); } return meta.args[index]; } BufferAccess BufferAccessOf(IrOpcode opcode) { switch (opcode) { case IrOpcode::LoadBuffer: case IrOpcode::ReadConstBuffer: case IrOpcode::LoadBufferU8: case IrOpcode::LoadBufferU16: case IrOpcode::LoadBufferU32: case IrOpcode::LoadBufferU32x2: case IrOpcode::LoadBufferU32x3: case IrOpcode::LoadBufferU32x4: return BufferAccess::Read; case IrOpcode::StoreBuffer: case IrOpcode::StoreBufferU8: case IrOpcode::StoreBufferU16: case IrOpcode::StoreBufferU32: case IrOpcode::StoreBufferU32x2: case IrOpcode::StoreBufferU32x3: case IrOpcode::StoreBufferU32x4: return BufferAccess::Write; case IrOpcode::BufferAtomicSwap32: case IrOpcode::BufferAtomicCmpSwap32: case IrOpcode::BufferAtomicSwap64: case IrOpcode::BufferAtomicIAdd32: case IrOpcode::BufferAtomicISub32: case IrOpcode::BufferAtomicSMin32: case IrOpcode::BufferAtomicUMin32: case IrOpcode::BufferAtomicSMax32: case IrOpcode::BufferAtomicUMax32: case IrOpcode::BufferAtomicAnd32: case IrOpcode::BufferAtomicOr32: case IrOpcode::BufferAtomicOr64: case IrOpcode::BufferAtomicXor32: case IrOpcode::BufferAtomicFMin32: case IrOpcode::BufferAtomicFMax32: case IrOpcode::BufferAtomicInc32: case IrOpcode::BufferAtomicDec32: case IrOpcode::BufferAtomicUSubSat32: case IrOpcode::BufferAtomicIAdd64: case IrOpcode::BufferAtomicISub64: case IrOpcode::BufferAtomicSMin64: case IrOpcode::BufferAtomicUMin64: case IrOpcode::BufferAtomicSMax64: case IrOpcode::BufferAtomicUMax64: case IrOpcode::BufferAtomicAnd64: case IrOpcode::BufferAtomicXor64: case IrOpcode::BufferAtomicCmpSwap64: case IrOpcode::BufferAtomicFCmpSwap32: case IrOpcode::BufferAtomicFCmpSwap64: case IrOpcode::BufferAtomicFMin64: case IrOpcode::BufferAtomicFMax64: case IrOpcode::BufferAtomicInc64: case IrOpcode::BufferAtomicDec64: return BufferAccess::Atomic; default: return BufferAccess::None; } } std::uint32_t BufferComponentCount(IrOpcode opcode) { switch (opcode) { case IrOpcode::BufferAtomicSwap64: case IrOpcode::BufferAtomicOr64: case IrOpcode::BufferAtomicIAdd64: case IrOpcode::BufferAtomicISub64: case IrOpcode::BufferAtomicSMin64: case IrOpcode::BufferAtomicUMin64: case IrOpcode::BufferAtomicSMax64: case IrOpcode::BufferAtomicUMax64: case IrOpcode::BufferAtomicAnd64: case IrOpcode::BufferAtomicXor64: case IrOpcode::BufferAtomicCmpSwap64: case IrOpcode::BufferAtomicFCmpSwap64: case IrOpcode::BufferAtomicFMin64: case IrOpcode::BufferAtomicFMax64: case IrOpcode::BufferAtomicInc64: case IrOpcode::BufferAtomicDec64: case IrOpcode::LoadBufferU32x2: case IrOpcode::StoreBufferU32x2: return 2u; case IrOpcode::LoadBufferU32x3: case IrOpcode::StoreBufferU32x3: return 3u; case IrOpcode::LoadBufferU32x4: case IrOpcode::StoreBufferU32x4: return 4u; default: return BufferAccessOf(opcode) == BufferAccess::None ? 0u : 1u; } } SharedAccess SharedAccessOf(IrOpcode opcode) { switch (opcode) { case IrOpcode::LoadShared: case IrOpcode::LoadSharedU8: case IrOpcode::LoadSharedU16: case IrOpcode::LoadSharedU32: case IrOpcode::LoadSharedU32x2: case IrOpcode::LoadSharedU32x3: case IrOpcode::LoadSharedU32x4: return SharedAccess::Read; case IrOpcode::StoreShared: case IrOpcode::WriteSharedU8: case IrOpcode::WriteSharedU16: case IrOpcode::WriteSharedU32: case IrOpcode::WriteSharedU32x2: case IrOpcode::WriteSharedU32x3: case IrOpcode::WriteSharedU32x4: return SharedAccess::Write; case IrOpcode::SharedAtomicFMin32: case IrOpcode::SharedAtomicFMax32: case IrOpcode::SharedAtomicSwap32: case IrOpcode::SharedAtomicIAdd32: case IrOpcode::SharedAtomicISub32: case IrOpcode::SharedAtomicInc32: case IrOpcode::SharedAtomicDec32: case IrOpcode::SharedAtomicSMin32: case IrOpcode::SharedAtomicUMin32: case IrOpcode::SharedAtomicSMax32: case IrOpcode::SharedAtomicUMax32: case IrOpcode::SharedAtomicAnd32: case IrOpcode::SharedAtomicOr32: case IrOpcode::SharedAtomicXor32: case IrOpcode::SharedAtomicRsub32: case IrOpcode::SharedAtomicFAdd32: case IrOpcode::SharedAtomicCmpst32: case IrOpcode::SharedAtomicCmpstF32: case IrOpcode::SharedAtomicMskor32: case IrOpcode::SharedAtomicWrap32: case IrOpcode::SharedAtomicSwap64: case IrOpcode::SharedAtomicIAdd64: case IrOpcode::SharedAtomicISub64: case IrOpcode::SharedAtomicRsub64: case IrOpcode::SharedAtomicInc64: case IrOpcode::SharedAtomicDec64: case IrOpcode::SharedAtomicSMin64: case IrOpcode::SharedAtomicUMin64: case IrOpcode::SharedAtomicSMax64: case IrOpcode::SharedAtomicUMax64: case IrOpcode::SharedAtomicAnd64: case IrOpcode::SharedAtomicOr64: case IrOpcode::SharedAtomicXor64: case IrOpcode::SharedAtomicFMin64: case IrOpcode::SharedAtomicFMax64: case IrOpcode::SharedAtomicCmpst64: case IrOpcode::SharedAtomicCmpstF64: case IrOpcode::SharedAtomicMskor64: return SharedAccess::Atomic; case IrOpcode::DataAppend: return SharedAccess::Append; case IrOpcode::DataConsume: return SharedAccess::Consume; default: return SharedAccess::None; } } std::uint32_t SharedComponentCount(IrOpcode opcode) { switch (opcode) { case IrOpcode::LoadSharedU32x2: case IrOpcode::WriteSharedU32x2: case IrOpcode::SharedAtomicSwap64: case IrOpcode::SharedAtomicIAdd64: case IrOpcode::SharedAtomicISub64: case IrOpcode::SharedAtomicRsub64: case IrOpcode::SharedAtomicInc64: case IrOpcode::SharedAtomicDec64: case IrOpcode::SharedAtomicSMin64: case IrOpcode::SharedAtomicUMin64: case IrOpcode::SharedAtomicSMax64: case IrOpcode::SharedAtomicUMax64: case IrOpcode::SharedAtomicAnd64: case IrOpcode::SharedAtomicOr64: case IrOpcode::SharedAtomicXor64: case IrOpcode::SharedAtomicFMin64: case IrOpcode::SharedAtomicFMax64: case IrOpcode::SharedAtomicCmpst64: case IrOpcode::SharedAtomicCmpstF64: case IrOpcode::SharedAtomicMskor64: return 2u; case IrOpcode::LoadSharedU32x3: case IrOpcode::WriteSharedU32x3: return 3u; case IrOpcode::LoadSharedU32x4: case IrOpcode::WriteSharedU32x4: return 4u; default: return SharedAccessOf(opcode) == SharedAccess::None ? 0u : 1u; } } AddressOpcodeInfo AddressOpcodeInfoOf(IrOpcode opcode) { switch (opcode) { case IrOpcode::LoadAddressU8: return {AddressAccess::Read, 8u}; case IrOpcode::LoadAddressU16: return {AddressAccess::Read, 16u}; case IrOpcode::LoadAddressU32: return {AddressAccess::Read, 32u}; case IrOpcode::LoadAddressU32x2: return {AddressAccess::Read, 32u, 2u}; case IrOpcode::LoadAddressU32x3: return {AddressAccess::Read, 32u, 3u}; case IrOpcode::LoadAddressU32x4: return {AddressAccess::Read, 32u, 4u}; case IrOpcode::StoreAddressU8: return {AddressAccess::Write, 8u}; case IrOpcode::StoreAddressU16: return {AddressAccess::Write, 16u}; case IrOpcode::StoreAddressU32: return {AddressAccess::Write, 32u}; case IrOpcode::AddressAtomicSwap32: case IrOpcode::AddressAtomicCmpSwap32: case IrOpcode::AddressAtomicIAdd32: case IrOpcode::AddressAtomicISub32: case IrOpcode::AddressAtomicSMin32: case IrOpcode::AddressAtomicUMin32: case IrOpcode::AddressAtomicSMax32: case IrOpcode::AddressAtomicUMax32: case IrOpcode::AddressAtomicAnd32: case IrOpcode::AddressAtomicOr32: case IrOpcode::AddressAtomicXor32: case IrOpcode::AddressAtomicInc32: case IrOpcode::AddressAtomicDec32: case IrOpcode::AddressAtomicUSubSat32: case IrOpcode::AddressAtomicFCmpSwap32: case IrOpcode::AddressAtomicFMin32: case IrOpcode::AddressAtomicFMax32: return {AddressAccess::Atomic, 32u}; case IrOpcode::AddressAtomicSwap64: case IrOpcode::AddressAtomicCmpSwap64: case IrOpcode::AddressAtomicIAdd64: case IrOpcode::AddressAtomicISub64: case IrOpcode::AddressAtomicSMin64: case IrOpcode::AddressAtomicUMin64: case IrOpcode::AddressAtomicSMax64: case IrOpcode::AddressAtomicUMax64: case IrOpcode::AddressAtomicAnd64: case IrOpcode::AddressAtomicOr64: case IrOpcode::AddressAtomicXor64: case IrOpcode::AddressAtomicFCmpSwap64: case IrOpcode::AddressAtomicFMin64: case IrOpcode::AddressAtomicFMax64: case IrOpcode::AddressAtomicInc64: case IrOpcode::AddressAtomicDec64: return {AddressAccess::Atomic, 32u, 2u}; default: return {}; } } ImageOpcodeInfo ImageOpcodeInfoOf(IrOpcode opcode) { switch (opcode) { case IrOpcode::ImageQueryDimensions: case IrOpcode::ImageRead: case IrOpcode::LoadImage: return {ImageAccess::Read, ImageResourceClass::Sampled, false}; case IrOpcode::ImageQueryLod: case IrOpcode::ImageSampleRaw: case IrOpcode::ImageGatherRaw: case IrOpcode::ImageSampleImplicitLod: case IrOpcode::ImageSampleExplicitLod: return {ImageAccess::Read, ImageResourceClass::Sampled, true}; case IrOpcode::ImageWrite: case IrOpcode::StoreImage: return {ImageAccess::Write, ImageResourceClass::Storage, false}; case IrOpcode::ImageAtomicSwap32: case IrOpcode::ImageAtomicIAdd32: case IrOpcode::ImageAtomicUMin32: case IrOpcode::ImageAtomicUMax32: case IrOpcode::ImageAtomicAnd32: case IrOpcode::ImageAtomicOr32: case IrOpcode::ImageAtomicXor32: case IrOpcode::ImageAtomicCmpSwap32: case IrOpcode::ImageAtomicISub32: case IrOpcode::ImageAtomicSMin32: case IrOpcode::ImageAtomicSMax32: case IrOpcode::ImageAtomicInc32: case IrOpcode::ImageAtomicDec32: case IrOpcode::ImageAtomicFCmpSwap32: case IrOpcode::ImageAtomicFMin32: case IrOpcode::ImageAtomicFMax32: case IrOpcode::ImageAtomicSwap64: case IrOpcode::ImageAtomicIAdd64: case IrOpcode::ImageAtomicISub64: case IrOpcode::ImageAtomicUMin64: case IrOpcode::ImageAtomicUMax64: case IrOpcode::ImageAtomicSMin64: case IrOpcode::ImageAtomicSMax64: case IrOpcode::ImageAtomicAnd64: case IrOpcode::ImageAtomicOr64: case IrOpcode::ImageAtomicXor64: case IrOpcode::ImageAtomicCmpSwap64: return {ImageAccess::Atomic, ImageResourceClass::Storage, false}; default: return {}; } } bool IsImageAtomic64Opcode(IrOpcode opcode) { return opcode >= IrOpcode::ImageAtomicSwap64 && opcode <= IrOpcode::ImageAtomicCmpSwap64; } bool IsFloat64Opcode(IrOpcode opcode) { return opcode >= IrOpcode::FPAdd64 && opcode <= IrOpcode::ConvertU32F64; } bool IrOpcodeHasSideEffects(IrOpcode opcode) { const BufferAccess bufferAccess = BufferAccessOf(opcode); if (bufferAccess == BufferAccess::Write || bufferAccess == BufferAccess::Atomic) { return true; } const SharedAccess sharedAccess = SharedAccessOf(opcode); if (sharedAccess == SharedAccess::Write || sharedAccess == SharedAccess::Atomic || sharedAccess == SharedAccess::Append || sharedAccess == SharedAccess::Consume) { return true; } const AddressAccess addressAccess = AddressOpcodeInfoOf(opcode).access; if (addressAccess == AddressAccess::Write || addressAccess == AddressAccess::Atomic) { return true; } const ImageAccess imageAccess = ImageOpcodeInfoOf(opcode).access; if (imageAccess == ImageAccess::Write || imageAccess == ImageAccess::Atomic) { return true; } switch (opcode) { case IrOpcode::SetRegister: case IrOpcode::Branch: case IrOpcode::BranchConditional: case IrOpcode::Loop: case IrOpcode::LoopMerge: case IrOpcode::Return: case IrOpcode::Unreachable: case IrOpcode::EmitVertex: case IrOpcode::Discard: case IrOpcode::Reference: case IrOpcode::ReferenceU32: case IrOpcode::SetTessellationAttribute: case IrOpcode::SetThreadBitScalarRegister: case IrOpcode::SetScalarMaskTag: case IrOpcode::SetScalarRegister: case IrOpcode::SetVectorRegister: case IrOpcode::SetGotoVariable: case IrOpcode::SetScc: case IrOpcode::SetExec: case IrOpcode::SetExecLo: case IrOpcode::SetExecHi: case IrOpcode::SetVcc: case IrOpcode::SetVccLo: case IrOpcode::SetVccHi: case IrOpcode::SetM0: case IrOpcode::MeshAllocate: case IrOpcode::Barrier: case IrOpcode::Waitcnt: case IrOpcode::Sendmsg: case IrOpcode::TtraceData: case IrOpcode::InstPrefetch: case IrOpcode::SetAttribute: return true; default: return false; } } std::string_view IrOpcodeName(IrOpcode opcode) { return metaOf(opcode).name; } }