shader: share formatted stores for GPU-selected signed byte records

This commit is contained in:
nmzik
2026-10-14 17:10:02 +02:00
parent 04cb4c6553
commit 6d6da57a95
5 changed files with 329 additions and 38 deletions
@@ -400,7 +400,8 @@ public:
std::vector<std::pair<const IndirectDescriptorPlan*, Value>> buffer_selections;
for (const auto& plan: m_indirect_descriptors) {
auto key = plan.key;
if (m_sources[plan.source].indirect_descriptor->table_maximum) {
if (m_sources[plan.source].indirect_descriptor->table_maximum &&
plan.handle->GetOpcode() != ValueOpcode::GetBufferResource) {
auto* block = plan.handle->Parent();
const auto where = std::ranges::find_if(block->Instructions(),
[&](const Inst& inst) { return &inst == plan.handle; });
@@ -481,7 +482,10 @@ public:
const auto where = std::ranges::find_if(block->Instructions(),
[&](const Inst& inst) { return &inst == anchor; });
const auto& indirect = *m_sources[plan.source].indirect_descriptor;
if (indirect.table_scalar) {
if (indirect.table_maximum) {
key = Value(&*block->PrependNewInst(
where, ValueOpcode::ShiftLeftLogical32, {key, Value(2u)}));
} else if (indirect.table_scalar) {
// Wrapped affine offsets span one power-of-two congruence class.
// Keep the existing mapping's byte key while compressing its empty gaps.
key = plan.reads[0]->Arg(1);
@@ -508,7 +512,7 @@ public:
plan.handle->SetArg(dword, plan.key);
}
}
if (plan.reads[0] != nullptr) {
if (plan.reads[0] != nullptr && !plan.retain_reads) {
for (uint32_t word = 0; word < plan.handle->NumArgs(); ++word)
m_program.memory_info[plan.memory[word]].planning_only = true;
}
@@ -2713,7 +2717,7 @@ private:
return !IndirectBufferAccess(*consumer.user);
});
})) {
return false;
plan.retain_reads = true;
}
plan.memory[dword] = memory_index;
plan.reads[dword] = read;
@@ -2725,6 +2729,15 @@ private:
return true;
}
bool SetExactTableMaximum(Value key, DescriptorSource::IndirectDescriptor& indirect) {
const auto maximum = SelectorMaximum(key);
if (maximum > UINT32_MAX / 4u ||
uint64_t {maximum} * indirect.table_stride + indirect.table_offset > UINT32_MAX)
return false;
indirect.table_maximum = maximum;
return true;
}
bool TryMakeNestedDescriptor(Inst& handle, const DescriptorSource& descriptor,
IndirectDescriptorPlan& plan) {
if (handle.GetOpcode() != ValueOpcode::GetImageResource &&
@@ -2769,9 +2782,7 @@ private:
DescriptorSource::IndirectDescriptor indirect;
if (!MatchTableOffset(low->Arg(1), key, indirect.table_offset, indirect.table_stride) ||
indirect.table_stride < 8u || (indirect.table_stride & 3u) != 0u) return false;
const auto maximum = SelectorMaximum(key);
if (maximum > UINT32_MAX / 4u ||
uint64_t {maximum} * indirect.table_stride + indirect.table_offset > UINT32_MAX ||
if (!SetExactTableMaximum(key, indirect) ||
(key.TryInstruction() != nullptr && !AvailableBefore(*key.Instruction(), handle)))
return false;
DescriptorSource table_source;
@@ -2780,7 +2791,6 @@ private:
indirect.table_source = InternSource(table_source);
indirect.table_immediate = low_memory->offset & ~3u;
indirect.table_scalar = true;
indirect.table_maximum = maximum;
indirect.pointer_offset = descriptor_offset;
DescriptorSource source;
source.dword_count = handle.NumArgs();
@@ -3007,6 +3017,11 @@ private:
indirect.signed_count = bound->GetOpcode() == ValueOpcode::SLessThan32;
return finish();
}
if (table_source.dword_count == 4u && !plan.split_offsets &&
plan.selection_anchor != nullptr && SetExactTableMaximum(key, indirect)) {
indirect.table_scalar = true;
return finish();
}
if (!legacy_store) {
// A bounded V# supplies every reachable descriptor without reading the GPU key.
// Separate U32 offsets could wrap each DWORD to a different table position.
@@ -3300,7 +3315,7 @@ private:
bool IsIndirectPlanningMemory(uint32_t index) const {
return std::any_of(m_indirect_descriptors.begin(), m_indirect_descriptors.end(),
[&](const IndirectDescriptorPlan& plan) {
return plan.reads[0] != nullptr &&
return plan.reads[0] != nullptr && !plan.retain_reads &&
std::find(plan.memory.begin(), plan.memory.begin() + plan.handle->NumArgs(), index) !=
plan.memory.begin() + plan.handle->NumArgs();
});