mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
1212 lines
50 KiB
C++
1212 lines
50 KiB
C++
#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 <algorithm>
|
|
#include <bit>
|
|
#include <fmt/format.h>
|
|
#include <set>
|
|
|
|
namespace Libs::Graphics::ShaderRecompiler::Decoder {
|
|
namespace {
|
|
|
|
uint32_t FloatBits(float value) {
|
|
return std::bit_cast<uint32_t>(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<int32_t>(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<uint32_t>(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<int32_t>(code - 128u);
|
|
operand.value = static_cast<uint32_t>(operand.signed_val);
|
|
return true;
|
|
}
|
|
if (code >= 193u && code <= 208u) {
|
|
operand.kind = OperandKind::IntegerInlineConstant;
|
|
operand.signed_val = 192 - static_cast<int32_t>(code);
|
|
operand.value = static_cast<uint32_t>(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<const uint32_t> 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<const uint32_t> code, uint32_t word_index,
|
|
uint32_t word_count) {
|
|
inst.word_count = word_count;
|
|
inst.raw_count = std::min<uint32_t>(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<const uint32_t> 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<uint32_t> 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
|