Fix SPIR-V float control contract (Preserve FP32 Inf and NaN)

This commit is contained in:
nmzik
2026-08-18 03:53:42 +02:00
parent 0df20eb300
commit b4809e7170
4 changed files with 37 additions and 0 deletions
@@ -33,6 +33,7 @@ enum : uint32_t {
ExecutionModeEarlyFragmentTests = 9,
ExecutionModeDepthReplacing = 12,
ExecutionModeLocalSize = 17,
ExecutionModeSignedZeroInfNanPreserve = 4461,
ExecutionModeDerivativeGroupQuadsKHR = 5289,
AddressingModelLogical = 0,
MemoryModelGLSL450 = 1,
@@ -46,6 +47,7 @@ enum : uint32_t {
CapabilityGroupNonUniform = 61,
CapabilityGroupNonUniformBallot = 64,
CapabilityGroupNonUniformShuffle = 65,
CapabilitySignedZeroInfNanPreserve = 4466,
CapabilityComputeDerivativeGroupQuadsKHR = 5288,
StorageClassUniformConstant = 0,
StorageClassInput = 1,
@@ -486,6 +486,7 @@ void EmitHeaderAndTypes(EmitterState& state) {
state.builder.AddCapability({CapabilitySampled1D});
state.builder.AddCapability({CapabilityImage1D});
state.builder.AddCapability({CapabilityImageQuery});
state.builder.AddCapability({CapabilitySignedZeroInfNanPreserve});
if (state.needs_image_gather_extended) {
state.builder.AddCapability({CapabilityImageGatherExtended});
}
@@ -509,10 +510,14 @@ void EmitHeaderAndTypes(EmitterState& state) {
state.builder.AddCapability({CapabilityComputeDerivativeGroupQuadsKHR});
state.builder.AddExtension("SPV_KHR_compute_shader_derivatives");
}
state.builder.AddExtension("SPV_KHR_float_controls");
state.builder.AddExtInstImport(state.glsl_std450, "GLSL.std.450");
state.builder.AddMemoryModel({AddressingModelLogical, MemoryModelGLSL450});
state.builder.AddEntryPoint(ExecutionModelForStage(state.stage), state.main_func, "main",
state.interface_variables);
// GCN/RDNA arithmetic preserves 32-bit signed zero, infinity, and NaN. Declaring that
// contract prevents host compilers from treating synthesized IEEE values as finite.
state.builder.AddExecutionMode({state.main_func, ExecutionModeSignedZeroInfNanPreserve, 32u});
if (state.stage == ShaderType::Compute) {
uint32_t local_x = state.needs_compute_derivatives ? 2u : 1u;
uint32_t local_y = state.needs_compute_derivatives ? 2u : 1u;
+26
View File
@@ -12679,6 +12679,31 @@ TestCase VectorVop3FmaF16UsesRdna2Opcode34b() {
{O::VMovB32, O::VFmaF16, O::BufferStoreDword, O::SEndpgm}};
}
TestCase VectorFloatControlContractPreservesInfNan() {
using O = ShaderOpcode;
std::vector<u32> code;
code.push_back(EncodeSop2(0x24, 0, InlineU32(8), InlineU32(23)));
code.push_back(EncodeVop1(0x01, 0, InlineU32(0)));
AppendVMovU32(&code, 1, 1);
AppendVMovU32(&code, 2, 3);
AppendVop3(&code, 0x108, 10, 0, Vgpr(0));
code.push_back(EncodeVopc(0x88, Vgpr(10), 2));
code.push_back(EncodeVop2(0x01, 3, InlineU32(0), 1));
AppendStoreVgpr(&code, 3, 0);
AppendEnd(&code);
TestCase test;
test.name = "VectorFloatControlContractPreservesInfNan";
test.code = std::move(code);
test.expected = {1u};
test.opcodes = {O::SBfmB32, O::VMovB32, O::VMulF32, O::VCmpClassF32,
O::VCndmaskB32, O::BufferStoreDword, O::SEndpgm};
test.required_spirv = {"SPV_KHR_float_controls",
"SignedZeroInfNanPreserve 32"};
return test;
}
TestCase VectorFloatArithmeticOps() {
using O = ShaderOpcode;
@@ -17005,6 +17030,7 @@ std::vector<TestCase> MakeCases() {
AddCase(MadMixF16LiteralHalfSourceUsesOpsel);
AddCase(MadMixF16NegHiIsAbsAndNegIsIndependent);
AddCase(VectorVop3FmaF16UsesRdna2Opcode34b);
AddCase(VectorFloatControlContractPreservesInfNan);
AddCase(VectorFloatArithmeticOps);
AddCase(VectorMinMaxF32NanAndSignedZeroEdges);
AddCase(VectorMed3F32NanUsesMin3Path);
+4
View File
@@ -978,6 +978,10 @@ void TestNewShaderRecompilerSMovB32() {
Check(std::find(result.spirv.begin(), result.spirv.end(), 0x12345678u) !=
result.spirv.end(),
"new SPIR-V emitter did not encode the literal as a binary word");
Check(SpirvContainsCapability(result.spirv, 4466),
"SPIR-V binary does not request signed-zero/Inf/NaN preservation");
Check(SpirvContainsExecutionMode(result.spirv, 4461),
"SPIR-V binary does not enable signed-zero/Inf/NaN preservation");
CheckSpirvBinaryValidates(result.spirv);
}