shader: snapshot wide SMEM sources before writes

This commit is contained in:
nmzik
2026-08-15 14:09:02 +02:00
parent 28a913894d
commit f453a752bb
5 changed files with 135 additions and 46 deletions
@@ -11,14 +11,16 @@ bool Translator::TranslateU64MaskOperation(const IR::Instruction& inst) {
: TranslateComposedInteger(inst);
}
bool Translator::TranslateInstruction(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot) {
bool Translator::TranslateInstruction(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot,
const ScalarMemorySourceValues* scalar_source_snapshot) {
switch (IR::GetOpcodeInfo(inst.op).lowering_class) {
case IR::LoweringClass::Control: return TranslateControlOperation(inst);
case IR::LoweringClass::Move: return TranslateMove(inst);
case IR::LoweringClass::Lane: return TranslateLaneOperation(inst);
case IR::LoweringClass::State: return TranslateStateOperation(inst);
case IR::LoweringClass::Memory: return TranslateMemoryOperation(inst, address_snapshot);
case IR::LoweringClass::Memory:
return TranslateMemoryOperation(inst, address_snapshot, scalar_source_snapshot);
case IR::LoweringClass::Attribute: return TranslateAttributeOperation(inst);
case IR::LoweringClass::IntegerCompare: return TranslateIntegerCompare(inst);
case IR::LoweringClass::Integer16Compare: return TranslateInteger16Compare(inst);
@@ -207,7 +207,19 @@ bool Translator::IsBufferLoadOperation(IR::Opcode opcode) {
opcode == IR::Opcode::BufferLoadDword;
}
bool Translator::TranslateScalarMemory(const IR::Instruction& inst) {
bool Translator::IsScalarMemoryLoadOperation(IR::Opcode opcode) {
return opcode == IR::Opcode::SLoadDword || opcode == IR::Opcode::SBufferLoadDword;
}
ScalarMemorySourceValues Translator::ReadScalarMemorySource(const IR::Instruction& inst) {
const auto resource = inst.op == IR::Opcode::SLoadDword
? GetScalarAddressResource(inst.memory.resource)
: GetBufferResource(inst.memory);
return {resource, ReadU32(inst.src[0])};
}
bool Translator::TranslateScalarMemory(const IR::Instruction& inst,
const ScalarMemorySourceValues* source_snapshot) {
switch (inst.op) {
case IR::Opcode::LoadSrtDword: {
const auto resource = ir.Emit(IR::ValueOpcode::GetSrtResource);
@@ -216,16 +228,18 @@ bool Translator::TranslateScalarMemory(const IR::Instruction& inst) {
return true;
}
case IR::Opcode::SBufferLoadDword: {
const auto resource = GetBufferResource(inst.memory);
const auto source =
source_snapshot != nullptr ? *source_snapshot : ReadScalarMemorySource(inst);
WriteOperand(inst.dst, ir.Emit(IR::ValueOpcode::ReadConstBuffer,
{resource, ReadU32(inst.src[0])}, AddMemoryInfo(inst)));
{source.resource, source.offset}, AddMemoryInfo(inst)));
return true;
}
case IR::Opcode::SLoadDword: {
const auto resource = GetScalarAddressResource(inst.memory.resource);
const auto source =
source_snapshot != nullptr ? *source_snapshot : ReadScalarMemorySource(inst);
WriteOperand(inst.dst,
ir.Emit(IR::ValueOpcode::LoadAddressU32,
{resource, ReadU32(inst.src[0]), IR::Value(0u), IR::Value(true)},
{source.resource, source.offset, IR::Value(0u), IR::Value(true)},
AddMemoryInfo(inst)));
return true;
}
@@ -579,12 +593,14 @@ bool Translator::TranslateSharedMemory(const IR::Instruction& inst) {
}
}
bool Translator::TranslateMemoryOperation(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot) {
bool Translator::TranslateMemoryOperation(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot,
const ScalarMemorySourceValues* scalar_source_snapshot) {
switch (inst.op) {
case IR::Opcode::LoadSrtDword:
case IR::Opcode::SLoadDword:
case IR::Opcode::SBufferLoadDword: return TranslateScalarMemory(inst);
case IR::Opcode::SBufferLoadDword:
return TranslateScalarMemory(inst, scalar_source_snapshot);
case IR::Opcode::BufferLoadUbyte:
case IR::Opcode::BufferLoadSbyte:
@@ -671,9 +671,12 @@ void Translator::WriteCompareResult(const IR::Operand& operand, IR::U1 value) {
}
bool Translator::TranslateBlock(const IR::BasicBlock& source, std::string* error) {
BufferAddressValues buffer_address_snapshot {};
uint32_t buffer_address_pc = 0;
bool has_buffer_address_snapshot = false;
BufferAddressValues buffer_address_snapshot {};
ScalarMemorySourceValues scalar_source_snapshot {};
uint32_t buffer_address_pc = 0;
uint32_t scalar_source_pc = 0;
bool has_buffer_address_snapshot = false;
bool has_scalar_source_snapshot = false;
for (const auto& source_inst: source.instructions) {
current_opcode = source_inst.op;
current_pc = source_inst.pc;
@@ -688,11 +691,23 @@ bool Translator::TranslateBlock(const IR::BasicBlock& source, std::string* error
} else if (!grouped_buffer_load) {
has_buffer_address_snapshot = false;
}
const bool grouped_scalar_load =
IsScalarMemoryLoadOperation(source_inst.op) && source_inst.memory.component_count > 1u;
if (grouped_scalar_load &&
(!has_scalar_source_snapshot || scalar_source_pc != source_inst.pc ||
source_inst.memory.component_index == 0u)) {
scalar_source_snapshot = ReadScalarMemorySource(source_inst);
scalar_source_pc = source_inst.pc;
has_scalar_source_snapshot = true;
} else if (!grouped_scalar_load) {
has_scalar_source_snapshot = false;
}
if (static_cast<size_t>(source_inst.op) >= static_cast<size_t>(IR::Opcode::Count)) {
return Fail(error, "value IR input opcode is out of range");
}
if (TranslateInstruction(source_inst,
grouped_buffer_load ? &buffer_address_snapshot : nullptr)) {
grouped_buffer_load ? &buffer_address_snapshot : nullptr,
grouped_scalar_load ? &scalar_source_snapshot : nullptr)) {
continue;
}
return Fail(error, fmt::format("opcode {} at 0x{:08x} has no typed Value IR lowering",
@@ -13,6 +13,11 @@ struct BufferAddressValues {
IR::U32 soffset;
};
struct ScalarMemorySourceValues {
IR::Value resource;
IR::U32 offset;
};
bool Fail(std::string* error, const std::string& message);
class Translator {
@@ -80,21 +85,24 @@ private:
void WriteImageComponents(const IR::Operand& dst, IR::Value value, uint32_t dmask,
uint32_t component_limit);
IR::ValueOpcode ImageAtomicOpcode(IR::Opcode opcode);
BufferAddressValues ReadBufferAddress(const IR::Instruction& inst, uint32_t source_offset);
IR::U32 WidenSubdword(IR::Value value, uint32_t bits, bool sign);
IR::Value NarrowSubdword(IR::U32 value, uint32_t bits);
IR::ValueOpcode BufferAtomicOpcode(IR::Opcode opcode);
IR::ValueOpcode SharedAtomicOpcode(IR::Opcode opcode, bool gds);
bool IsBufferLoadOperation(IR::Opcode opcode);
bool TranslateScalarMemory(const IR::Instruction& inst);
bool TranslateBufferLoad(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot);
bool TranslateBufferStore(const IR::Instruction& inst);
bool TranslateAtomicMemory(const IR::Instruction& inst);
bool TranslateFlatLoad(const IR::Instruction& inst);
bool TranslateFlatStore(const IR::Instruction& inst);
bool TranslateImageMemory(const IR::Instruction& inst);
bool TranslateSharedMemory(const IR::Instruction& inst);
BufferAddressValues ReadBufferAddress(const IR::Instruction& inst, uint32_t source_offset);
IR::U32 WidenSubdword(IR::Value value, uint32_t bits, bool sign);
IR::Value NarrowSubdword(IR::U32 value, uint32_t bits);
IR::ValueOpcode BufferAtomicOpcode(IR::Opcode opcode);
IR::ValueOpcode SharedAtomicOpcode(IR::Opcode opcode, bool gds);
bool IsBufferLoadOperation(IR::Opcode opcode);
bool IsScalarMemoryLoadOperation(IR::Opcode opcode);
ScalarMemorySourceValues ReadScalarMemorySource(const IR::Instruction& inst);
bool TranslateScalarMemory(const IR::Instruction& inst,
const ScalarMemorySourceValues* source_snapshot);
bool TranslateBufferLoad(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot);
bool TranslateBufferStore(const IR::Instruction& inst);
bool TranslateAtomicMemory(const IR::Instruction& inst);
bool TranslateFlatLoad(const IR::Instruction& inst);
bool TranslateFlatStore(const IR::Instruction& inst);
bool TranslateImageMemory(const IR::Instruction& inst);
bool TranslateSharedMemory(const IR::Instruction& inst);
IR::F32 SelectF32(IR::U1 condition, IR::F32 true_value, IR::F32 false_value);
IR::U32 ConvertF32ToU32Saturated(IR::F32 value, float upper_bound, float safe_upper,
@@ -104,15 +112,17 @@ private:
uint32_t upper_result);
IR::U32 PackU16Lanes(IR::U32 low, IR::U32 high);
bool TranslateInstruction(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot);
bool TranslateInstruction(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot,
const ScalarMemorySourceValues* scalar_source_snapshot);
bool TranslateStateOperation(const IR::Instruction& inst);
bool TranslateControlOperation(const IR::Instruction& inst);
bool TranslateMove(const IR::Instruction& inst);
bool TranslateLaneOperation(const IR::Instruction& inst);
bool TranslateAttributeOperation(const IR::Instruction& inst);
bool TranslateMemoryOperation(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot = nullptr);
bool TranslateMemoryOperation(const IR::Instruction& inst,
const BufferAddressValues* address_snapshot,
const ScalarMemorySourceValues* scalar_source_snapshot);
bool TranslateIntegerCompare(const IR::Instruction& inst);
bool TranslateInteger16Compare(const IR::Instruction& inst);
bool TranslateFloatCompare(const IR::Instruction& inst);