This commit is contained in:
Marcin Mikołajczyk 2026-04-14 21:41:55 +02:00 committed by GitHub
parent b12ca606c8
commit c1e496efcd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 151 additions and 1 deletions

View File

@ -132,6 +132,7 @@ GcnInst GcnDecodeContext::decodeInstruction(GcnCodeSlice& code) {
// Note: Literal constant decode must be performed after meta info updated.
if (encodingLen == sizeof(u32)) {
decodeLiteralConstant(encoding, code);
decodeSubDwordAddressing(encoding, code);
}
repairOperandType();
@ -431,6 +432,76 @@ void GcnDecodeContext::decodeLiteralConstant(InstEncoding encoding, GcnCodeSlice
}
}
void GcnDecodeContext::decodeSubDwordAddressing(InstEncoding encoding, GcnCodeSlice& code) {
// Find if the instruction contains SDWA (it's legal only as src0)
if (m_instruction.src[0].field == OperandField::Sdwa) {
m_instruction.src[0].code = code.readu32();
m_instruction.length += sizeof(u32);
if (encoding == InstEncoding::VOPC) {
SdwaVopc sdwa = *reinterpret_cast<SdwaVopc*>(&m_instruction.src[0].code);
m_instruction.src[0].field =
sdwa.s0 == 0 ? OperandField::VectorGPR : getOperandField(sdwa.src0);
m_instruction.src[0].code = sdwa.src0;
m_instruction.src[0].sdwa_sel = SdwaSelector(sdwa.src0_sel);
m_instruction.src[0].input_modifier.neg = sdwa.src0_neg;
m_instruction.src[0].input_modifier.abs = sdwa.src0_abs;
m_instruction.src[0].input_modifier.sext = sdwa.src0_sext;
m_instruction.src[1].field =
sdwa.s1 == 0 ? OperandField::VectorGPR : getOperandField(m_instruction.src[1].code);
m_instruction.src[1].sdwa_sel = SdwaSelector(sdwa.src1_sel);
m_instruction.src[1].input_modifier.neg = sdwa.src1_neg;
m_instruction.src[1].input_modifier.abs = sdwa.src1_abs;
m_instruction.src[1].input_modifier.sext = sdwa.src1_sext;
m_instruction.dst[0].sdwa_sel = SdwaSelector(sdwa.dst_sel);
m_instruction.dst[0].sdwa_dst = SdwaDstUnused(sdwa.dst_u);
m_instruction.dst[0].output_modifier.clamp = sdwa.clamp;
switch (sdwa.omod) {
case 0:
m_instruction.dst[0].output_modifier.multiplier = 0.f;
break;
case 1:
m_instruction.dst[0].output_modifier.multiplier = 2.0f;
break;
case 2:
m_instruction.dst[0].output_modifier.multiplier = 4.0f;
break;
case 3:
m_instruction.dst[0].output_modifier.multiplier = 0.5f;
break;
}
} else if (encoding == InstEncoding::VOP1 || encoding == InstEncoding::VOP2) {
SdwaVop12 sdwa = *reinterpret_cast<SdwaVop12*>(&m_instruction.src[0].code);
m_instruction.src[0].field =
sdwa.s0 == 0 ? OperandField::VectorGPR : getOperandField(sdwa.src0);
m_instruction.src[0].code = sdwa.src0;
m_instruction.src[0].sdwa_sel = SdwaSelector(sdwa.src0_sel);
m_instruction.src[0].input_modifier.neg = sdwa.src0_neg;
m_instruction.src[0].input_modifier.abs = sdwa.src0_abs;
m_instruction.src[0].input_modifier.sext = sdwa.src0_sext;
m_instruction.src[1].field =
sdwa.s1 == 0 ? OperandField::VectorGPR : getOperandField(m_instruction.src[1].code);
m_instruction.src[1].sdwa_sel = SdwaSelector(sdwa.src1_sel);
m_instruction.src[1].input_modifier.neg = sdwa.src1_neg;
m_instruction.src[1].input_modifier.abs = sdwa.src1_abs;
m_instruction.src[1].input_modifier.sext = sdwa.src1_sext;
m_instruction.dst[0].field = sdwa.sd ? OperandField::ScalarGPR : OperandField::VccLo;
m_instruction.dst[0].code = sdwa.sdst;
} else {
LOG_WARNING(Render_Recompiler, "illegal instruction: SDWA used outside VOP1/VOP2/VOPC");
}
}
}
void GcnDecodeContext::decodeInstructionSOP1(u32 hexInstruction) {
u32 ssrc0 = bit::extract(hexInstruction, 7, 0);
u32 op = bit::extract(hexInstruction, 15, 8);

View File

@ -70,6 +70,7 @@ private:
void decodeInstruction32(InstEncoding encoding, GcnCodeSlice& code);
void decodeInstruction64(InstEncoding encoding, GcnCodeSlice& code);
void decodeLiteralConstant(InstEncoding encoding, GcnCodeSlice& code);
void decodeSubDwordAddressing(InstEncoding encoding, GcnCodeSlice& code);
// 32 bits encodings
void decodeInstructionSOP1(uint32_t hexInstruction);

View File

@ -28,6 +28,7 @@ struct InputModifiers {
bool neg = false;
bool neg_hi = false;
bool abs = false;
bool sext = false;
};
/// These are applied before storing an operand register.
@ -41,6 +42,24 @@ struct OperandSelection {
bool op_sel_hi = false;
};
enum class SdwaSelector : u32 {
Byte0 = 0,
Byte1 = 1,
Byte2 = 2,
Byte3 = 3,
Word0 = 4,
Word1 = 5,
Dword = 6,
Invalid = 7,
};
enum class SdwaDstUnused : u32 {
Pad = 0,
Sext = 1,
Preserve = 2,
Invalid = 3,
};
struct InstOperand {
OperandField field = OperandField::Undefined;
ScalarType type = ScalarType::Undefined;
@ -48,6 +67,8 @@ struct InstOperand {
OutputModifiers output_modifier = {};
// only valid for packed 16bit operations
OperandSelection op_sel = {};
SdwaDstUnused sdwa_dst = SdwaDstUnused::Invalid;
SdwaSelector sdwa_sel = SdwaSelector::Invalid;
u32 code = 0xFFFFFFFF;
};
@ -219,6 +240,51 @@ union InstControl {
InstControlEXP exp;
};
struct SdwaVopc {
u32 src0 : 8;
u32 dst_sel : 3;
u32 dst_u : 2;
u32 clamp : 1;
u32 omod : 2;
u32 src0_sel : 3;
u32 src0_sext : 1;
u32 src0_neg : 1;
u32 src0_abs : 1;
u32 : 1;
u32 s0 : 1;
u32 src1_sel : 3;
u32 src1_sext : 1;
u32 src1_neg : 1;
u32 src1_abs : 1;
u32 : 1;
u32 s1 : 1;
};
struct SdwaVop12 {
u32 src0 : 8;
u32 sdst : 7;
u32 sd : 1;
u32 src0_sel : 3;
u32 src0_sext : 1;
u32 src0_neg : 1;
u32 src0_abs : 1;
u32 : 1;
u32 s0 : 1;
u32 src1_sel : 3;
u32 src1_sext : 1;
u32 src1_neg : 1;
u32 src1_abs : 1;
u32 : 1;
u32 s1 : 1;
};
union Sdwa {
SdwaVopc vopc;
SdwaVop12 vop12;
};
struct GcnInst {
Opcode opcode;
InstEncoding encoding;

View File

@ -2448,6 +2448,9 @@ enum class OperandField : u32 {
ConstFloatNeg_2_0,
ConstFloatPos_4_0,
ConstFloatNeg_4_0,
Inv2Pi,
Sdwa,
Dpp,
VccZ = 251,
ExecZ = 252,
Scc = 253,

View File

@ -4,6 +4,7 @@
#include "common/io_file.h"
#include "common/path_util.h"
#include "core/emulator_settings.h"
#include "core/libraries/kernel/process.h"
#include "shader_recompiler/frontend/decode.h"
#include "shader_recompiler/frontend/fetch_shader.h"
#include "shader_recompiler/frontend/translate/translate.h"
@ -15,6 +16,7 @@
#include "shader_recompiler/runtime_info.h"
#include "video_core/amdgpu/resource.h"
#include <numbers>
#define MAGIC_ENUM_RANGE_MIN 0
#define MAGIC_ENUM_RANGE_MAX 1515
#include <magic_enum/magic_enum.hpp>
@ -334,6 +336,13 @@ T Translator::GetSrc(const InstOperand& operand) {
case OperandField::ConstFloatNeg_4_0:
value = get_imm(-4.0f);
break;
case OperandField::Inv2Pi:
value = get_imm(static_cast<float>(1.0f / (2.0f * std::numbers::pi)));
break;
case OperandField::Sdwa:
UNREACHABLE_MSG("unhandled SDWA");
case OperandField::Dpp:
UNREACHABLE_MSG("unhandled DPP");
case OperandField::VccLo:
if constexpr (is_float) {
value = ir.BitCast<IR::F32>(ir.GetVccLo());
@ -363,7 +372,7 @@ T Translator::GetSrc(const InstOperand& operand) {
}
break;
default:
UNREACHABLE();
UNREACHABLE_MSG("unexpected operand: {}", std::to_underlying(operand.field));
}
if constexpr (is_float) {