mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 05:46:56 +01: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 =
|
const auto selected_mask_valid =
|
||||||
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1,
|
IR::U1(ir.Emit(IR::ValueOpcode::SelectU1,
|
||||||
{condition, ReadMaskValid(inst.src0), ReadMaskValid(false_source)}));
|
{condition, ReadMaskValid(inst.src0), ReadMaskValid(false_source)}));
|
||||||
if (IsExecOrVcc(inst.dst)) {
|
|
||||||
WriteMask(inst.dst, selected_mask, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
WriteU32Pair(inst.dst,
|
WriteU32Pair(inst.dst,
|
||||||
{ir.Select(condition, lhs[0], rhs[0]), ir.Select(condition, lhs[1], rhs[1])});
|
{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);
|
const auto dst = static_cast<IR::ScalarReg>(inst.dst.reg);
|
||||||
ir.SetThreadBitScalarReg(dst, selected_mask);
|
ir.SetThreadBitScalarReg(dst, selected_mask);
|
||||||
ir.SetScalarMaskTag(dst, selected_mask_valid);
|
ir.SetScalarMaskTag(dst, selected_mask_valid);
|
||||||
|
|||||||
@@ -20020,10 +20020,13 @@ TestCase ScalarMaskHighWriteInvalidatesProvenance() {
|
|||||||
O::S_ENDPGM}};
|
O::S_ENDPGM}};
|
||||||
}
|
}
|
||||||
|
|
||||||
TestCase ScalarSelectB64PreservesMaskProvenance() {
|
TestCase ScalarSelectB64PreservesMaskProvenance(u32 wave_size) {
|
||||||
using O = ShaderOpcode;
|
using O = ShaderOpcode;
|
||||||
|
|
||||||
std::vector<u32> code;
|
TestCase test;
|
||||||
|
test.name = wave_size == 32 ? "ScalarSelectB64PreservesMaskProvenanceWave32"
|
||||||
|
: "ScalarSelectB64PreservesMaskProvenanceWave64";
|
||||||
|
auto &code = test.code;
|
||||||
const auto set_scc = [&] {
|
const auto set_scc = [&] {
|
||||||
code.push_back(EncodeSopc(0x06, InlineU32(1), InlineU32(1)));
|
code.push_back(EncodeSopc(0x06, InlineU32(1), InlineU32(1)));
|
||||||
};
|
};
|
||||||
@@ -20040,24 +20043,53 @@ TestCase ScalarSelectB64PreservesMaskProvenance() {
|
|||||||
code.push_back(EncodeSop1(0x08, 6, 4));
|
code.push_back(EncodeSop1(0x08, 6, 4));
|
||||||
capture_scc(8);
|
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));
|
code.push_back(EncodeSop1(0x04, 10, 106));
|
||||||
set_scc();
|
set_scc();
|
||||||
code.push_back(EncodeSop2(0x0b, 12, 10, 2));
|
code.push_back(EncodeSop2(0x0b, 12, 10, 2));
|
||||||
code.push_back(EncodeSop1(0x08, 14, 12));
|
code.push_back(EncodeSop1(0x08, 14, 12));
|
||||||
capture_scc(16);
|
capture_scc(16);
|
||||||
|
|
||||||
AppendStoreSgpr(&code, 8, 0);
|
AppendStoreSgprAtLaneDwordOffset(&code, 8, 0, 0);
|
||||||
AppendStoreSgpr(&code, 16, 1);
|
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);
|
AppendEnd(&code);
|
||||||
|
|
||||||
return {"ScalarSelectB64PreservesMaskProvenance",
|
test.initial.assign(test.expected.size(), 0xdeadbeefu);
|
||||||
code,
|
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,
|
||||||
{1, 1},
|
O::V_LSHLREV_B32, O::V_ADD_NC_U32, O::BUFFER_STORE_DWORD, O::S_ENDPGM};
|
||||||
{O::S_MOV_B32, O::S_CMP_EQ_U32, O::S_CSELECT_B64, O::S_NOT_B64,
|
test.compute_info.threads_num[0] = wave_size;
|
||||||
O::S_CSELECT_B32, O::V_CMP_EQ_U32, O::S_MOV_B64, O::V_MOV_B32,
|
test.compute_info.threads_num[1] = test.compute_info.threads_num[2] = 1;
|
||||||
O::BUFFER_STORE_DWORD, O::S_ENDPGM}};
|
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) {
|
TestCase ScalarWqmB32Masks(u32 wave_size) {
|
||||||
@@ -33077,7 +33109,8 @@ std::vector<TestCase> MakeCases() {
|
|||||||
AddCase(ScalarConditionalMoveB64PreservesMasks);
|
AddCase(ScalarConditionalMoveB64PreservesMasks);
|
||||||
AddCase(ScalarAndn2B64SccUsesMaskShadow);
|
AddCase(ScalarAndn2B64SccUsesMaskShadow);
|
||||||
AddCase(ScalarMaskHighWriteInvalidatesProvenance);
|
AddCase(ScalarMaskHighWriteInvalidatesProvenance);
|
||||||
AddCase(ScalarSelectB64PreservesMaskProvenance);
|
cases.push_back(ScalarSelectB64PreservesMaskProvenance(32));
|
||||||
|
cases.push_back(ScalarSelectB64PreservesMaskProvenance(64));
|
||||||
AddCase(ScalarWqmB64SelectsSccDomain);
|
AddCase(ScalarWqmB64SelectsSccDomain);
|
||||||
AddCase(ScalarWqmB64PreservesPartialMasks);
|
AddCase(ScalarWqmB64PreservesPartialMasks);
|
||||||
cases.push_back(ScalarWqmB32Masks(32));
|
cases.push_back(ScalarWqmB32Masks(32));
|
||||||
@@ -38629,7 +38662,8 @@ int main(int argc, char **argv) {
|
|||||||
RunCase(&vulkan, ScalarSubvectorLoops(32));
|
RunCase(&vulkan, ScalarSubvectorLoops(32));
|
||||||
RunCase(&vulkan, ScalarSubvectorLoops(64));
|
RunCase(&vulkan, ScalarSubvectorLoops(64));
|
||||||
RunCase(&vulkan, ScalarNotB64UpdatesScc());
|
RunCase(&vulkan, ScalarNotB64UpdatesScc());
|
||||||
RunCase(&vulkan, ScalarSelectB64PreservesMaskProvenance());
|
RunCase(&vulkan, ScalarSelectB64PreservesMaskProvenance(32));
|
||||||
|
RunCase(&vulkan, ScalarSelectB64PreservesMaskProvenance(64));
|
||||||
RunCase(&vulkan, ScalarConditionalMoveB64());
|
RunCase(&vulkan, ScalarConditionalMoveB64());
|
||||||
RunCase(&vulkan, ScalarConditionalMoveB64PreservesMasks());
|
RunCase(&vulkan, ScalarConditionalMoveB64PreservesMasks());
|
||||||
RunCase(&vulkan, ScalarWqmB64SelectsSccDomain());
|
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() {
|
void TestNativeGuardedSamplerSource() {
|
||||||
constexpr uint32_t nested = 12, sample = 18, join = 20, end = 22;
|
constexpr uint32_t nested = 12, sample = 18, join = 20, end = 22;
|
||||||
const uint32_t shader[] = {
|
const uint32_t shader[] = {
|
||||||
@@ -14682,6 +14722,7 @@ int main() {
|
|||||||
TestSharedExitPreservesNativeDescriptorSources();
|
TestSharedExitPreservesNativeDescriptorSources();
|
||||||
TestNestedSelectionPreservesDescriptorSources();
|
TestNestedSelectionPreservesDescriptorSources();
|
||||||
TestNativeScalarReadDescriptorPlanning();
|
TestNativeScalarReadDescriptorPlanning();
|
||||||
|
TestScalarSelectedVccBufferAddress();
|
||||||
TestNativeGuardedSamplerSource();
|
TestNativeGuardedSamplerSource();
|
||||||
for (const bool scalar_key : {false, true}) TestBoundedMaterialBufferStores(scalar_key);
|
for (const bool scalar_key : {false, true}) TestBoundedMaterialBufferStores(scalar_key);
|
||||||
TestNativeDescriptorProvenanceKeepsGpuSelection();
|
TestNativeDescriptorProvenanceKeepsGpuSelection();
|
||||||
|
|||||||
Reference in New Issue
Block a user