mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 11:26:56 +02:00
shader: preserve raw EXEC and VCC bits in 64-bit scalar selects
This commit is contained in:
@@ -256,13 +256,14 @@ void Translator::ScalarSelect64(const Decoder::Instruction& inst,
|
||||
const auto selected_mask_valid =
|
||||
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1,
|
||||
{condition, ReadMaskValid(inst.src0), ReadMaskValid(false_source)}));
|
||||
if (IsExecOrVcc(inst.dst)) {
|
||||
WriteMask(inst.dst, selected_mask, true);
|
||||
return;
|
||||
}
|
||||
WriteU32Pair(inst.dst,
|
||||
{ir.Select(condition, lhs[0], rhs[0]), ir.Select(condition, lhs[1], rhs[1])});
|
||||
if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
|
||||
// Scalar selects preserve the raw pair even when EXEC/VCC holds an address.
|
||||
if (inst.dst.kind == Decoder::OperandKind::ExecLo) {
|
||||
ir.SetExec(selected_mask);
|
||||
} else if (inst.dst.kind == Decoder::OperandKind::VccLo) {
|
||||
ir.SetVcc(selected_mask);
|
||||
} else if (inst.dst.kind == Decoder::OperandKind::Sgpr) {
|
||||
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
|
||||
ir.SetThreadBitScalarReg(dst, selected_mask);
|
||||
ir.SetScalarMaskTag(dst, selected_mask_valid);
|
||||
|
||||
@@ -20020,10 +20020,13 @@ TestCase ScalarMaskHighWriteInvalidatesProvenance() {
|
||||
O::S_ENDPGM}};
|
||||
}
|
||||
|
||||
TestCase ScalarSelectB64PreservesMaskProvenance() {
|
||||
TestCase ScalarSelectB64PreservesMaskProvenance(u32 wave_size) {
|
||||
using O = ShaderOpcode;
|
||||
|
||||
std::vector<u32> code;
|
||||
TestCase test;
|
||||
test.name = wave_size == 32 ? "ScalarSelectB64PreservesMaskProvenanceWave32"
|
||||
: "ScalarSelectB64PreservesMaskProvenanceWave64";
|
||||
auto &code = test.code;
|
||||
const auto set_scc = [&] {
|
||||
code.push_back(EncodeSopc(0x06, InlineU32(1), InlineU32(1)));
|
||||
};
|
||||
@@ -20040,24 +20043,53 @@ TestCase ScalarSelectB64PreservesMaskProvenance() {
|
||||
code.push_back(EncodeSop1(0x08, 6, 4));
|
||||
capture_scc(8);
|
||||
|
||||
code.push_back(EncodeVopc(0xc2, Vgpr(0), 0));
|
||||
code.push_back(EncodeVopc(0xc2, InlineU32(0), 0)); // Only lane zero is set.
|
||||
code.push_back(EncodeSop1(0x04, 10, 106));
|
||||
set_scc();
|
||||
code.push_back(EncodeSop2(0x0b, 12, 10, 2));
|
||||
code.push_back(EncodeSop1(0x08, 14, 12));
|
||||
capture_scc(16);
|
||||
|
||||
AppendStoreSgpr(&code, 8, 0);
|
||||
AppendStoreSgpr(&code, 16, 1);
|
||||
AppendStoreSgprAtLaneDwordOffset(&code, 8, 0, 0);
|
||||
AppendStoreSgprAtLaneDwordOffset(&code, 16, 0, wave_size);
|
||||
test.expected.assign(2u * wave_size, 1u);
|
||||
code.push_back(EncodeSop1(0x04, 16, 126)); // Save full EXEC.
|
||||
AppendVMovU32(&code, 2, 9);
|
||||
constexpr std::array<uint32_t, 4> words{
|
||||
0x5aa55aa5u, 0xc39ac39au, 0xa55aa55au, 0x3c653c65u};
|
||||
for (u32 i = 0; i < words.size(); ++i) AppendSMovLiteral(&code, i, words[i]);
|
||||
for (const u32 destination : {106u, 126u}) {
|
||||
for (const u32 scc : {0u, 1u}) {
|
||||
code.push_back(EncodeSopc(0x06, InlineU32(scc), InlineU32(1)));
|
||||
code.push_back(EncodeSop2(0x0b, destination, 0, 2));
|
||||
code.push_back(EncodeSop1(0x04, 8, destination)); // Preserve both raw words.
|
||||
code.push_back(EncodeSop1(0x04, 126, destination));
|
||||
AppendStoreVgprAtLaneDwordOffset(&code, 2, 0,
|
||||
static_cast<u32>(test.expected.size()));
|
||||
const u32 selected = scc ? 0u : 2u;
|
||||
for (u32 lane = 0; lane < wave_size; ++lane)
|
||||
test.expected.push_back((words[selected + lane / 32u] >> (lane & 31u)) & 1u
|
||||
? 9u : 0xdeadbeefu);
|
||||
code.push_back(EncodeSop1(0x04, 126, 16));
|
||||
for (u32 component = 0; component < 2; ++component) {
|
||||
AppendStoreSgprAtLaneDwordOffset(&code, 8 + component, 0,
|
||||
static_cast<u32>(test.expected.size()));
|
||||
test.expected.insert(test.expected.end(), wave_size, words[selected + component]);
|
||||
}
|
||||
}
|
||||
}
|
||||
AppendEnd(&code);
|
||||
|
||||
return {"ScalarSelectB64PreservesMaskProvenance",
|
||||
code,
|
||||
{},
|
||||
{1, 1},
|
||||
{O::S_MOV_B32, O::S_CMP_EQ_U32, O::S_CSELECT_B64, O::S_NOT_B64,
|
||||
O::S_CSELECT_B32, O::V_CMP_EQ_U32, O::S_MOV_B64, O::V_MOV_B32,
|
||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
||||
test.initial.assign(test.expected.size(), 0xdeadbeefu);
|
||||
test.opcodes = {O::S_MOV_B32, O::S_CMP_EQ_U32, O::S_CSELECT_B64, O::S_NOT_B64,
|
||||
O::S_CSELECT_B32, O::V_CMP_EQ_U32, O::S_MOV_B64, O::V_MOV_B32,
|
||||
O::V_LSHLREV_B32, O::V_ADD_NC_U32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||
test.compute_info.threads_num[0] = wave_size;
|
||||
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
|
||||
test.compute_info.thread_ids_num = 1;
|
||||
test.compute_info.wave_size = wave_size;
|
||||
test.has_compute_info = true;
|
||||
return test;
|
||||
}
|
||||
|
||||
TestCase ScalarWqmB32Masks(u32 wave_size) {
|
||||
@@ -33077,7 +33109,8 @@ std::vector<TestCase> MakeCases() {
|
||||
AddCase(ScalarConditionalMoveB64PreservesMasks);
|
||||
AddCase(ScalarAndn2B64SccUsesMaskShadow);
|
||||
AddCase(ScalarMaskHighWriteInvalidatesProvenance);
|
||||
AddCase(ScalarSelectB64PreservesMaskProvenance);
|
||||
cases.push_back(ScalarSelectB64PreservesMaskProvenance(32));
|
||||
cases.push_back(ScalarSelectB64PreservesMaskProvenance(64));
|
||||
AddCase(ScalarWqmB64SelectsSccDomain);
|
||||
AddCase(ScalarWqmB64PreservesPartialMasks);
|
||||
cases.push_back(ScalarWqmB32Masks(32));
|
||||
@@ -38629,7 +38662,8 @@ int main(int argc, char **argv) {
|
||||
RunCase(&vulkan, ScalarSubvectorLoops(32));
|
||||
RunCase(&vulkan, ScalarSubvectorLoops(64));
|
||||
RunCase(&vulkan, ScalarNotB64UpdatesScc());
|
||||
RunCase(&vulkan, ScalarSelectB64PreservesMaskProvenance());
|
||||
RunCase(&vulkan, ScalarSelectB64PreservesMaskProvenance(32));
|
||||
RunCase(&vulkan, ScalarSelectB64PreservesMaskProvenance(64));
|
||||
RunCase(&vulkan, ScalarConditionalMoveB64());
|
||||
RunCase(&vulkan, ScalarConditionalMoveB64PreservesMasks());
|
||||
RunCase(&vulkan, ScalarWqmB64SelectsSccDomain());
|
||||
|
||||
@@ -8849,6 +8849,46 @@ void TestNativeScalarReadDescriptorPlanning() {
|
||||
}
|
||||
}
|
||||
|
||||
void TestScalarSelectedVccBufferAddress() {
|
||||
using namespace ShaderRecompiler::IR;
|
||||
// 68ca7b6fd9c44cfa selects an ordinary 64-bit address through VCC before
|
||||
// copying its words into a writable buffer descriptor.
|
||||
const uint32_t shader[] = {
|
||||
EncodeSopc(0x07, 4, 128), EncodeSop2(0x0b, 106, 0, 2),
|
||||
EncodeVop1(0x01, 1, 106), EncodeVop1(0x02, 8, 257),
|
||||
EncodeSMovB32(9, 107), EncodeSMovB32(10, 132),
|
||||
EncodeSMovB32(11, 255), 3u << 28u,
|
||||
EncodeMubuf0(0x1c, 0, false), EncodeMubuf1(0, 2, 0),
|
||||
EncodeSopp(0x01),
|
||||
};
|
||||
std::array<uint32_t, 5> userdata{0x12345670u, 0x12u, 0xb27c0000u, 0x30u, 0u};
|
||||
for (const uint32_t wave_size : {32u, 64u}) {
|
||||
auto options = MakeCompileOptions(ShaderType::Compute);
|
||||
auto input = *options.input_info.compute;
|
||||
input.threads_num[0] = input.wave_size = options.wave_size = wave_size;
|
||||
options.input_info.compute = &input;
|
||||
options.user_data = userdata;
|
||||
auto translated = ShaderRecompiler::TranslateProgram(shader, options);
|
||||
auto plan = ExtractResourcePlan(translated.program);
|
||||
ResourceSnapshot snapshot;
|
||||
ResourceSpecialization specialization;
|
||||
for (const uint32_t condition : {0u, 1u}) {
|
||||
userdata[4] = condition;
|
||||
Check(MaterializeResources(plan, {.user_data = userdata}, snapshot, specialization),
|
||||
"scalar-selected VCC address did not materialize");
|
||||
const auto offset = condition ? 0u : 2u;
|
||||
Check(snapshot.buffers.size() == 1 && snapshot.flattened_srt.empty() &&
|
||||
snapshot.specialization_reads.empty() &&
|
||||
snapshot.buffers[0].dwords[0] == userdata[offset] &&
|
||||
snapshot.buffers[0].dwords[1] == userdata[offset + 1],
|
||||
"VCC selection replaced raw address words with a lane ballot");
|
||||
}
|
||||
const auto compiled = ShaderRecompiler::CompileProgram(
|
||||
std::move(translated), options, specialization);
|
||||
CheckSpirvBinaryValidates(compiled.spirv);
|
||||
}
|
||||
}
|
||||
|
||||
void TestNativeGuardedSamplerSource() {
|
||||
constexpr uint32_t nested = 12, sample = 18, join = 20, end = 22;
|
||||
const uint32_t shader[] = {
|
||||
@@ -14682,6 +14722,7 @@ int main() {
|
||||
TestSharedExitPreservesNativeDescriptorSources();
|
||||
TestNestedSelectionPreservesDescriptorSources();
|
||||
TestNativeScalarReadDescriptorPlanning();
|
||||
TestScalarSelectedVccBufferAddress();
|
||||
TestNativeGuardedSamplerSource();
|
||||
for (const bool scalar_key : {false, true}) TestBoundedMaterialBufferStores(scalar_key);
|
||||
TestNativeDescriptorProvenanceKeepsGpuSelection();
|
||||
|
||||
Reference in New Issue
Block a user