From: Marcos Maronas Date: Mon, 3 Aug 2026 20:15:23 +0100 Subject: [04/13] [Backport to 22] Emit FPFastMathMode for Call (#3912) Origin: upstream, https://github.com/KhronosGroup/SPIRV-LLVM-Translator/commit/e24edbd78b78779fc4c99847cf937059dcae234d `SPV_KHR_float_controls2` makes `FPFastMathMode` valid for all core instructions, so this patch enables translation of fast math flags for `OpFunctionCall`. --- lib/SPIRV/SPIRVReader.cpp | 1 + lib/SPIRV/SPIRVWriter.cpp | 18 +++++-- .../fp-fast-math-mode-function-call.ll | 48 +++++++++++++++++++ 3 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 test/extensions/KHR/SPV_KHR_float_controls2/fp-fast-math-mode-function-call.ll diff --git a/lib/SPIRV/SPIRVReader.cpp b/lib/SPIRV/SPIRVReader.cpp index 1eab73ab..d0452afc 100644 --- a/lib/SPIRV/SPIRVReader.cpp +++ b/lib/SPIRV/SPIRVReader.cpp @@ -2777,6 +2777,7 @@ Value *SPIRVToLLVM::transValueWithoutDecoration(SPIRVValue *BV, Function *F, BC->getName(), BB); setCallingConv(Call); setAttrByCalledFunc(Call); + applyFPFastMathModeDecorations(BV, Call); return mapValue(BV, Call); } diff --git a/lib/SPIRV/SPIRVWriter.cpp b/lib/SPIRV/SPIRVWriter.cpp index 2f0b3a46..678b440c 100644 --- a/lib/SPIRV/SPIRVWriter.cpp +++ b/lib/SPIRV/SPIRVWriter.cpp @@ -3201,12 +3201,16 @@ bool LLVMToSPIRVBase::transDecoration(Value *V, SPIRVValue *BV) { if (auto *BVF = dyn_cast_or_null(V)) { auto Opcode = BVF->getOpcode(); + bool IsSPV16Op = (Opcode == Instruction::FNeg || + Opcode == Instruction::FCmp || BV->isExtInst()) && + BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_6); + bool IsFC2Op = + BV->getOpCode() == OpFunctionCall && + BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_float_controls2); if (Opcode == Instruction::FAdd || Opcode == Instruction::FSub || Opcode == Instruction::FMul || Opcode == Instruction::FDiv || Opcode == Instruction::FRem || BV->getOpCode() == OpFmaKHR || - ((Opcode == Instruction::FNeg || Opcode == Instruction::FCmp || - BV->isExtInst()) && - BM->isAllowedToUseVersion(VersionNumber::SPIRV_1_6))) { + IsSPV16Op || IsFC2Op) { bool AllowFloatControls2 = BM->isAllowedToUseExtension(ExtensionID::SPV_KHR_float_controls2); bool AllowIntelFpFastMathMode = @@ -3307,9 +3311,13 @@ bool LLVMToSPIRVBase::transDecoration(Value *V, SPIRVValue *BV) { } if (M != 0) { BV->setFPFastMathMode(M); - if (Opcode == Instruction::FNeg || Opcode == Instruction::FCmp || - BV->isExtInst()) + if (IsSPV16Op) BM->setMinSPIRVVersion(VersionNumber::SPIRV_1_6); + if (IsFC2Op) { + BM->setMinSPIRVVersion(VersionNumber::SPIRV_1_6); + BM->addCapability(CapabilityFloatControls2); + BM->addExtension(ExtensionID::SPV_KHR_float_controls2); + } } } } diff --git a/test/extensions/KHR/SPV_KHR_float_controls2/fp-fast-math-mode-function-call.ll b/test/extensions/KHR/SPV_KHR_float_controls2/fp-fast-math-mode-function-call.ll new file mode 100644 index 00000000..d6c600cd --- /dev/null +++ b/test/extensions/KHR/SPV_KHR_float_controls2/fp-fast-math-mode-function-call.ll @@ -0,0 +1,48 @@ +; Verify that FPFastMathMode decorations are emitted for OpFunctionCall when +; SPV_KHR_float_controls2 is enabled. Also verify that non-core instructions +; (e.g. OpGroupFMulKHR from SPV_KHR_uniform_group_instructions) do NOT get a +; spurious FPFastMathMode decoration. SPV_KHR_float_controls2 extends +; FPFastMathMode to all *core* instructions, but not to extension-defined ones. + +; Without FC2: no decoration on call. +; RUN: llvm-spirv -spirv-text %s --spirv-max-version=1.5 --spirv-ext=+SPV_KHR_uniform_group_instructions -o - | FileCheck %s --check-prefix=NO-DECO +; RUN: llvm-spirv -spirv-text %s --spirv-ext=+SPV_KHR_uniform_group_instructions -o - | FileCheck %s --check-prefix=NO-DECO + +; With FC2: decoration emitted on OpFunctionCall, not on extension instructions. +; RUN: llvm-spirv -spirv-text %s --spirv-ext=+SPV_KHR_float_controls2,+SPV_KHR_uniform_group_instructions -o - | FileCheck %s --check-prefix=SPIRV + +; Roundtrip with FC2. +; RUN: llvm-spirv %s --spirv-ext=+SPV_KHR_float_controls2,+SPV_KHR_uniform_group_instructions -o %t.spv +; RUN: spirv-val %t.spv +; RUN: llvm-spirv -r %t.spv -o - | llvm-dis | FileCheck %s --check-prefix=IR + +target triple = "spirv-unknown-unknown" + +define internal spir_func float @helper(float %x) { + %r = fmul float %x, %x + ret float %r +} + +declare spir_func float @_Z20__spirv_GroupFMulKHRjjf(i32, i32, float) + +; NO-DECO-NOT: FPFastMathMode + +; SPIRV-DAG: FunctionCall [[#]] [[#CALL:]] +; SPIRV-DAG: GroupFMulKHR [[#]] [[#GFMUL:]] +; SPIRV-DAG: Decorate [[#CALL]] FPFastMathMode 458767 + +; OpGroupFMulKHR is defined by SPV_KHR_uniform_group_instructions, not core. +; It should NOT get FPFastMathMode because FC2 only covers core instructions. +; SPIRV-NOT: Decorate [[#GFMUL]] FPFastMathMode + +define spir_kernel void @test(ptr addrspace(1) %out, float %a) { +entry: + ; IR: %call_fast = call reassoc nnan ninf nsz arcp contract spir_func float @helper(float %a) + %call_fast = call fast spir_func float @helper(float %a) + store float %call_fast, ptr addrspace(1) %out, align 4 + + %gfmul_fast = call fast spir_func float @_Z20__spirv_GroupFMulKHRjjf(i32 2, i32 0, float %a) + store float %gfmul_fast, ptr addrspace(1) %out, align 4 + + ret void +} -- 2.55.0