From 2f88a0a3b293fbe010d13e941b968304b498c157 Mon Sep 17 00:00:00 2001 From: nmzik Date: Tue, 13 Oct 2026 00:53:23 +0200 Subject: [PATCH] shader: elide bitcasts between identical physical types --- .../backend/spirv/spirvEmitterInstructions.h | 7 +++--- tests/ShaderRecompilerComputeTests.cpp | 22 ++++++++++++++++--- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h index 6bd749e6..ad6b3138 100644 --- a/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h +++ b/src/graphics/shader/recompiler/backend/spirv/spirvEmitterInstructions.h @@ -5,15 +5,17 @@ #include namespace Libs::Graphics::ShaderRecompiler::Spirv::Emitter { +uint32_t EmitIdentity(ValueEmitContext& ctx, uint32_t value); + // Operand signatures distinguish SPIR-V IDs (uint32_t), raw literals/values // (IR::Value), and instructions whose metadata or operand loads must stay lazy. #define EMIT_NATIVE(name, opcode, type, ...) \ inline constexpr auto Emit##name = EmitNative; -EMIT_NATIVE(BitCastU16F16, OpBitcast, U32, uint32_t) +inline constexpr auto EmitBitCastU16F16 = EmitIdentity; inline constexpr auto EmitBitCastF16U16 = EmitBitCastU16F16; inline constexpr auto EmitConvertU32U16 = EmitBitCastU16F16; inline constexpr auto EmitConvertU32U8 = EmitBitCastU16F16; -inline constexpr auto EmitBitCastU32F32 = EmitBitCastU16F16; +EMIT_NATIVE(BitCastU32F32, OpBitcast, U32, uint32_t) EMIT_NATIVE(BitCastF32U32, OpBitcast, F32, uint32_t) EMIT_NATIVE(BitCastU64F64, OpBitcast, U64, uint32_t) EMIT_NATIVE(BitCastF64U64, OpBitcast, F64, uint32_t) @@ -207,7 +209,6 @@ uint32_t EmitFPSin(EmitterState& state, uint32_t arg0); uint32_t EmitFPCos(EmitterState& state, uint32_t arg0); #undef EMIT_NATIVE -uint32_t EmitIdentity(ValueEmitContext& ctx, uint32_t value); void EmitVoid(ValueEmitContext&); inline constexpr auto EmitReference = EmitVoid; inline constexpr auto EmitReferenceU32 = EmitVoid; diff --git a/tests/ShaderRecompilerComputeTests.cpp b/tests/ShaderRecompilerComputeTests.cpp index ac3b7e2e..064aaf0f 100644 --- a/tests/ShaderRecompilerComputeTests.cpp +++ b/tests/ShaderRecompilerComputeTests.cpp @@ -1,3 +1,5 @@ +#define SPV_ENABLE_UTILITY_CODE + #include "common/assert.h" #include "common/emulatorConfig.h" #include "common/file.h" @@ -1610,7 +1612,21 @@ void CheckRectListShaders() { ValidateSpirv(name, position_only.evaluation); } -void CheckSpirvText(const TestCase &test, const std::vector &spirv) { +void CheckSpirvEmission(const TestCase &test, const std::vector &spirv) { + std::vector result_types(spirv[3]); + for (size_t offset = 5; offset < spirv.size();) { + const auto words = std::span(spirv).subspan(offset, spirv[offset] >> 16u); + const auto opcode = static_cast(words[0] & 0xffffu); + bool has_result = false, has_type = false; + spv::HasResultAndType(opcode, &has_result, &has_type); + if (has_result && has_type) result_types[words[2]] = words[1]; + if (opcode == spv::OpBitcast) { + Require(test.name, "bitcast changes representation", + words[1] != result_types[words[3]], + "emitted a redundant bitcast between identical SPIR-V types"); + } + offset += words.size(); + } if (test.required_spirv.empty() && test.forbidden_spirv.empty()) { return; } @@ -1737,7 +1753,7 @@ CompiledShader CompileCase(const TestCase &test, u32 host_subgroup_size = 64) { Require(test.name, "SPIR-V emit", !result.spirv.empty(), "recompiler returned empty SPIR-V"); ValidateSpirv(test.name, result.spirv); - CheckSpirvText(test, result.spirv); + CheckSpirvEmission(test, result.spirv); if (test.expected_buffer_resources) { std::vector resources; for (u32 i = 0; i < result.program.info.buffers.size(); ++i) { @@ -36184,7 +36200,7 @@ void CheckIndirectBufferStore(VulkanHarness &vulkan) { } else { test.required_spirv = {"OpSwitch"}; } - CheckSpirvText(test, compiled.spirv); + CheckSpirvEmission(test, compiled.spirv); for (const bool swapped : {false, true}) { if (layout != Layout::Shared && layout != Layout::IndexedNullChild && swapped) continue;