Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/VectorWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,57 @@ std::size_t WindowStores(std::span<const std::uint32_t> words) {
return stores;
}

constexpr std::array<std::uint32_t, 34> WindowInit{
0x34020086, 0x34060088, 0x4a140680, 0x4a160681, 0x4a180682, 0x4a1a0683, 0x4a1c0684, 0x4a1e0685,
0x4a200686, 0x4a220687, 0x4a240688, 0x4a260689, 0x4a28068a, 0x4a2a068b, 0x4a2c068c, 0x4a2e068d,
0x4a30068e, 0x4a32068f, 0x4a340690, 0x4a360691, 0x4a380692, 0x4a3a0693, 0x4a3c0694, 0x4a3e0695,
0x4a400696, 0x4a420697, 0x4a440698, 0x4a460699, 0x4a48069a, 0x4a4a069b, 0x4a4c069c, 0x4a4e069d,
0x4a50069e, 0x4a52069f,
};
constexpr std::uint32_t MoveM0BoundedS8 = 0x877c8308u;
constexpr std::uint32_t MoveM0S9 = 0xbefc0309u;
constexpr std::uint32_t MovrelsV4V10 = 0x7e08870au;

std::vector<std::uint32_t> NarrowingProgram(std::uint32_t unbounded) {
std::vector<std::uint32_t> code(WindowInit.begin(), WindowInit.end());
code.push_back(MoveM0BoundedS8);
code.push_back(MovrelsV4V10);
code.push_back(0xe0701ffcu);
code.push_back(0x80010401u);
code.push_back(MoveM0S9);
for (std::uint32_t read = 0; read < unbounded; ++read) {
const std::uint32_t destination = 42u + read % 100u;
code.push_back((MovrelsV4V10 & ~(0xffu << 17u)) | (destination << 17u));
code.push_back(0xe0701000u | ((read * 4u) & 0xfffu));
code.push_back(0x80010001u | destination << 8u);
}
code.push_back(EndProgram);
return code;
}

std::vector<std::uint32_t> RecompileNarrowing(std::uint32_t unbounded) {
std::array<std::uint32_t, 10> userData{0u, 0u, 0u, 0u, 0x10000000u, 0u, 0x40u, 0x31016facu, 3u, 5u};
return RecompileProgram(NarrowingProgram(unbounded), userData);
}

struct Narrowing {
std::uint32_t functionVariables = 0;
std::uint32_t switchCases = 0;
};

Narrowing ScanNarrowing(std::span<const std::uint32_t> words) {
Narrowing result;
for (std::size_t cursor = 5; cursor < words.size();) {
const auto count = words[cursor] >> spv::WordCountShift;
const auto op = static_cast<spv::Op>(words[cursor] & spv::OpCodeMask);
Require(count != 0 && cursor + count <= words.size(), "truncated SPIR-V instruction");
if (op == spv::OpVariable && words[cursor + 3] == spv::StorageClassFunction) ++result.functionVariables;
if (op == spv::OpSwitch) result.switchCases += (count - 3u) / 2u;
cursor += count;
}
return result;
}

IrProgram TranslateStage(ShaderStageKind stage, std::uint32_t waveSize, std::uint32_t base = 0u, std::uint32_t fetchStart = 0u, std::uint32_t fetchCount = 0u) {
ShaderComputeInputInfo compute{};
compute.threadIdsNum = 3;
Expand Down Expand Up @@ -322,6 +373,19 @@ int main(int argc, char** argv) {
return twice == single && single >= 3u;
});

passed &= run("a window with a few unproven relative reads keeps its unindexed slots out of the array", [] {
const auto few = ScanNarrowing(RecompileNarrowing(2));
if (few.functionVariables <= 8u || few.switchCases == 0u) std::fprintf(stderr, " two unproven reads: %u function variables, %u switch cases\n", few.functionVariables, few.switchCases);
return few.functionVariables > 8u && few.switchCases != 0u;
});

passed &= run("a window with hundreds of unproven relative reads does not grow a switch for each of them", [] {
const auto many = ScanNarrowing(RecompileNarrowing(300));
const auto few = ScanNarrowing(RecompileNarrowing(2));
if (many.switchCases > 4096u || many.functionVariables >= few.functionVariables) std::fprintf(stderr, " 300 unproven reads: %u function variables, %u switch cases (2 reads: %u, %u)\n", many.functionVariables, many.switchCases, few.functionVariables, few.switchCases);
return many.switchCases <= 4096u && many.functionVariables < few.functionVariables;
});

if (passed) std::puts("Vector window shape and SSA control tests passed");
return passed ? 0 : 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -192,19 +192,24 @@ class WindowIndexBounds {
std::unordered_set<const IrValue*> active;
};

std::uint32_t IndexedWindowSlots(const IrProgram& program) {
constexpr std::uint64_t MaxNarrowedSwitchCases = 4096;

std::uint32_t IndexedWindowSlots(const IrProgram& program, std::uint32_t laneCount) {
const auto window = program.Metadata().vectorWindowSize;
WindowIndexBounds bounds;
std::uint64_t reached = 0;
std::uint64_t dynamicAccesses = 0;
for (const auto& block : program.Blocks()) {
for (const IrValue* inst : block->Instructions()) {
if (inst->Opcode() != IrOpcode::LoadVectorWindow && inst->Opcode() != IrOpcode::StoreVectorWindow) continue;
const IrValue* index = inst->Argument(0)->Resolve();
if (index->HasImmediate()) continue;
++dynamicAccesses;
const auto bound = bounds.Of(*index);
if (bound && *bound < window / 2u) reached = std::max(reached, *bound + 1u);
}
}
if (reached == 0u || dynamicAccesses * (window - reached) * laneCount > MaxNarrowedSwitchCases) return 0u;
return static_cast<std::uint32_t>(reached);
}

Expand All @@ -226,7 +231,7 @@ void DefineModule(SpirvEmitterState& state) {
}
if (const auto window = state.program.Metadata().vectorWindowSize; window != 0u) {
static const bool narrowWindow = std::getenv("APS5_NO_WINDOW_NARROWING") == nullptr;
state.vectorWindowIndexed = narrowWindow ? IndexedWindowSlots(state.program) : 0u;
state.vectorWindowIndexed = narrowWindow ? IndexedWindowSlots(state.program, state.laneCount) : 0u;
for (std::uint32_t half = 0; half < state.laneCount; half++) {
state.vectorWindowVariable.at(half) = state.module.AllocateId();
if (state.vectorWindowIndexed == 0u) continue;
Expand Down
Loading