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
13 changes: 13 additions & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,19 @@ if(BUILD_TESTING)
endif()
endif()

add_test_executable(agc_spirv_failure_text_tests EXCLUDE_FROM_ALL tests/SpirvFailureText.cpp)
target_link_libraries(agc_spirv_failure_text_tests PRIVATE shader_recompiler_agc_driver libc)
set_target_properties(agc_spirv_failure_text_tests PROPERTIES CXX_EXTENSIONS OFF)
configure_windows_unwind(agc_spirv_failure_text_tests)
if(BUILD_TESTING)
set_target_properties(agc_spirv_failure_text_tests PROPERTIES EXCLUDE_FROM_ALL OFF)
add_test(NAME agc_spirv_failure_text COMMAND agc_spirv_failure_text_tests)
set_tests_properties(agc_spirv_failure_text PROPERTIES ENVIRONMENT "ANYPS5_NO_SHADER_CACHE=1")
if(WIN32)
set_tests_properties(agc_spirv_failure_text PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:libc>")
endif()
endif()

add_test_executable(agc_spirv_lds_atomic_lock_tests EXCLUDE_FROM_ALL tests/SpirvLdsAtomicLock.cpp)
target_link_libraries(agc_spirv_lds_atomic_lock_tests PRIVATE shader_recompiler_agc_driver libc)
set_target_properties(agc_spirv_lds_atomic_lock_tests PROPERTIES CXX_EXTENSIONS OFF)
Expand Down
75 changes: 75 additions & 0 deletions core/libs/prx/libSceAgcDriver/tests/SpirvFailureText.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#include "IntermediateRepresentation/IrProgram.hpp"
#include "Optimization/ShaderStageInputInfo.hpp"
#include "SpirvBackend/SpirvEmitter.hpp"
#include "PipelineSpecialization.hpp"
#include <cstdint>
#include <cstdio>
#include <exception>
#include <stdexcept>
#include <string>
#include <string_view>

namespace {

using namespace ShaderRecompiler;

void require(bool condition, const std::string& message) {
if (!condition) throw std::runtime_error(message);
}

enum class Failure { MissingComputeInput, UnloweredInstruction };

std::string emissionFailure(Failure failure) {
IrProgram program;
program.SetWaveSize(32);
program.Resources().stage = IrShaderStage::Compute;
program.Resources().shaderHash = 0x1173ae1000ull;
program.Resources().srtPlanComplete = true;
program.Resources().resourceTrackingComplete = true;
program.Metadata().shaderInfoComplete = true;
program.Metadata().bindingLayoutComplete = true;
auto& block = program.CreateBlock();
program.SetEntryBlock(block);
program.BlockOrder().push_back(&block);
program.Metadata().blockInfo.emplace_back();
if (failure == Failure::UnloweredInstruction) block.AppendInstruction(&program.CreateValue(IrOpcode::Unreachable, IrType::Void));
ShaderComputeInputInfo compute;
compute.threadsNum[0] = 32;
compute.threadsNum[1] = 1;
compute.threadsNum[2] = 1;
compute.hostSubgroupSize = 32;
compute.waveSize = 32;
ShaderStageInputInfo inputs;
if (failure != Failure::MissingComputeInput) inputs.compute = &compute;
CompiledBindingLayout bindings;
bindings.layout = program.Metadata().bindings;
SpirvTargetOptions target{};
target.vulkanVersion = 0x00401000;
target.spirvVersion = 0x00010300;
target.subgroupSize = 32;
try {
static_cast<void>(SpirvEmitter().Emit(program, inputs, bindings, target));
} catch (const std::runtime_error& error) {
return error.what();
}
throw std::runtime_error("the program emitted without a failure");
}

void requireFailure(Failure failure, std::string_view prefix, std::string_view reason) {
const auto text = emissionFailure(failure);
require(text.starts_with(prefix) && text.find(reason) != std::string::npos, "expected \"" + std::string(prefix) + "...\" with \"" + std::string(reason) + "\", got \"" + text + "\"");
}

}

int main() {
try {
requireFailure(Failure::MissingComputeInput, "SPIR-V emission failed: hash=0x1173ae1000 stage=", " reason=compute input info is missing");
requireFailure(Failure::UnloweredInstruction, "SPIR-V emission failed: hash=0x1173ae1000 stage=", " opcode=Unreachable reason=");
} catch (const std::exception& error) {
std::fprintf(stderr, "SpirvFailureText: %s\n", error.what());
return 1;
}
std::puts("SpirvFailureText: emission failures name the shader hash in hex");
return 0;
}
11 changes: 9 additions & 2 deletions core/shader/recompiler/SpirvBackend/src/SpirvEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <spirv/unified1/spirv.hpp>
#include <algorithm>
#include <bit>
#include <cstdio>
#include <cstdlib>
#include <stdexcept>
#include <string>
Expand All @@ -18,8 +19,14 @@ namespace ShaderRecompiler {

namespace {

std::string FailureText(const IrProgram& program) {
char hash[24];
std::snprintf(hash, sizeof(hash), "%llx", static_cast<unsigned long long>(program.Resources().shaderHash));
return std::string("SPIR-V emission failed: hash=0x") + hash + " stage=" + std::to_string(static_cast<unsigned>(program.Resources().stage));
}

[[noreturn]] void FailProgram(const IrProgram& program, const char* reason) {
throw std::runtime_error("SPIR-V emission failed: hash=0x" + std::to_string(program.Resources().shaderHash) + " stage=" + std::to_string(static_cast<unsigned>(program.Resources().stage)) + " reason=" + reason);
throw std::runtime_error(FailureText(program) + " reason=" + reason);
}

const ShaderWorkgroupInputInfo* ShaderWorkgroupInputFor(const SpirvEmitterState& state) {
Expand Down Expand Up @@ -233,7 +240,7 @@ std::uint32_t SpirvValueEmitContext::Label(const IrBlock* block) const {
}

[[noreturn]] void SpirvValueEmitContext::Fail(const IrValue& inst, const char* reason) const {
throw std::runtime_error("SPIR-V emission failed: hash=0x" + std::to_string(state.program.Resources().shaderHash) + " stage=" + std::to_string(static_cast<unsigned>(state.program.Resources().stage)) + " opcode=" + std::string(IrOpcodeName(inst.Opcode())) + " reason=" + reason);
throw std::runtime_error(FailureText(state.program) + " opcode=" + std::string(IrOpcodeName(inst.Opcode())) + " reason=" + reason);
}

std::vector<std::uint32_t> SpirvEmitter::Emit(const IrProgram& program, const CompiledBindingLayout& bindings, const SpirvTargetOptions& target) const {
Expand Down
Loading