mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 00:22:57 -05:00
Reading src_shared_base, src_shared_limit, src_private_base or src_private_limit (scalar source codes 235-238) refused the shader since #1940, because their values were unknown. They now read as the 64-bit apertures that the flat routing from #1190 classifies: a base is the aperture's high dword over a low dword of 0, a limit is the same high dword over 0xffffffff (shared 0x80000000, private 0x70000000). A 64-bit read (s_mov_b64, a 64-bit VALU source, a wave64 lane mask) gets the whole value and a 32-bit read gets the low dword. A flat pointer built from the high dword therefore reaches LDS or scratch, and 64-bit compares against the limits order as on the hardware. The flat routing and the reads share one definition of the two high dwords. Sources: LLVM SIRegisterInfo.td (aperture registers are 64-bit, their low 32 bits are always 0 for a base and -1 for a limit) and getSegmentAperture in AMDGPULegalizerInfo.cpp and SIISelLowering.cpp (a 64-bit read whose high half is the aperture); the RDNA 2 ISA guide, sections 5.2, 5.8 (SH_MEM_BASES holds 16-bit bases) and 9.3; the KFD's MAKE_LDS_APP_LIMIT (limit = base | 0xffffffff); the gfx1030 and gfx1035 readouts on #1190 and #3803. The PS5's two high dwords stay inferred, as the shader technical debt records. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
108 lines
4.5 KiB
C++
108 lines
4.5 KiB
C++
#include "IntermediateRepresentation/IrProgram.hpp"
|
|
#include "RdnaDecoder/RdnaInstructionDecoder.hpp"
|
|
#include "RdnaDecoder/RdnaScalarOpDecoder.hpp"
|
|
#include "Translation/TranslationContext.hpp"
|
|
#include <array>
|
|
#include <cstdio>
|
|
#include <map>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
using namespace ShaderRecompiler;
|
|
|
|
namespace {
|
|
|
|
struct ApertureSource {
|
|
std::uint32_t code;
|
|
RdnaOperandKind kind;
|
|
const char* name;
|
|
std::uint32_t low;
|
|
std::uint32_t high;
|
|
};
|
|
|
|
const std::array<ApertureSource, 4> ApertureSources{{
|
|
{235u, RdnaOperandKind::SrcSharedBase, "src_shared_base", 0x00000000u, 0x80000000u},
|
|
{236u, RdnaOperandKind::SrcSharedLimit, "src_shared_limit", 0xffffffffu, 0x80000000u},
|
|
{237u, RdnaOperandKind::SrcPrivateBase, "src_private_base", 0x00000000u, 0x70000000u},
|
|
{238u, RdnaOperandKind::SrcPrivateLimit, "src_private_limit", 0xffffffffu, 0x70000000u},
|
|
}};
|
|
|
|
constexpr std::uint32_t MovB32 = 0x03u;
|
|
constexpr std::uint32_t MovB64 = 0x04u;
|
|
|
|
void Require(bool value, const std::string& message) {
|
|
if (!value) throw std::runtime_error(message);
|
|
}
|
|
|
|
std::string Hex(std::uint32_t value) {
|
|
char text[16];
|
|
std::snprintf(text, sizeof(text), "0x%08x", value);
|
|
return text;
|
|
}
|
|
|
|
RdnaInstruction ScalarMove(std::uint32_t opcode, std::uint32_t source) {
|
|
const std::array<std::uint32_t, 2> words{0x80000000u | (0x7du << 23u) | (opcode << 8u) | source, 0u};
|
|
return DecodeRdnaSop1(0u, words, 0u);
|
|
}
|
|
|
|
std::map<std::uint32_t, std::uint32_t> TranslateWrites(const RdnaInstruction& instruction) {
|
|
IrProgram program;
|
|
auto& block = program.CreateBlock();
|
|
program.SetEntryBlock(block);
|
|
program.BlockOrder() = {&block};
|
|
program.Metadata().blockInfo.resize(1);
|
|
TranslationContext context(program, block, 256);
|
|
context.TranslateInstruction(instruction);
|
|
std::map<std::uint32_t, std::uint32_t> writes;
|
|
for (const IrValue* value : block.Instructions()) {
|
|
if (value->Opcode() != IrOpcode::SetScalarRegister) continue;
|
|
const IrValue* written = value->Argument(1u)->Resolve();
|
|
Require(written->HasImmediate(), "the write of s" + std::to_string(value->Argument(0u)->Register().index) + " is not a constant");
|
|
writes[value->Argument(0u)->Register().index] = written->ImmediateU32();
|
|
}
|
|
return writes;
|
|
}
|
|
|
|
void CheckDecode() {
|
|
for (const auto& source : ApertureSources) {
|
|
const auto operand = DecodeRdnaScalarSource(source.code, 0u);
|
|
Require(operand.kind == source.kind,
|
|
"scalar source " + std::to_string(source.code) + " decoded to the wrong operand kind");
|
|
Require(RdnaOperandToString(operand) == source.name,
|
|
"scalar source " + std::to_string(source.code) + " is named " + RdnaOperandToString(operand));
|
|
}
|
|
}
|
|
|
|
void CheckWord(const std::map<std::uint32_t, std::uint32_t>& writes, std::uint32_t reg, std::uint32_t expected, const std::string& read) {
|
|
const auto found = writes.find(reg);
|
|
Require(found != writes.end(), read + " did not write s" + std::to_string(reg));
|
|
Require(found->second == expected, read + " wrote " + Hex(found->second) + " to s" + std::to_string(reg) + ", expected " + Hex(expected));
|
|
}
|
|
|
|
void CheckReadValues() {
|
|
for (const auto& source : ApertureSources) {
|
|
const RdnaInstruction narrow = ScalarMove(MovB32, source.code);
|
|
Require(narrow.op == RdnaOpcode::SMovB32, "the 32-bit scalar move decoded to another opcode");
|
|
Require(narrow.source0.kind == source.kind, "the 32-bit scalar move decodes source0 as the wrong operand kind");
|
|
const auto narrowWrites = TranslateWrites(narrow);
|
|
CheckWord(narrowWrites, 0u, source.low, std::string("s_mov_b32 of ") + source.name);
|
|
Require(narrowWrites.size() == 1u, std::string("s_mov_b32 of ") + source.name + " wrote more than one register");
|
|
const RdnaInstruction wide = ScalarMove(MovB64, source.code);
|
|
Require(wide.op == RdnaOpcode::SMovB64, "the 64-bit scalar move decoded to another opcode");
|
|
Require(wide.source0.kind == source.kind, "the 64-bit scalar move decodes source0 as the wrong operand kind");
|
|
const auto wideWrites = TranslateWrites(wide);
|
|
CheckWord(wideWrites, 0u, source.low, std::string("s_mov_b64 of ") + source.name);
|
|
CheckWord(wideWrites, 1u, source.high, std::string("s_mov_b64 of ") + source.name);
|
|
Require(wideWrites.size() == 2u, std::string("s_mov_b64 of ") + source.name + " wrote more than two registers");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
CheckDecode();
|
|
CheckReadValues();
|
|
std::puts("aperture sources tests passed");
|
|
return 0;
|
|
}
|