shader: support S_QUADMASK_B32

This commit is contained in:
nmzik
2026-10-28 22:31:16 +01:00
parent 963aaeb3b6
commit 138d5b86c4
8 changed files with 69 additions and 9 deletions
+2
View File
@@ -694,6 +694,8 @@ if(BUILD_TESTING)
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --float-min-max-only)
add_test(NAME shader_recompiler_vop3_conversions
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --vop3-conversions-only)
add_test(NAME shader_recompiler_quadmask
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --quadmask-only)
add_test(NAME shader_recompiler_alignbyte
COMMAND $<TARGET_FILE:shader_recompiler_compute_tests> --alignbyte-only)
add_test(NAME graphics_pipeline_rasterization
@@ -70,6 +70,7 @@ constexpr OpcodeMap SOP1_OPCODE_LIST[] = {
{0x21u, Opcode::S_SWAPPC_B64},
{0x24u, Opcode::S_AND_SAVEEXEC_B64},
{0x28u, Opcode::S_ORN2_SAVEEXEC_B64},
{0x2cu, Opcode::S_QUADMASK_B32},
{0x2du, Opcode::S_QUADMASK_B64},
{0x34u, Opcode::S_ABS_I32},
{0x37u, Opcode::S_ANDN1_SAVEEXEC_B64},
@@ -517,6 +517,7 @@ std::string InstructionToString(const Instruction& inst) {
case Opcode::S_NOT_B64:
case Opcode::S_WQM_B32:
case Opcode::S_WQM_B64:
case Opcode::S_QUADMASK_B32:
case Opcode::S_QUADMASK_B64:
case Opcode::S_AND_SAVEEXEC_B32:
case Opcode::S_ORN2_SAVEEXEC_B32:
@@ -63,6 +63,7 @@ enum class Opcode {
S_FLBIT_I32,
S_FLBIT_I32_I64,
S_BITREPLICATE_B64_B32,
S_QUADMASK_B32,
S_QUADMASK_B64,
S_GETPC_B64,
S_SETPC_B64,
@@ -375,7 +375,7 @@ void Translator::S_BITREPLICATE_B64_B32(const Decoder::Instruction& inst) {
WriteOperand(DestinationOperand(inst), ir.ConstructU64(replicate(low), replicate(high)));
}
void Translator::S_QUADMASK_B64(const Decoder::Instruction& inst) {
void Translator::S_QUADMASK(const Decoder::Instruction& inst, bool is64) {
const auto compact = [&](IR::U32 value) {
auto bits = ir.BitwiseOr(value, ir.ShiftRightLogical(value, IR::U32(IR::Value(1u))));
bits = ir.BitwiseOr(bits, ir.ShiftRightLogical(bits, IR::U32(IR::Value(2u))));
@@ -388,12 +388,17 @@ void Translator::S_QUADMASK_B64(const Decoder::Instruction& inst) {
ir.BitwiseOr(bits, ir.ShiftRightLogical(bits, IR::U32(IR::Value(12u)))),
IR::U32(IR::Value(0xffu)));
};
IR::U32 quads;
if (is64) {
const auto source = ReadU32Pair(inst.src0);
const auto quads = ir.BitwiseOr(
quads = ir.BitwiseOr(
compact(source[0]), ir.ShiftLeftLogical(compact(source[1]), IR::U32(IR::Value(8u))));
const auto result = ir.ConstructU64(quads, IR::U32(IR::Value(0u)));
WriteOperand(DestinationOperand(inst), result);
ir.SetScc(IR::U1(ir.Emit(IR::ValueOpcode::INotEqual64, {result, IR::Value(uint64_t {0})})));
WriteOperand(DestinationOperand(inst), ir.ConstructU64(quads, IR::U32(IR::Value(0u))));
} else {
quads = compact(ReadU32(inst.src0));
WriteOperand(DestinationOperand(inst), quads);
}
ir.SetScc(ir.INotEqual(quads, IR::U32(IR::Value(0u))));
}
void Translator::BFM_B32(const Decoder::Instruction& inst) {
@@ -248,7 +248,8 @@ void Translator::EmitScalar(const Decoder::Instruction& inst) {
case O::S_BITSET0_B64: return S_BITSET_B64(inst, false);
case O::S_BITSET1_B64: return S_BITSET_B64(inst, true);
case O::S_BITREPLICATE_B64_B32: return S_BITREPLICATE_B64_B32(inst);
case O::S_QUADMASK_B64: return S_QUADMASK_B64(inst);
case O::S_QUADMASK_B32: return S_QUADMASK(inst, false);
case O::S_QUADMASK_B64: return S_QUADMASK(inst, true);
case O::S_BFM_B32: return BFM_B32(inst);
case O::S_BFM_B64: return S_BFM_B64(inst);
case O::S_BFE_U32: return S_BFE_U32(inst, false);
@@ -196,7 +196,7 @@ private:
void V_BCNT_U32_B32(const Decoder::Instruction& inst);
void V_MBCNT_U32_B32(const Decoder::Instruction& inst, bool low);
void S_BITREPLICATE_B64_B32(const Decoder::Instruction& inst);
void S_QUADMASK_B64(const Decoder::Instruction& inst);
void S_QUADMASK(const Decoder::Instruction& inst, bool is64);
void BFM_B32(const Decoder::Instruction& inst);
IR::U32 RightMask32(IR::U32 count);
void S_BFM_B64(const Decoder::Instruction& inst);
+49
View File
@@ -23748,6 +23748,46 @@ TestCase ScalarNotB64UpdatesScc() {
O::S_ENDPGM}};
}
TestCase ScalarQuadmaskB32(u32 wave_size) {
using O = ShaderOpcode;
TestCase test;
test.name = wave_size == 32 ? "ScalarQuadmaskB32Wave32" : "ScalarQuadmaskB32Wave64";
test.initial = {0, 0xffffffffu, 0x80000011u, 0x01010101u};
for (u32 bit = 0; bit < 32; ++bit) test.initial.push_back(1u << bit);
test.expected = test.initial;
auto &code = test.code;
for (u32 i = 0; i < test.initial.size(); ++i) {
u32 quads = 0;
for (u32 q = 0; q < 8; ++q) {
if ((test.initial[i] >> (4 * q)) & 15u) quads |= 1u << q;
}
AppendVMovU32(&code, 30, i * sizeof(u32));
AppendBufferLoadDword(&code, 2, 30);
for (u32 dst : {12u, 106u}) {
code.push_back(EncodeVop1(0x02, dst, Vgpr(2)));
AppendSMovLiteral(&code, dst + 1, 0xdeadbeefu);
code.push_back(EncodeSopc(0x06, InlineU32(quads == 0), InlineU32(1)));
code.push_back(EncodeSop1(0x2c, dst, dst));
code.push_back(EncodeSop2(0x0a, 14, InlineU32(1), InlineU32(0)));
AppendStoreSgpr(&code, dst, static_cast<u32>(test.expected.size()));
AppendStoreSgpr(&code, dst + 1, static_cast<u32>(test.expected.size()) + 1);
AppendStoreSgpr(&code, 14, static_cast<u32>(test.expected.size()) + 2);
test.expected.insert(test.expected.end(), {quads, 0xdeadbeefu, quads != 0});
}
}
code.push_back(EncodeSop1(0x2c, 12, 255));
code.push_back(0x000f000fu);
AppendStoreSgpr(&code, 12, static_cast<u32>(test.expected.size()));
test.expected.push_back(0x11u);
AppendEnd(&code);
test.opcodes = {O::S_QUADMASK_B32, O::S_CMP_EQ_U32, O::S_CSELECT_B32, O::S_MOV_B32,
O::V_READFIRSTLANE_B32, O::V_MOV_B32, O::BUFFER_LOAD_DWORD,
O::BUFFER_STORE_DWORD, O::S_ENDPGM};
test.compute_info.wave_size = wave_size;
test.has_compute_info = true;
return test;
}
TestCase ScalarQuadmaskB64() {
using O = ShaderOpcode;
@@ -46047,6 +46087,8 @@ std::vector<TestCase> MakeCases() {
AddCase(ScalarCompareOps);
AddCase(ScalarShiftAddAndMaskOps);
AddCase(ScalarNotB64UpdatesScc);
cases.push_back(ScalarQuadmaskB32(32));
cases.push_back(ScalarQuadmaskB32(64));
AddCase(ScalarQuadmaskB64);
AddCase(ScalarFlbitI32B64Gpu);
AddCase(ScalarFlbitI32B32Gpu);
@@ -52562,6 +52604,13 @@ int main(int argc, char **argv) {
std::setvbuf(stdout, nullptr, _IONBF, 0);
EnsureConfigInitialized();
CheckLeastRecentlyUsedCacheOrdering();
if (argc == 2 && std::strcmp(argv[1], "--quadmask-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, ScalarQuadmaskB32(32));
RunCase(&vulkan, ScalarQuadmaskB32(64));
RunCase(&vulkan, ScalarQuadmaskB64());
return 0;
}
if (argc == 2 && std::strcmp(argv[1], "--vop3-conversions-only") == 0) {
VulkanHarness vulkan;
RunCase(&vulkan, Vop3FloatConversions(32));