#include "graphics/shader/recompiler/frontend/decode/ShaderDecoder.h" #include "graphics/shader/recompiler/frontend/decode/ExportOps.h" #include "graphics/shader/recompiler/frontend/decode/ImageOps.h" #include "graphics/shader/recompiler/frontend/decode/MemoryOps.h" #include "graphics/shader/recompiler/frontend/decode/ScalarAluOps.h" #include "graphics/shader/recompiler/frontend/decode/VectorAluOps.h" #include #include #include #include namespace Libs::Graphics::ShaderRecompiler::Decoder { namespace { uint32_t FloatBits(float value) { return std::bit_cast(value); } void SetError(std::string* error, const char* message) { if (error != nullptr) { *error = message; } } bool HasLiteral(const Instruction& inst) { return inst.src0.kind == OperandKind::LiteralConstant || inst.src1.kind == OperandKind::LiteralConstant || inst.src2.kind == OperandKind::LiteralConstant || inst.src3.kind == OperandKind::LiteralConstant; } bool IsControlFlowBranch(Opcode opcode) { switch (opcode) { case Opcode::SBranch: case Opcode::SCbranchScc0: case Opcode::SCbranchScc1: case Opcode::SCbranchVccz: case Opcode::SCbranchVccnz: case Opcode::SCbranchExecz: case Opcode::SCbranchExecnz: return true; default: return false; } } void ApplyLiteral(Operand& operand, uint32_t literal) { if (operand.kind == OperandKind::LiteralConstant) { operand.value = literal; operand.signed_val = static_cast(literal); } } std::string RawWordsToString(const Instruction& inst) { std::string text; for (uint32_t i = 0; i < inst.raw_count; i++) { if (i != 0) { text += " "; } text += fmt::format("0x{:08x}", inst.raw[i]); } return text; } std::string FormatBinary(const Instruction& inst) { std::string text = fmt::format("0x{:08x}: {} {}", inst.pc, OpcodeToString(inst.opcode).c_str(), OperandToString(inst.dst).c_str()); if (inst.dst2.kind != OperandKind::Unknown) { text += ", "; text += OperandToString(inst.dst2); } const Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2, &inst.src3}; for (uint32_t i = 0; i < inst.src_count && i < 4u; i++) { text += ", "; text += OperandToString(*sources[i]); } return text; } std::string FormatSources(const Instruction& inst) { std::string text = fmt::format("0x{:08x}: {}", inst.pc, OpcodeToString(inst.opcode)); const Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2, &inst.src3}; for (uint32_t i = 0; i < inst.src_count && i < 4u; i++) { text += i == 0 ? " " : ", "; text += OperandToString(*sources[i]); } return text; } std::string FormatMemory(const Instruction& inst) { std::string text = fmt::format("0x{:08x}: {} {}", inst.pc, OpcodeToString(inst.opcode).c_str(), OperandToString(inst.dst).c_str()); const Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2, &inst.src3}; for (uint32_t i = 0; i < inst.src_count && i < 4u; i++) { text += ", "; text += OperandToString(*sources[i]); } text += fmt::format(" ; offset={} offset2={} dwords={} bits={} dfmt={} nfmt={} signed={} " "typed={} formatted={} segment={} glc={} slc={} idxen={} offen={}", inst.offset, inst.secondary_offset, inst.data_dwords, inst.data_bits, inst.data_format, inst.number_format, inst.data_signed ? 1u : 0u, inst.typed ? 1u : 0u, inst.formatted ? 1u : 0u, inst.memory_segment, inst.glc ? 1u : 0u, inst.slc ? 1u : 0u, inst.idxen ? 1u : 0u, inst.offen ? 1u : 0u); return text; } std::string WithUnsupportedReason(const Instruction& inst, const std::string& text) { if (inst.unsupported_reason.empty()) { return text; } return text + fmt::format(" ; family={} opcode=0x{:02x} raw=[{}] reason={}", FamilyToString(inst.family).c_str(), inst.opcode_id, RawWordsToString(inst).c_str(), inst.unsupported_reason.c_str()); } void AppendFlag(std::string* text, bool* first, uint32_t flags, uint32_t flag, const char* name) { if ((flags & flag) == 0) { return; } if (!*first) { *text += "|"; } *text += name; *first = false; } std::string ImageSampleFlagsToString(uint32_t flags) { if (flags == 0) { return "none"; } std::string text; bool first = true; AppendFlag(&text, &first, flags, ImageSampleFlagLod, "lod"); AppendFlag(&text, &first, flags, ImageSampleFlagBias, "bias"); AppendFlag(&text, &first, flags, ImageSampleFlagDerivative, "derivative"); AppendFlag(&text, &first, flags, ImageSampleFlagCompare, "compare"); AppendFlag(&text, &first, flags, ImageSampleFlagOffset, "offset"); AppendFlag(&text, &first, flags, ImageSampleFlagLevelZero, "level_zero"); AppendFlag(&text, &first, flags, ImageSampleFlagLodClamp, "lod_clamp"); AppendFlag(&text, &first, flags, ImageSampleFlagA16, "a16"); AppendFlag(&text, &first, flags, ImageSampleFlagCd, "cd"); AppendFlag(&text, &first, flags, ImageSampleFlagGatherHorizontal, "gather_horizontal"); return text; } std::string FormatMimg(const Instruction& inst) { const char* sample_name = inst.opcode == Opcode::ImageSample ? MimgSampleOpcodeName(inst.opcode_id) : nullptr; const std::string name = sample_name != nullptr ? std::string(sample_name) : OpcodeToString(inst.opcode); std::string text = fmt::format( "0x{:08x}: {} {}, {}, {}, {} ; dmask=0x{:x} image_dim={}", inst.pc, name.c_str(), OperandToString(inst.dst).c_str(), OperandToString(inst.src0).c_str(), OperandToString(inst.src1).c_str(), OperandToString(inst.src2).c_str(), inst.dmask, ImageDimensionToString(inst.image_dimension)); switch (inst.opcode) { case Opcode::ImageSample: case Opcode::ImageGather4Lz: case Opcode::ImageGather4C: case Opcode::ImageGather4CLz: case Opcode::ImageGather4LzO: case Opcode::ImageGather4CO: case Opcode::ImageGather4CLzO: case Opcode::ImageGather4H: text += fmt::format(" sample_flags={} addr_components={}", ImageSampleFlagsToString(inst.image_sample_flags).c_str(), inst.image_address_components); break; default: break; } if (inst.image_nsa_dwords != 0) { text += fmt::format(" nsa_dwords={} nsa_addr=", inst.image_nsa_dwords); const auto count = std::min(inst.image_nsa_dwords * 4u, MaxImageNsaAddressComponents); for (uint32_t i = 0; i < count; i++) { if (i != 0) { text += ","; } text += fmt::format("{}", inst.image_nsa_addr[i]); } } return text; } std::string FormatExp(const Instruction& inst) { std::string text = fmt::format("0x{:08x}: exp target=0x{:02x} en=0x{:x} done={} compr={} vm={}", inst.pc, inst.exp.target, inst.exp.en, inst.exp.done ? 1u : 0u, inst.exp.compr ? 1u : 0u, inst.exp.vm ? 1u : 0u); const Operand* sources[] = {&inst.src0, &inst.src1, &inst.src2, &inst.src3}; for (uint32_t i = 0; i < inst.src_count && i < 4u; i++) { text += i == 0 ? " " : ", "; text += OperandToString(*sources[i]); } return text; } } // namespace const char* ImageDimensionToString(ImageDimension dimension) { switch (dimension) { case ImageDimension::Dim1D: return "1d"; case ImageDimension::Dim1DArray: return "1d_array"; case ImageDimension::Dim2D: return "2d"; case ImageDimension::Dim3D: return "3d"; case ImageDimension::Dim2DArray: return "2d_array"; case ImageDimension::Dim2DMsaa: return "2d_msaa"; case ImageDimension::Dim2DMsaaArray: return "2d_msaa_array"; default: return "unknown"; } } bool DecodeScalarSource(uint32_t code, uint32_t pc, Operand& operand, std::string* error) { operand = {}; if (code <= 105u) { operand.kind = OperandKind::Sgpr; operand.reg = code; return true; } if (code >= 128u && code <= 192u) { operand.kind = OperandKind::IntegerInlineConstant; operand.signed_val = static_cast(code - 128u); operand.value = static_cast(operand.signed_val); return true; } if (code >= 193u && code <= 208u) { operand.kind = OperandKind::IntegerInlineConstant; operand.signed_val = 192 - static_cast(code); operand.value = static_cast(operand.signed_val); return true; } if (code >= 240u && code <= 247u) { constexpr float values[] = {0.5f, -0.5f, 1.0f, -1.0f, 2.0f, -2.0f, 4.0f, -4.0f}; operand.kind = OperandKind::FloatInlineConstant; operand.float_val = values[code - 240u]; operand.value = FloatBits(operand.float_val); return true; } if (code >= 256u && code <= 511u) { return DecodeVectorGpr(code - 256u, operand, error); } switch (code) { case 106u: operand.kind = OperandKind::VccLo; return true; case 107u: operand.kind = OperandKind::VccHi; return true; case 124u: operand.kind = OperandKind::M0; return true; case 125u: operand.kind = OperandKind::Null; return true; case 126u: operand.kind = OperandKind::ExecLo; return true; case 127u: operand.kind = OperandKind::ExecHi; return true; case 239u: operand.kind = OperandKind::PopsExitingWaveId; return true; case 248u: operand.kind = OperandKind::FloatInlineConstant; operand.float_val = 0.15915494309189535f; operand.value = FloatBits(operand.float_val); return true; case 251u: operand.kind = OperandKind::VccZ; return true; case 252u: operand.kind = OperandKind::ExecZ; return true; case 253u: operand.kind = OperandKind::Scc; return true; case 255u: operand.kind = OperandKind::LiteralConstant; return true; default: if (error != nullptr) { *error = fmt::format("unsupported scalar source operand 0x{:08x} at pc 0x{:08x}", code, pc); } return false; } } bool DecodeScalarDestination(uint32_t code, uint32_t pc, Operand& operand, std::string* error) { operand = {}; if (code <= 105u) { operand.kind = OperandKind::Sgpr; operand.reg = code; return true; } switch (code) { case 106u: operand.kind = OperandKind::VccLo; return true; case 107u: operand.kind = OperandKind::VccHi; return true; case 124u: operand.kind = OperandKind::M0; return true; case 125u: operand.kind = OperandKind::Null; return true; case 126u: operand.kind = OperandKind::ExecLo; return true; case 127u: operand.kind = OperandKind::ExecHi; return true; default: if (error != nullptr) { *error = fmt::format( "unsupported scalar destination operand 0x{:08x} at pc 0x{:08x}", code, pc); } return false; } } bool DecodeVectorGpr(uint32_t reg, Operand& operand, std::string* error) { if (reg > 255u) { SetError(error, "VGPR index is out of range"); return false; } operand = {}; operand.kind = OperandKind::Vgpr; operand.reg = reg; return true; } bool ReadLiteralOperands(std::span code, uint32_t word_index, Instruction& inst, std::string* error) { if (!HasLiteral(inst)) { return true; } if (word_index + inst.word_count >= code.size()) { if (error != nullptr) { *error = fmt::format("missing literal constant at pc 0x{:08x}", inst.pc); } return false; } const auto literal = code[word_index + inst.word_count]; ApplyLiteral(inst.src0, literal); ApplyLiteral(inst.src1, literal); ApplyLiteral(inst.src2, literal); ApplyLiteral(inst.src3, literal); inst.word_count++; SetRawWords(inst, code, word_index, inst.word_count); return true; } void SetRawWords(Instruction& inst, std::span code, uint32_t word_index, uint32_t word_count) { inst.word_count = word_count; inst.raw_count = std::min(word_count, MaxInstructionRawWords); for (uint32_t i = 0; i < inst.raw_count; i++) { inst.raw[i] = code[word_index + i]; } } void SetUnsupported(Instruction& inst, Family family, uint32_t opcode_id, const char* reason) { inst.opcode = Opcode::Unsupported; inst.family = family; inst.opcode_id = opcode_id; inst.unsupported_reason = reason; } bool DecodeProgram(std::span code, Program& program, std::string* error) { if (code.empty() || code.size() > UINT32_MAX / sizeof(uint32_t)) { SetError(error, "invalid shader decoder input"); return false; } program.instructions.clear(); program.code = code; std::set branch_targets; for (uint32_t word_index = 0; word_index < code.size();) { const uint32_t pc = word_index * 4u; const uint32_t word = code[word_index]; Instruction inst; bool ok = false; if ((word & 0x80000000u) == 0u) { ok = DecodeVop2(pc, code, word_index, inst, error); } else if ((word & 0xc0000000u) == 0x80000000u) { const auto opcode = (word >> 23u) & 0x7fu; switch (opcode) { case 0x7du: ok = DecodeSop1(pc, code, word_index, inst, error); break; case 0x7eu: ok = DecodeSopc(pc, code, word_index, inst, error); break; case 0x7fu: ok = DecodeSopp(pc, code, word_index, inst, error); break; default: ok = opcode >= 0x60u ? DecodeSopk(pc, code, word_index, inst, error) : DecodeSop2(pc, code, word_index, inst, error); break; } } else { switch (word >> 26u) { case 0x32u: ok = DecodeVintrp(pc, code, word_index, inst, error); break; case 0x33u: ok = DecodeVop3p(pc, code, word_index, inst, error); break; case 0x35u: ok = DecodeVop3(pc, code, word_index, inst, error); break; case 0x36u: ok = DecodeDs(pc, code, word_index, inst, error); break; case 0x37u: ok = DecodeFlat(pc, code, word_index, inst, error); break; case 0x38u: ok = DecodeMubuf(pc, code, word_index, inst, error); break; case 0x3au: ok = DecodeMtbuf(pc, code, word_index, inst, error); break; case 0x3cu: ok = DecodeMimg(pc, code, word_index, inst, error); break; case 0x3du: ok = DecodeSmem(pc, code, word_index, inst, error); break; case 0x3eu: ok = DecodeExp(pc, code, word_index, inst, error); break; default: if (error != nullptr) { *error = fmt::format( "unknown RDNA2 instruction family at pc 0x{:08x}, raw=0x{:08x}", pc, word); } return false; } } if (!ok) { return false; } program.instructions.push_back(inst); word_index += inst.word_count; if (IsControlFlowBranch(inst.opcode)) { branch_targets.insert(inst.branch_target); } if (inst.opcode == Opcode::SEndpgm && (word_index >= code.size() || !branch_targets.contains(word_index * 4u))) { return true; } } SetError(error, "shader decode reached the code boundary before S_ENDPGM"); return false; } std::string FamilyToString(Family family) { switch (family) { case Family::SOP1: return "SOP1"; case Family::SOP2: return "SOP2"; case Family::SOPK: return "SOPK"; case Family::SOPC: return "SOPC"; case Family::SOPP: return "SOPP"; case Family::VOP1: return "VOP1"; case Family::VOP2: return "VOP2"; case Family::VOP3: return "VOP3"; case Family::VOP3P: return "VOP3P"; case Family::VOPC: return "VOPC"; case Family::VINTRP: return "VINTRP"; case Family::SMEM: return "SMEM"; case Family::MUBUF: return "MUBUF"; case Family::MTBUF: return "MTBUF"; case Family::FLAT: return "FLAT"; case Family::DS: return "DS"; case Family::MIMG: return "MIMG"; case Family::EXP: return "EXP"; default: return "Unknown"; } } std::string OpcodeToString(Opcode opcode) { switch (opcode) { case Opcode::SMovB32: return "s_mov_b32"; case Opcode::SMovB64: return "s_mov_b64"; case Opcode::SMovkI32: return "s_movk_i32"; case Opcode::SAbsI32: return "s_abs_i32"; case Opcode::SBrevB32: return "s_brev_b32"; case Opcode::SBcnt1I32B32: return "s_bcnt1_i32_b32"; case Opcode::SBcnt1I32B64: return "s_bcnt1_i32_b64"; case Opcode::SFf1I32B32: return "s_ff1_i32_b32"; case Opcode::SFlbitI32B64: return "s_flbit_i32_b64"; case Opcode::SBitreplicateB64B32: return "s_bitreplicate_b64_b32"; case Opcode::SGetpcB64: return "s_getpc_b64"; case Opcode::SSetpcB64: return "s_setpc_b64"; case Opcode::SAndSaveexecB32: return "s_and_saveexec_b32"; case Opcode::SAndn1SaveexecB32: return "s_andn1_saveexec_b32"; case Opcode::SAndSaveexecB64: return "s_and_saveexec_b64"; case Opcode::SOrn2SaveexecB64: return "s_orn2_saveexec_b64"; case Opcode::SAndn1SaveexecB64: return "s_andn1_saveexec_b64"; case Opcode::SNotB32: return "s_not_b32"; case Opcode::SNotB64: return "s_not_b64"; case Opcode::SWqmB64: return "s_wqm_b64"; case Opcode::SAddU32: return "s_add_u32"; case Opcode::SAddcU32: return "s_addc_u32"; case Opcode::SSubbU32: return "s_subb_u32"; case Opcode::SSubU32: return "s_sub_u32"; case Opcode::SAddI32: return "s_add_i32"; case Opcode::SSubI32: return "s_sub_i32"; case Opcode::SBitcmp0B32: return "s_bitcmp0_b32"; case Opcode::SBitcmp1B32: return "s_bitcmp1_b32"; case Opcode::SBitset0B32: return "s_bitset0_b32"; case Opcode::SBitset1B32: return "s_bitset1_b32"; case Opcode::SMinI32: return "s_min_i32"; case Opcode::SMaxI32: return "s_max_i32"; case Opcode::SMinU32: return "s_min_u32"; case Opcode::SMaxU32: return "s_max_u32"; case Opcode::SAndB32: return "s_and_b32"; case Opcode::SAndB64: return "s_and_b64"; case Opcode::SAndn2B32: return "s_andn2_b32"; case Opcode::SAndn2B64: return "s_andn2_b64"; case Opcode::SOrB32: return "s_or_b32"; case Opcode::SOrB64: return "s_or_b64"; case Opcode::SOrn2B32: return "s_orn2_b32"; case Opcode::SOrn2B64: return "s_orn2_b64"; case Opcode::SXorB32: return "s_xor_b32"; case Opcode::SXorB64: return "s_xor_b64"; case Opcode::SNandB32: return "s_nand_b32"; case Opcode::SNandB64: return "s_nand_b64"; case Opcode::SNorB32: return "s_nor_b32"; case Opcode::SNorB64: return "s_nor_b64"; case Opcode::SXnorB32: return "s_xnor_b32"; case Opcode::SXnorB64: return "s_xnor_b64"; case Opcode::SLshlB32: return "s_lshl_b32"; case Opcode::SLshlB64: return "s_lshl_b64"; case Opcode::SLshl1AddU32: return "s_lshl1_add_u32"; case Opcode::SLshl2AddU32: return "s_lshl2_add_u32"; case Opcode::SLshl3AddU32: return "s_lshl3_add_u32"; case Opcode::SLshl4AddU32: return "s_lshl4_add_u32"; case Opcode::SLshrB32: return "s_lshr_b32"; case Opcode::SLshrB64: return "s_lshr_b64"; case Opcode::SAshrI32: return "s_ashr_i32"; case Opcode::SMulI32: return "s_mul_i32"; case Opcode::SMulHiU32: return "s_mul_hi_u32"; case Opcode::SMulkI32: return "s_mulk_i32"; case Opcode::SBfeU32: return "s_bfe_u32"; case Opcode::SBfeU64: return "s_bfe_u64"; case Opcode::SBfmB32: return "s_bfm_b32"; case Opcode::SBfmB64: return "s_bfm_b64"; case Opcode::SCselectB32: return "s_cselect_b32"; case Opcode::SCselectB64: return "s_cselect_b64"; case Opcode::SPackLlB32B16: return "s_pack_ll_b32_b16"; case Opcode::SPackLhB32B16: return "s_pack_lh_b32_b16"; case Opcode::SPackHhB32B16: return "s_pack_hh_b32_b16"; case Opcode::SCmpEqI32: return "s_cmp_eq_i32"; case Opcode::SCmpLgI32: return "s_cmp_lg_i32"; case Opcode::SCmpGtI32: return "s_cmp_gt_i32"; case Opcode::SCmpGeI32: return "s_cmp_ge_i32"; case Opcode::SCmpLtI32: return "s_cmp_lt_i32"; case Opcode::SCmpLeI32: return "s_cmp_le_i32"; case Opcode::SCmpEqU32: return "s_cmp_eq_u32"; case Opcode::SCmpLgU32: return "s_cmp_lg_u32"; case Opcode::SCmpGtU32: return "s_cmp_gt_u32"; case Opcode::SCmpGeU32: return "s_cmp_ge_u32"; case Opcode::SCmpLtU32: return "s_cmp_lt_u32"; case Opcode::SCmpLeU32: return "s_cmp_le_u32"; case Opcode::SCmpEqU64: return "s_cmp_eq_u64"; case Opcode::SCmpLgU64: return "s_cmp_lg_u64"; case Opcode::VNop: return "v_nop"; case Opcode::VMovB32: return "v_mov_b32"; case Opcode::VMovreldB32: return "v_movreld_b32"; case Opcode::VMovrelsB32: return "v_movrels_b32"; case Opcode::VReadfirstlaneB32: return "v_readfirstlane_b32"; case Opcode::VReadlaneB32: return "v_readlane_b32"; case Opcode::VWritelaneB32: return "v_writelane_b32"; case Opcode::VPermlane16B32: return "v_permlane16_b32"; case Opcode::VPermlanex16B32: return "v_permlanex16_b32"; case Opcode::VCubeidF32: return "v_cubeid_f32"; case Opcode::VCubescF32: return "v_cubesc_f32"; case Opcode::VCubetcF32: return "v_cubetc_f32"; case Opcode::VCubemaF32: return "v_cubema_f32"; case Opcode::VCndmaskB32: return "v_cndmask_b32"; case Opcode::VDot2cF32F16: return "v_dot2c_f32_f16"; case Opcode::VCvtF32I32: return "v_cvt_f32_i32"; case Opcode::VCvtF32U32: return "v_cvt_f32_u32"; case Opcode::VCvtU32F32: return "v_cvt_u32_f32"; case Opcode::VCvtI32F32: return "v_cvt_i32_f32"; case Opcode::VCvtF16F32: return "v_cvt_f16_f32"; case Opcode::VCvtF32F16: return "v_cvt_f32_f16"; case Opcode::VCvtF16U16: return "v_cvt_f16_u16"; case Opcode::VCvtU16F16: return "v_cvt_u16_f16"; case Opcode::VCvtF16I16: return "v_cvt_f16_i16"; case Opcode::VCvtI16F16: return "v_cvt_i16_f16"; case Opcode::VCvtRpiI32F32: return "v_cvt_rpi_i32_f32"; case Opcode::VCvtFlrI32F32: return "v_cvt_flr_i32_f32"; case Opcode::VCvtOffF32I4: return "v_cvt_off_f32_i4"; case Opcode::VCvtF32Ubyte0: return "v_cvt_f32_ubyte0"; case Opcode::VCvtF32Ubyte1: return "v_cvt_f32_ubyte1"; case Opcode::VCvtF32Ubyte2: return "v_cvt_f32_ubyte2"; case Opcode::VCvtF32Ubyte3: return "v_cvt_f32_ubyte3"; case Opcode::VRcpF32: return "v_rcp_f32"; case Opcode::VRcpIflagF32: return "v_rcp_iflag_f32"; case Opcode::VFractF32: return "v_fract_f32"; case Opcode::VTruncF32: return "v_trunc_f32"; case Opcode::VCeilF32: return "v_ceil_f32"; case Opcode::VRndneF32: return "v_rndne_f32"; case Opcode::VFloorF32: return "v_floor_f32"; case Opcode::VExpF32: return "v_exp_f32"; case Opcode::VLogF32: return "v_log_f32"; case Opcode::VRsqF32: return "v_rsq_f32"; case Opcode::VSqrtF32: return "v_sqrt_f32"; case Opcode::VRcpF16: return "v_rcp_f16"; case Opcode::VSqrtF16: return "v_sqrt_f16"; case Opcode::VRsqF16: return "v_rsq_f16"; case Opcode::VLogF16: return "v_log_f16"; case Opcode::VExpF16: return "v_exp_f16"; case Opcode::VFloorF16: return "v_floor_f16"; case Opcode::VCeilF16: return "v_ceil_f16"; case Opcode::VTruncF16: return "v_trunc_f16"; case Opcode::VRndneF16: return "v_rndne_f16"; case Opcode::VSinF32: return "v_sin_f32"; case Opcode::VCosF32: return "v_cos_f32"; case Opcode::VNotB32: return "v_not_b32"; case Opcode::VBfrevB32: return "v_bfrev_b32"; case Opcode::VFfbhU32: return "v_ffbh_u32"; case Opcode::VFfblB32: return "v_ffbl_b32"; case Opcode::VAddF32: return "v_add_f32"; case Opcode::VSubF32: return "v_sub_f32"; case Opcode::VSubrevF32: return "v_subrev_f32"; case Opcode::VMulF32: return "v_mul_f32"; case Opcode::VMacF32: return "v_mac_f32"; case Opcode::VMadmkF32: return "v_madmk_f32"; case Opcode::VMadakF32: return "v_madak_f32"; case Opcode::VMinF32: return "v_min_f32"; case Opcode::VMaxF32: return "v_max_f32"; case Opcode::VAddF16: return "v_add_f16"; case Opcode::VSubF16: return "v_sub_f16"; case Opcode::VSubrevF16: return "v_subrev_f16"; case Opcode::VMulF16: return "v_mul_f16"; case Opcode::VFmacF16: return "v_fmac_f16"; case Opcode::VFmamkF16: return "v_fmamk_f16"; case Opcode::VFmaakF16: return "v_fmaak_f16"; case Opcode::VMinI32: return "v_min_i32"; case Opcode::VMaxI32: return "v_max_i32"; case Opcode::VMulI32I24: return "v_mul_i32_i24"; case Opcode::VMulU32U24: return "v_mul_u32_u24"; case Opcode::VMulLoU32: return "v_mul_lo_u32"; case Opcode::VMulHiU32: return "v_mul_hi_u32"; case Opcode::VMulLoI32: return "v_mul_lo_i32"; case Opcode::VMulHiI32: return "v_mul_hi_i32"; case Opcode::VCvtPkrtzF16F32: return "v_cvt_pkrtz_f16_f32"; case Opcode::VCvtPkU8F32: return "v_cvt_pk_u8_f32"; case Opcode::VMadF32: return "v_mad_f32"; case Opcode::VMadI32I24: return "v_mad_i32_i24"; case Opcode::VMadU32U24: return "v_mad_u32_u24"; case Opcode::VMadU64U32: return "v_mad_u64_u32"; case Opcode::VFmaF32: return "v_fma_f32"; case Opcode::VFmaF16: return "v_fma_f16"; case Opcode::VPackB32F16: return "v_pack_b32_f16"; case Opcode::VBfeU32: return "v_bfe_u32"; case Opcode::VBfeI32: return "v_bfe_i32"; case Opcode::VBfiB32: return "v_bfi_b32"; case Opcode::VAlignbitB32: return "v_alignbit_b32"; case Opcode::VMin3F32: return "v_min3_f32"; case Opcode::VMin3I32: return "v_min3_i32"; case Opcode::VMin3U32: return "v_min3_u32"; case Opcode::VMin3F16: return "v_min3_f16"; case Opcode::VMax3F32: return "v_max3_f32"; case Opcode::VMax3I32: return "v_max3_i32"; case Opcode::VMax3U32: return "v_max3_u32"; case Opcode::VMax3F16: return "v_max3_f16"; case Opcode::VMed3F32: return "v_med3_f32"; case Opcode::VMed3I32: return "v_med3_i32"; case Opcode::VMed3U32: return "v_med3_u32"; case Opcode::VMed3F16: return "v_med3_f16"; case Opcode::VSadU32: return "v_sad_u32"; case Opcode::VAdd3U32: return "v_add3_u32"; case Opcode::VLshlAddU32: return "v_lshl_add_u32"; case Opcode::VAddLshlU32: return "v_add_lshl_u32"; case Opcode::VXadU32: return "v_xad_u32"; case Opcode::VLshlOrB32: return "v_lshl_or_b32"; case Opcode::VAndOrB32: return "v_and_or_b32"; case Opcode::VOr3B32: return "v_or3_b32"; case Opcode::VXor3B32: return "v_xor3_b32"; case Opcode::VAddI32: return "v_add_i32"; case Opcode::VSubI32: return "v_sub_i32"; case Opcode::VSubrevI32: return "v_subrev_i32"; case Opcode::VBfmB32: return "v_bfm_b32"; case Opcode::VLdexpF32: return "v_ldexp_f32"; case Opcode::VCvtPknormI16F32: return "v_cvt_pknorm_i16_f32"; case Opcode::VCvtPknormU16F32: return "v_cvt_pknorm_u16_f32"; case Opcode::VCvtPkU16U32: return "v_cvt_pk_u16_u32"; case Opcode::VPkMadI16: return "v_pk_mad_i16"; case Opcode::VPkMulLoU16: return "v_pk_mul_lo_u16"; case Opcode::VPkAddI16: return "v_pk_add_i16"; case Opcode::VPkSubI16: return "v_pk_sub_i16"; case Opcode::VPkLshlrevB16: return "v_pk_lshlrev_b16"; case Opcode::VPkLshrrevB16: return "v_pk_lshrrev_b16"; case Opcode::VPkAshrrevI16: return "v_pk_ashrrev_i16"; case Opcode::VPkMaxI16: return "v_pk_max_i16"; case Opcode::VPkMinI16: return "v_pk_min_i16"; case Opcode::VPkMadU16: return "v_pk_mad_u16"; case Opcode::VPkAddF16: return "v_pk_add_f16"; case Opcode::VPkMulF16: return "v_pk_mul_f16"; case Opcode::VPkMinF16: return "v_pk_min_f16"; case Opcode::VPkMaxF16: return "v_pk_max_f16"; case Opcode::VPkFmaF16: return "v_pk_fma_f16"; case Opcode::VPkFmacF16: return "v_pk_fmac_f16"; case Opcode::VPkAddU16: return "v_pk_add_u16"; case Opcode::VPkSubU16: return "v_pk_sub_u16"; case Opcode::VPkMaxU16: return "v_pk_max_u16"; case Opcode::VPkMinU16: return "v_pk_min_u16"; case Opcode::VMadMixloF16: return "v_mad_mixlo_f16"; case Opcode::VMadMixhiF16: return "v_mad_mixhi_f16"; case Opcode::VAddNcU32: return "v_add_nc_u32"; case Opcode::VAddcU32: return "v_addc_u32"; case Opcode::VSubrevCoCiU32: return "v_subrev_co_ci_u32"; case Opcode::VSubNcU32: return "v_sub_nc_u32"; case Opcode::VSubrevNcU32: return "v_subrev_nc_u32"; case Opcode::VAddNcU16: return "v_add_nc_u16"; case Opcode::VSubNcU16: return "v_sub_nc_u16"; case Opcode::VMaxU16: return "v_max_u16"; case Opcode::VMaxI16: return "v_max_i16"; case Opcode::VMinU16: return "v_min_u16"; case Opcode::VMinI16: return "v_min_i16"; case Opcode::VAddNcI16: return "v_add_nc_i16"; case Opcode::VSubNcI16: return "v_sub_nc_i16"; case Opcode::VAndB32: return "v_and_b32"; case Opcode::VOrB32: return "v_or_b32"; case Opcode::VXorB32: return "v_xor_b32"; case Opcode::VXnorB32: return "v_xnor_b32"; case Opcode::VLshlB32: return "v_lshl_b32"; case Opcode::VLshlrevB32: return "v_lshlrev_b32"; case Opcode::VLshrB32: return "v_lshr_b32"; case Opcode::VLshrrevB32: return "v_lshrrev_b32"; case Opcode::VAshrI32: return "v_ashr_i32"; case Opcode::VAshrrevI32: return "v_ashrrev_i32"; case Opcode::VLshlrevB16: return "v_lshlrev_b16"; case Opcode::VLshrrevB16: return "v_lshrrev_b16"; case Opcode::VAshrrevI16: return "v_ashrrev_i16"; case Opcode::VBcntU32B32: return "v_bcnt_u32_b32"; case Opcode::VMbcntLoU32B32: return "v_mbcnt_lo_u32_b32"; case Opcode::VMbcntHiU32B32: return "v_mbcnt_hi_u32_b32"; case Opcode::VMinU32: return "v_min_u32"; case Opcode::VMaxU32: return "v_max_u32"; case Opcode::VMaxF16: return "v_max_f16"; case Opcode::VMinF16: return "v_min_f16"; case Opcode::VCmpFF32: return "v_cmp_f_f32"; case Opcode::VCmpLtF32: return "v_cmp_lt_f32"; case Opcode::VCmpEqF32: return "v_cmp_eq_f32"; case Opcode::VCmpLeF32: return "v_cmp_le_f32"; case Opcode::VCmpGtF32: return "v_cmp_gt_f32"; case Opcode::VCmpLgF32: return "v_cmp_lg_f32"; case Opcode::VCmpGeF32: return "v_cmp_ge_f32"; case Opcode::VCmpOF32: return "v_cmp_o_f32"; case Opcode::VCmpUF32: return "v_cmp_u_f32"; case Opcode::VCmpNgeF32: return "v_cmp_nge_f32"; case Opcode::VCmpNlgF32: return "v_cmp_nlg_f32"; case Opcode::VCmpNgtF32: return "v_cmp_ngt_f32"; case Opcode::VCmpNleF32: return "v_cmp_nle_f32"; case Opcode::VCmpNeqF32: return "v_cmp_neq_f32"; case Opcode::VCmpNltF32: return "v_cmp_nlt_f32"; case Opcode::VCmpTruF32: return "v_cmp_tru_f32"; case Opcode::VCmpxLtF32: return "v_cmpx_lt_f32"; case Opcode::VCmpxEqF32: return "v_cmpx_eq_f32"; case Opcode::VCmpxLeF32: return "v_cmpx_le_f32"; case Opcode::VCmpxGtF32: return "v_cmpx_gt_f32"; case Opcode::VCmpxLgF32: return "v_cmpx_lg_f32"; case Opcode::VCmpxGeF32: return "v_cmpx_ge_f32"; case Opcode::VCmpxNgeF32: return "v_cmpx_nge_f32"; case Opcode::VCmpxNlgF32: return "v_cmpx_nlg_f32"; case Opcode::VCmpxNgtF32: return "v_cmpx_ngt_f32"; case Opcode::VCmpxNleF32: return "v_cmpx_nle_f32"; case Opcode::VCmpxNeqF32: return "v_cmpx_neq_f32"; case Opcode::VCmpxNltF32: return "v_cmpx_nlt_f32"; case Opcode::VCmpFI32: return "v_cmp_f_i32"; case Opcode::VCmpLtI32: return "v_cmp_lt_i32"; case Opcode::VCmpEqI32: return "v_cmp_eq_i32"; case Opcode::VCmpLeI32: return "v_cmp_le_i32"; case Opcode::VCmpGtI32: return "v_cmp_gt_i32"; case Opcode::VCmpNeI32: return "v_cmp_ne_i32"; case Opcode::VCmpGeI32: return "v_cmp_ge_i32"; case Opcode::VCmpTI32: return "v_cmp_t_i32"; case Opcode::VCmpClassF32: return "v_cmp_class_f32"; case Opcode::VCmpLtI16: return "v_cmp_lt_i16"; case Opcode::VCmpEqI16: return "v_cmp_eq_i16"; case Opcode::VCmpLeI16: return "v_cmp_le_i16"; case Opcode::VCmpGtI16: return "v_cmp_gt_i16"; case Opcode::VCmpNeI16: return "v_cmp_ne_i16"; case Opcode::VCmpGeI16: return "v_cmp_ge_i16"; case Opcode::VCmpLtF16: return "v_cmp_lt_f16"; case Opcode::VCmpEqF16: return "v_cmp_eq_f16"; case Opcode::VCmpLeF16: return "v_cmp_le_f16"; case Opcode::VCmpGtF16: return "v_cmp_gt_f16"; case Opcode::VCmpLgF16: return "v_cmp_lg_f16"; case Opcode::VCmpGeF16: return "v_cmp_ge_f16"; case Opcode::VCmpNeqF16: return "v_cmp_neq_f16"; case Opcode::VCmpxLtF16: return "v_cmpx_lt_f16"; case Opcode::VCmpxEqF16: return "v_cmpx_eq_f16"; case Opcode::VCmpxLeF16: return "v_cmpx_le_f16"; case Opcode::VCmpxGtF16: return "v_cmpx_gt_f16"; case Opcode::VCmpxGeF16: return "v_cmpx_ge_f16"; case Opcode::VCmpxNeqF16: return "v_cmpx_neq_f16"; case Opcode::VCmpxNltF16: return "v_cmpx_nlt_f16"; case Opcode::VCmpxLtI32: return "v_cmpx_lt_i32"; case Opcode::VCmpxEqI32: return "v_cmpx_eq_i32"; case Opcode::VCmpxLeI32: return "v_cmpx_le_i32"; case Opcode::VCmpxGtI32: return "v_cmpx_gt_i32"; case Opcode::VCmpxNeI32: return "v_cmpx_ne_i32"; case Opcode::VCmpxGeI32: return "v_cmpx_ge_i32"; case Opcode::VCmpLtU16: return "v_cmp_lt_u16"; case Opcode::VCmpEqU16: return "v_cmp_eq_u16"; case Opcode::VCmpLeU16: return "v_cmp_le_u16"; case Opcode::VCmpGtU16: return "v_cmp_gt_u16"; case Opcode::VCmpNeU16: return "v_cmp_ne_u16"; case Opcode::VCmpGeU16: return "v_cmp_ge_u16"; case Opcode::VCmpFU32: return "v_cmp_f_u32"; case Opcode::VCmpLtU32: return "v_cmp_lt_u32"; case Opcode::VCmpEqU32: return "v_cmp_eq_u32"; case Opcode::VCmpLeU32: return "v_cmp_le_u32"; case Opcode::VCmpGtU32: return "v_cmp_gt_u32"; case Opcode::VCmpNeU32: return "v_cmp_ne_u32"; case Opcode::VCmpGeU32: return "v_cmp_ge_u32"; case Opcode::VCmpTU32: return "v_cmp_t_u32"; case Opcode::VCmpEqI64: return "v_cmp_eq_i64"; case Opcode::VCmpGtU64: return "v_cmp_gt_u64"; case Opcode::VCmpNeU64: return "v_cmp_ne_u64"; case Opcode::VCmpxLtU32: return "v_cmpx_lt_u32"; case Opcode::VCmpxEqU32: return "v_cmpx_eq_u32"; case Opcode::VCmpxLeU32: return "v_cmpx_le_u32"; case Opcode::VCmpxGtU32: return "v_cmpx_gt_u32"; case Opcode::VCmpxNeU32: return "v_cmpx_ne_u32"; case Opcode::VCmpxGeU32: return "v_cmpx_ge_u32"; case Opcode::SLoadDword: return "s_load_dword"; case Opcode::SLoadDwordx2: return "s_load_dwordx2"; case Opcode::SLoadDwordx4: return "s_load_dwordx4"; case Opcode::SLoadDwordx8: return "s_load_dwordx8"; case Opcode::SLoadDwordx16: return "s_load_dwordx16"; case Opcode::SBufferLoadDword: return "s_buffer_load_dword"; case Opcode::SBufferLoadDwordx2: return "s_buffer_load_dwordx2"; case Opcode::SBufferLoadDwordx4: return "s_buffer_load_dwordx4"; case Opcode::SBufferLoadDwordx8: return "s_buffer_load_dwordx8"; case Opcode::SBufferLoadDwordx16: return "s_buffer_load_dwordx16"; case Opcode::BufferLoadFormatX: return "buffer_load_format_x"; case Opcode::BufferLoadFormatXy: return "buffer_load_format_xy"; case Opcode::BufferLoadFormatXyz: return "buffer_load_format_xyz"; case Opcode::BufferLoadFormatXyzw: return "buffer_load_format_xyzw"; case Opcode::BufferStoreFormatX: return "buffer_store_format_x"; case Opcode::BufferStoreFormatXy: return "buffer_store_format_xy"; case Opcode::BufferStoreFormatXyz: return "buffer_store_format_xyz"; case Opcode::BufferStoreFormatXyzw: return "buffer_store_format_xyzw"; case Opcode::BufferLoadUbyte: return "buffer_load_ubyte"; case Opcode::BufferLoadSbyte: return "buffer_load_sbyte"; case Opcode::BufferLoadUshort: return "buffer_load_ushort"; case Opcode::BufferLoadSshort: return "buffer_load_sshort"; case Opcode::BufferLoadDword: return "buffer_load_dword"; case Opcode::BufferLoadDwordx2: return "buffer_load_dwordx2"; case Opcode::BufferLoadDwordx3: return "buffer_load_dwordx3"; case Opcode::BufferLoadDwordx4: return "buffer_load_dwordx4"; case Opcode::BufferStoreByte: return "buffer_store_byte"; case Opcode::BufferStoreShort: return "buffer_store_short"; case Opcode::BufferStoreDword: return "buffer_store_dword"; case Opcode::BufferStoreDwordx2: return "buffer_store_dwordx2"; case Opcode::BufferStoreDwordx3: return "buffer_store_dwordx3"; case Opcode::BufferStoreDwordx4: return "buffer_store_dwordx4"; case Opcode::TBufferLoadFormatX: return "tbuffer_load_format_x"; case Opcode::TBufferLoadFormatXy: return "tbuffer_load_format_xy"; case Opcode::TBufferLoadFormatXyz: return "tbuffer_load_format_xyz"; case Opcode::TBufferLoadFormatXyzw: return "tbuffer_load_format_xyzw"; case Opcode::TBufferStoreFormatX: return "tbuffer_store_format_x"; case Opcode::TBufferStoreFormatXy: return "tbuffer_store_format_xy"; case Opcode::TBufferStoreFormatXyz: return "tbuffer_store_format_xyz"; case Opcode::TBufferStoreFormatXyzw: return "tbuffer_store_format_xyzw"; case Opcode::BufferAtomicSwap: return "buffer_atomic_swap"; case Opcode::BufferAtomicAdd: return "buffer_atomic_add"; case Opcode::BufferAtomicSub: return "buffer_atomic_sub"; case Opcode::BufferAtomicSMin: return "buffer_atomic_smin"; case Opcode::BufferAtomicUMin: return "buffer_atomic_umin"; case Opcode::BufferAtomicSMax: return "buffer_atomic_smax"; case Opcode::BufferAtomicUMax: return "buffer_atomic_umax"; case Opcode::BufferAtomicAnd: return "buffer_atomic_and"; case Opcode::BufferAtomicOr: return "buffer_atomic_or"; case Opcode::BufferAtomicXor: return "buffer_atomic_xor"; case Opcode::BufferAtomicFMin: return "buffer_atomic_fmin"; case Opcode::BufferAtomicFMax: return "buffer_atomic_fmax"; case Opcode::FlatLoadUbyte: return "flat_load_ubyte"; case Opcode::FlatLoadSbyte: return "flat_load_sbyte"; case Opcode::FlatLoadUshort: return "flat_load_ushort"; case Opcode::FlatLoadSshort: return "flat_load_sshort"; case Opcode::FlatLoadDword: return "flat_load_dword"; case Opcode::FlatLoadDwordx2: return "flat_load_dwordx2"; case Opcode::FlatLoadDwordx3: return "flat_load_dwordx3"; case Opcode::FlatLoadDwordx4: return "flat_load_dwordx4"; case Opcode::FlatStoreByte: return "flat_store_byte"; case Opcode::FlatStoreShort: return "flat_store_short"; case Opcode::FlatStoreDword: return "flat_store_dword"; case Opcode::FlatStoreDwordx2: return "flat_store_dwordx2"; case Opcode::FlatStoreDwordx3: return "flat_store_dwordx3"; case Opcode::FlatStoreDwordx4: return "flat_store_dwordx4"; case Opcode::DsAddU32: return "ds_add_u32"; case Opcode::DsAddRtnU32: return "ds_add_rtn_u32"; case Opcode::DsSubU32: return "ds_sub_u32"; case Opcode::DsSubRtnU32: return "ds_sub_rtn_u32"; case Opcode::DsMinI32: return "ds_min_i32"; case Opcode::DsMinRtnI32: return "ds_min_rtn_i32"; case Opcode::DsMaxI32: return "ds_max_i32"; case Opcode::DsMaxRtnI32: return "ds_max_rtn_i32"; case Opcode::DsMinU32: return "ds_min_u32"; case Opcode::DsMinRtnU32: return "ds_min_rtn_u32"; case Opcode::DsMaxU32: return "ds_max_u32"; case Opcode::DsMaxRtnU32: return "ds_max_rtn_u32"; case Opcode::DsAndB32: return "ds_and_b32"; case Opcode::DsAndRtnB32: return "ds_and_rtn_b32"; case Opcode::DsOrB32: return "ds_or_b32"; case Opcode::DsOrRtnB32: return "ds_or_rtn_b32"; case Opcode::DsXorB32: return "ds_xor_b32"; case Opcode::DsXorRtnB32: return "ds_xor_rtn_b32"; case Opcode::DsWrxchgRtnB32: return "ds_wrxchg_rtn_b32"; case Opcode::DsMinF32: return "ds_min_f32"; case Opcode::DsMaxF32: return "ds_max_f32"; case Opcode::DsSwizzleB32: return "ds_swizzle_b32"; case Opcode::DsConsume: return "ds_consume"; case Opcode::DsAppend: return "ds_append"; case Opcode::DsReadSbyte: return "ds_read_i8"; case Opcode::DsReadUbyte: return "ds_read_u8"; case Opcode::DsReadSshort: return "ds_read_i16"; case Opcode::DsReadUshort: return "ds_read_u16"; case Opcode::DsRead2B32: return "ds_read2_b32"; case Opcode::DsReadB32: return "ds_read_b32"; case Opcode::DsReadB64: return "ds_read_b64"; case Opcode::DsRead2B64: return "ds_read2_b64"; case Opcode::DsRead2St64B64: return "ds_read2st64_b64"; case Opcode::DsReadB96: return "ds_read_b96"; case Opcode::DsReadB128: return "ds_read_b128"; case Opcode::DsWriteByte: return "ds_write_b8"; case Opcode::DsWriteShort: return "ds_write_b16"; case Opcode::DsWrite2B32: return "ds_write2_b32"; case Opcode::DsWrite2St64B32: return "ds_write2st64_b32"; case Opcode::DsWrite2B64: return "ds_write2_b64"; case Opcode::DsWrite2St64B64: return "ds_write2st64_b64"; case Opcode::DsWriteB32: return "ds_write_b32"; case Opcode::DsWriteB64: return "ds_write_b64"; case Opcode::DsWriteB96: return "ds_write_b96"; case Opcode::DsWriteB128: return "ds_write_b128"; case Opcode::DsWriteAddtidB32: return "ds_write_addtid_b32"; case Opcode::DsReadAddtidB32: return "ds_read_addtid_b32"; case Opcode::ImageGetResinfo: return "image_get_resinfo"; case Opcode::ImageGetLod: return "image_get_lod"; case Opcode::ImageLoad: return "image_load"; case Opcode::ImageLoadMip: return "image_load_mip"; case Opcode::ImageStore: return "image_store"; case Opcode::ImageStoreMip: return "image_store_mip"; case Opcode::ImageAtomicAdd: return "image_atomic_add"; case Opcode::ImageAtomicUMin: return "image_atomic_umin"; case Opcode::ImageAtomicUMax: return "image_atomic_umax"; case Opcode::ImageAtomicAnd: return "image_atomic_and"; case Opcode::ImageAtomicOr: return "image_atomic_or"; case Opcode::ImageAtomicXor: return "image_atomic_xor"; case Opcode::ImageSample: return "image_sample"; case Opcode::ImageGather4Lz: return "image_gather4_lz"; case Opcode::ImageGather4C: return "image_gather4_c"; case Opcode::ImageGather4CLz: return "image_gather4_c_lz"; case Opcode::ImageGather4LzO: return "image_gather4_lz_o"; case Opcode::ImageGather4CO: return "image_gather4_c_o"; case Opcode::ImageGather4CLzO: return "image_gather4_c_lz_o"; case Opcode::ImageGather4H: return "image_gather4h"; case Opcode::VInterpP1F32: return "v_interp_p1_f32"; case Opcode::VInterpP2F32: return "v_interp_p2_f32"; case Opcode::VInterpMovF32: return "v_interp_mov_f32"; case Opcode::SNop: return "s_nop"; case Opcode::SWaitcnt: return "s_waitcnt"; case Opcode::SBarrier: return "s_barrier"; case Opcode::SBranch: return "s_branch"; case Opcode::SCbranchScc0: return "s_cbranch_scc0"; case Opcode::SCbranchScc1: return "s_cbranch_scc1"; case Opcode::SCbranchVccz: return "s_cbranch_vccz"; case Opcode::SCbranchVccnz: return "s_cbranch_vccnz"; case Opcode::SCbranchExecz: return "s_cbranch_execz"; case Opcode::SCbranchExecnz: return "s_cbranch_execnz"; case Opcode::SSendmsg: return "s_sendmsg"; case Opcode::SSetregB32: return "s_setreg_b32"; case Opcode::SSleep: return "s_sleep"; case Opcode::STrap: return "s_trap"; case Opcode::STtraceData: return "s_ttracedata"; case Opcode::SInstPrefetch: return "s_inst_prefetch"; case Opcode::SEndpgm: return "s_endpgm"; case Opcode::Exp: return "exp"; case Opcode::Unsupported: return "unsupported"; default: return "unknown"; } } std::string OperandToString(const Operand& operand) { std::string text; switch (operand.kind) { case OperandKind::LiteralConstant: text = fmt::format("0x{:08x}", operand.value); break; case OperandKind::IntegerInlineConstant: text = fmt::format("{}", operand.signed_val); break; case OperandKind::FloatInlineConstant: text = fmt::format("{:f}", operand.float_val); break; case OperandKind::Sgpr: text = fmt::format("s{}", operand.reg); break; case OperandKind::Vgpr: text = fmt::format("v{}", operand.reg); break; case OperandKind::VccLo: text = "vcc_lo"; break; case OperandKind::VccHi: text = "vcc_hi"; break; case OperandKind::VccZ: text = "vccz"; break; case OperandKind::ExecLo: text = "exec_lo"; break; case OperandKind::ExecHi: text = "exec_hi"; break; case OperandKind::ExecZ: text = "execz"; break; case OperandKind::Scc: text = "scc"; break; case OperandKind::M0: text = "m0"; break; case OperandKind::PopsExitingWaveId: text = "pops_exiting_wave_id"; break; case OperandKind::Null: text = "null"; break; default: text = "unknown"; break; } if (operand.sdwa_sel != 6 || operand.sdwa_sext) { text += fmt::format(".sdwa(sel={},sext={})", operand.sdwa_sel, operand.sdwa_sext ? 1u : 0u); } if (operand.absolute) { text += ".abs"; } if (operand.negate) { text += ".neg"; } if (operand.op_sel || operand.op_sel_hi || operand.negate_hi) { text += fmt::format(".opsel(lo={},hi={},neghi={})", operand.op_sel ? 1u : 0u, operand.op_sel_hi ? 1u : 0u, operand.negate_hi ? 1u : 0u); } if (operand.omod != 0) { text += fmt::format(".omod({})", operand.omod); } if (operand.clamp) { text += ".clamp"; } if (operand.dpp) { text += fmt::format(".dpp(ctrl=0x{:x},fi={},bc={})", operand.dpp_ctrl, operand.dpp_fetch_inactive ? 1u : 0u, operand.dpp_bound_ctrl ? 1u : 0u); } return text; } std::string InstructionToString(const Instruction& inst) { if (inst.opcode == Opcode::Unsupported) { return fmt::format("0x{:08x}: unsupported family={} opcode=0x{:02x} raw=[{}] reason={}", inst.pc, FamilyToString(inst.family).c_str(), inst.opcode_id, RawWordsToString(inst).c_str(), inst.unsupported_reason.c_str()); } if (inst.family == Family::SOPC) { return WithUnsupportedReason(inst, FormatSources(inst)); } switch (inst.opcode) { case Opcode::SMovB32: case Opcode::SMovB64: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: {} {}, {}", inst.pc, OpcodeToString(inst.opcode).c_str(), OperandToString(inst.dst).c_str(), OperandToString(inst.src0).c_str())); case Opcode::SAbsI32: case Opcode::SBrevB32: case Opcode::SBcnt1I32B32: case Opcode::SFf1I32B32: case Opcode::SNotB64: case Opcode::SWqmB64: case Opcode::SAndSaveexecB32: case Opcode::SAndn1SaveexecB32: case Opcode::SAndSaveexecB64: case Opcode::SOrn2SaveexecB64: case Opcode::SAndn1SaveexecB64: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: {} {}, {}", inst.pc, OpcodeToString(inst.opcode).c_str(), OperandToString(inst.dst).c_str(), OperandToString(inst.src0).c_str())); case Opcode::SGetpcB64: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: s_getpc_b64 {}", inst.pc, OperandToString(inst.dst).c_str())); case Opcode::SSetpcB64: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: s_setpc_b64 {}", inst.pc, OperandToString(inst.src0).c_str())); case Opcode::SSetregB32: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: s_setreg_b32 {}, {}", inst.pc, OperandToString(inst.src0).c_str(), OperandToString(inst.src1).c_str())); case Opcode::SNop: case Opcode::SWaitcnt: case Opcode::SSleep: case Opcode::STrap: case Opcode::SSendmsg: case Opcode::STtraceData: case Opcode::SInstPrefetch: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: {} {}", inst.pc, OpcodeToString(inst.opcode).c_str(), OperandToString(inst.src0).c_str())); case Opcode::SBarrier: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: s_barrier", inst.pc)); case Opcode::VNop: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: v_nop", inst.pc)); case Opcode::SEndpgm: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: s_endpgm", inst.pc)); case Opcode::SBranch: case Opcode::SCbranchScc0: case Opcode::SCbranchScc1: case Opcode::SCbranchVccz: case Opcode::SCbranchVccnz: case Opcode::SCbranchExecz: case Opcode::SCbranchExecnz: return WithUnsupportedReason(inst, fmt::format("0x{:08x}: {} 0x{:08x}", inst.pc, OpcodeToString(inst.opcode).c_str(), inst.branch_target)); case Opcode::Exp: return WithUnsupportedReason(inst, FormatExp(inst)); case Opcode::ImageSample: case Opcode::ImageStore: case Opcode::ImageStoreMip: case Opcode::ImageAtomicAdd: case Opcode::ImageAtomicUMin: case Opcode::ImageAtomicUMax: case Opcode::ImageAtomicAnd: case Opcode::ImageAtomicOr: case Opcode::ImageAtomicXor: case Opcode::ImageLoad: case Opcode::ImageLoadMip: case Opcode::ImageGetResinfo: case Opcode::ImageGetLod: case Opcode::ImageGather4Lz: case Opcode::ImageGather4C: case Opcode::ImageGather4CLz: case Opcode::ImageGather4LzO: case Opcode::ImageGather4CO: case Opcode::ImageGather4CLzO: case Opcode::ImageGather4H: return WithUnsupportedReason(inst, FormatMimg(inst)); case Opcode::SLoadDword: case Opcode::SLoadDwordx2: case Opcode::SLoadDwordx4: case Opcode::SLoadDwordx8: case Opcode::SLoadDwordx16: case Opcode::SBufferLoadDword: case Opcode::SBufferLoadDwordx2: case Opcode::SBufferLoadDwordx4: case Opcode::SBufferLoadDwordx8: case Opcode::SBufferLoadDwordx16: case Opcode::BufferLoadFormatX: case Opcode::BufferLoadFormatXy: case Opcode::BufferLoadFormatXyz: case Opcode::BufferLoadFormatXyzw: case Opcode::BufferStoreFormatX: case Opcode::BufferStoreFormatXy: case Opcode::BufferStoreFormatXyz: case Opcode::BufferStoreFormatXyzw: case Opcode::BufferLoadUbyte: case Opcode::BufferLoadUshort: case Opcode::BufferLoadDword: case Opcode::BufferLoadDwordx2: case Opcode::BufferLoadDwordx3: case Opcode::BufferLoadDwordx4: case Opcode::BufferStoreByte: case Opcode::BufferStoreShort: case Opcode::BufferStoreDword: case Opcode::BufferStoreDwordx2: case Opcode::BufferStoreDwordx3: case Opcode::BufferStoreDwordx4: case Opcode::TBufferLoadFormatX: case Opcode::TBufferLoadFormatXy: case Opcode::TBufferLoadFormatXyz: case Opcode::TBufferLoadFormatXyzw: case Opcode::TBufferStoreFormatX: case Opcode::TBufferStoreFormatXy: case Opcode::TBufferStoreFormatXyz: case Opcode::TBufferStoreFormatXyzw: case Opcode::BufferAtomicSwap: case Opcode::BufferAtomicAdd: case Opcode::BufferAtomicSub: case Opcode::BufferAtomicSMin: case Opcode::BufferAtomicUMin: case Opcode::BufferAtomicSMax: case Opcode::BufferAtomicUMax: case Opcode::BufferAtomicAnd: case Opcode::BufferAtomicOr: case Opcode::BufferAtomicXor: case Opcode::BufferAtomicFMin: case Opcode::BufferAtomicFMax: case Opcode::BufferLoadSbyte: case Opcode::BufferLoadSshort: case Opcode::FlatLoadUbyte: case Opcode::FlatLoadSbyte: case Opcode::FlatLoadUshort: case Opcode::FlatLoadSshort: case Opcode::FlatLoadDword: case Opcode::FlatLoadDwordx2: case Opcode::FlatLoadDwordx3: case Opcode::FlatLoadDwordx4: case Opcode::FlatStoreByte: case Opcode::FlatStoreShort: case Opcode::FlatStoreDword: case Opcode::FlatStoreDwordx2: case Opcode::FlatStoreDwordx3: case Opcode::FlatStoreDwordx4: case Opcode::DsAddU32: case Opcode::DsAddRtnU32: case Opcode::DsSubU32: case Opcode::DsSubRtnU32: case Opcode::DsMinI32: case Opcode::DsMinRtnI32: case Opcode::DsMaxI32: case Opcode::DsMaxRtnI32: case Opcode::DsMinU32: case Opcode::DsMinRtnU32: case Opcode::DsMaxU32: case Opcode::DsMaxRtnU32: case Opcode::DsAndB32: case Opcode::DsAndRtnB32: case Opcode::DsOrB32: case Opcode::DsOrRtnB32: case Opcode::DsXorB32: case Opcode::DsXorRtnB32: case Opcode::DsWrxchgRtnB32: case Opcode::DsMinF32: case Opcode::DsMaxF32: case Opcode::DsSwizzleB32: case Opcode::DsReadSbyte: case Opcode::DsReadUbyte: case Opcode::DsReadSshort: case Opcode::DsReadUshort: case Opcode::DsRead2B32: case Opcode::DsReadB32: case Opcode::DsReadB64: case Opcode::DsRead2B64: case Opcode::DsRead2St64B64: case Opcode::DsReadB96: case Opcode::DsReadB128: case Opcode::DsWriteByte: case Opcode::DsWriteShort: case Opcode::DsWrite2B32: case Opcode::DsWrite2St64B32: case Opcode::DsWrite2B64: case Opcode::DsWrite2St64B64: case Opcode::DsWriteB32: case Opcode::DsWriteB64: case Opcode::DsWriteB96: case Opcode::DsWriteB128: case Opcode::DsWriteAddtidB32: case Opcode::DsReadAddtidB32: return WithUnsupportedReason(inst, FormatMemory(inst)); default: return WithUnsupportedReason(inst, FormatBinary(inst)); } } std::string ProgramToString(const Program& program) { std::string text; for (const auto& inst: program.instructions) { text += InstructionToString(inst); text += "\n"; } return text; } } // namespace Libs::Graphics::ShaderRecompiler::Decoder