refactor(shader): preserve native scalar memory operations

This commit is contained in:
nmzik committed 2026-08-21 03:32:47 +02:00
1 parent c236ba713d
commit 8063822243
10 files changed
+296 -200

No files matched your search

@@ -273,7 +273,7 @@ void ClearRegisterOffsetModifiers(Decoder::Operand& operand) {
operand.dpp = false;
}
bool TryGetScalarDestinationCode(const Decoder::Operand& operand, uint32_t& code) {
bool TryGetEncodedScalarCode(const Decoder::Operand& operand, uint32_t& code) {
switch (operand.kind) {
case Decoder::OperandKind::Sgpr: code = operand.reg; return true;
case Decoder::OperandKind::VccLo: code = SCALAR_DST_VCC_LO; return true;
@@ -290,7 +290,7 @@ bool TryOffsetScalarDestination(const Decoder::Operand& operand, uint32_t index,
// aliases such as VCC and EXEC sit beside ordinary SGPRs. Re-decode after adding the
// dword index so s_buffer_load_dwordx2 vcc_lo writes vcc_lo, then vcc_hi.
uint32_t code = 0;
return TryGetScalarDestinationCode(operand, code) &&
return TryGetEncodedScalarCode(operand, code) &&
Decoder::DecodeScalarDestination(code + index, 0, decoded, nullptr);
}
@@ -30,7 +30,7 @@ uint32_t ResourceIndexFromOperand(const Decoder::Operand& operand);
MemoryInfo MemoryInfoFromDecoded(const Decoder::Instruction& decoded, ResourceKind kind);
uint32_t RawScalarLoadBase(const Decoder::Operand& operand);
void ClearRegisterOffsetModifiers(Decoder::Operand& operand);
bool TryGetScalarDestinationCode(const Decoder::Operand& operand, uint32_t& code);
bool TryGetEncodedScalarCode(const Decoder::Operand& operand, uint32_t& code);
bool TryOffsetScalarDestination(const Decoder::Operand& operand, uint32_t index,
Decoder::Operand& result);
Decoder::Operand OffsetDecodedRegister(const Decoder::Operand& operand, uint32_t index);
@@ -77,24 +77,40 @@ Opcode LoweredImageOpcode(Decoder::Opcode opcode) {
bool LowerScalarMemoryLoadDword(const Decoder::Instruction& decoded, BasicBlock& block, Opcode op,
std::string* error) {
for (uint32_t i = 0; i < decoded.data_dwords; i++) {
Instruction inst;
inst.pc = decoded.pc;
inst.op = op;
inst.src_count = 1;
const auto kind =
op == Opcode::SLoadDword ? ResourceKind::ScalarAddress : ResourceKind::ScalarBuffer;
inst.memory = OffsetMemoryInfo(decoded, kind, i);
// Raw s_load uses a two-SGPR pointer base; s_buffer_load uses a four-SGPR
// descriptor resource index.
inst.memory.resource = op == Opcode::SLoadDword ? RawScalarLoadBase(decoded.src0)
: ResourceIndexFromOperand(decoded.src0);
if (!LowerRegisterOperand(OffsetDecodedRegister(decoded.dst, i), inst.dst, error) ||
!LowerSourceOperand(decoded.src1, inst.src[0], error)) {
return false;
}
block.instructions.push_back(inst);
uint32_t destination_code = 0;
const auto alignment = decoded.data_dwords == 1u ? 1u
: decoded.data_dwords == 2u ? 2u
: 4u;
if (!TryGetEncodedScalarCode(decoded.dst, destination_code) ||
destination_code % alignment != 0u ||
destination_code + decoded.data_dwords > 108u) {
SetError(error, "scalar-memory destination has an invalid aligned SGPR span");
return false;
}
uint32_t base_code = 0;
const auto base_alignment = op == Opcode::SLoadDword ? 2u : 4u;
const auto base_width = op == Opcode::SLoadDword ? 2u : 4u;
if (!TryGetEncodedScalarCode(decoded.src0, base_code) ||
base_code % base_alignment != 0u || base_code + base_width > 108u) {
SetError(error, "scalar-memory base has an invalid aligned SGPR span");
return false;
}
Instruction inst;
inst.pc = decoded.pc;
inst.op = op;
inst.src_count = 1;
const auto kind =
op == Opcode::SLoadDword ? ResourceKind::ScalarAddress : ResourceKind::ScalarBuffer;
inst.memory = MemoryInfoFromDecoded(decoded, kind);
// Raw s_load uses a two-SGPR pointer base; s_buffer_load uses a four-SGPR
// descriptor resource index.
inst.memory.resource = op == Opcode::SLoadDword ? RawScalarLoadBase(decoded.src0)
: ResourceIndexFromOperand(decoded.src0);
if (!LowerRegisterOperand(decoded.dst, inst.dst, error) ||
!LowerSourceOperand(decoded.src1, inst.src[0], error)) {
return false;
}
block.instructions.push_back(inst);
return true;
}
@@ -311,6 +311,33 @@ bool ValidateValueProgram(const ValueProgram& program, bool require_ssa, std::st
ValueOpcodeName(inst.GetOpcode()), inst.NumArgs(),
NumArgsOf(inst.GetOpcode())));
}
if (IsRuntimeRead(inst.GetOpcode())) {
const auto memory_index = inst.Flags<MemoryFlags>().index;
if (memory_index >= program.memory_info.size()) {
return Fail(error, fmt::format("{} has an invalid memory-info index",
ValueOpcodeName(inst.GetOpcode())));
}
const auto& memory = program.memory_info[memory_index];
const bool scalar_buffer = inst.GetOpcode() == ValueOpcode::ReadConstBuffer;
const bool scalar_address = memory.kind == ResourceKind::ScalarAddress;
if ((scalar_buffer && memory.kind != ResourceKind::ScalarBuffer) ||
(!scalar_buffer && !scalar_address && memory.kind != ResourceKind::Flat &&
memory.kind != ResourceKind::Global && memory.kind != ResourceKind::Scratch)) {
return Fail(error, fmt::format("{} has an invalid scalar-memory resource kind",
ValueOpcodeName(inst.GetOpcode())));
}
const bool scalar_memory = scalar_buffer || scalar_address;
const bool valid_group_width =
scalar_memory ? memory.component_count == 1u || memory.component_count == 2u ||
memory.component_count == 4u || memory.component_count == 8u ||
memory.component_count == 16u
: memory.component_count >= 1u && memory.component_count <= 4u;
if (memory.data_bits != 32u || memory.data_dwords != 1u ||
!valid_group_width || memory.component_index >= memory.component_count) {
return Fail(error, fmt::format("{} has inconsistent scalar-memory metadata",
ValueOpcodeName(inst.GetOpcode())));
}
}
const auto buffer_components = BufferComponentCount(inst.GetOpcode());
if (buffer_components != 0u) {
const auto memory_index = inst.Flags<MemoryFlags>().index;