Skip to content
Open

SDWA #4203

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions src/shader_recompiler/frontend/decode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -431,6 +432,78 @@ 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) {
ASSERT_MSG(Libraries::Kernel::sceKernelIsNeoMode(), "SDWA is not supported in Base mode");

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 : OperandField::ScalarGPR;
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 : OperandField::ScalarGPR;
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 : OperandField::ScalarGPR;
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 : OperandField::ScalarGPR;
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 = OperandField::ScalarGPR;
m_instruction.dst[0].code = sdwa.sdst;
} else {
UNREACHABLE_MSG("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);
Expand Down
1 change: 1 addition & 0 deletions src/shader_recompiler/frontend/decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ class GcnDecodeContext {
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);
Expand Down
66 changes: 66 additions & 0 deletions src/shader_recompiler/frontend/instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -41,13 +42,33 @@ 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;
InputModifiers input_modifier = {};
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;
};

Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions src/shader_recompiler/frontend/opcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
20 changes: 18 additions & 2 deletions src/shader_recompiler/frontend/translate/translate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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>
Expand Down Expand Up @@ -339,8 +341,22 @@ T Translator::GetSrc(const InstOperand& operand) {
value = ir.BitCast<IR::U32>(ir.GetScc());
}
break;
default:
UNREACHABLE();
default: {
if (Libraries::Kernel::sceKernelIsNeoMode()) {
switch (operand.field) {
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");
default:
break;
}
}
UNREACHABLE_MSG("unexpected operand: {}", std::to_underlying(operand.field));
}
}

if constexpr (is_float) {
Expand Down
Loading