[llvm] [SPIR-V] Implement SPV_KHR_float_controls2 (PR #146941)

Marcos Maronas via llvm-commits llvm-commits at lists.llvm.org
Wed Jul 16 08:21:58 PDT 2025


================
@@ -0,0 +1,92 @@
+; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - | FileCheck %s
+; TODO: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown --spirv-ext=+SPV_KHR_float_controls2 %s -o - -filetype=obj | spirv-val %}
+
+; CHECK-DAG: Capability FloatControls2 
+; CHECK: Extension "SPV_KHR_float_controls2"
+
+; CHECK: OpName %[[#addRes:]] "addRes"
+; CHECK: OpName %[[#subRes:]] "subRes"
+; CHECK: OpName %[[#mulRes:]] "mulRes"
+; CHECK: OpName %[[#divRes:]] "divRes"
+; CHECK: OpName %[[#remRes:]] "remRes"
+; CHECK: OpName %[[#negRes:]] "negRes"
+; CHECK: OpName %[[#oeqRes:]] "oeqRes"
+; CHECK: OpName %[[#oneRes:]] "oneRes"
+; CHECK: OpName %[[#oltRes:]] "oltRes"
+; CHECK: OpName %[[#ogtRes:]] "ogtRes"
+; CHECK: OpName %[[#oleRes:]] "oleRes"
+; CHECK: OpName %[[#ogeRes:]] "ogeRes"
+; CHECK: OpName %[[#ordRes:]] "ordRes"
+; CHECK: OpName %[[#ueqRes:]] "ueqRes"
+; CHECK: OpName %[[#uneRes:]] "uneRes"
+; CHECK: OpName %[[#ultRes:]] "ultRes"
+; CHECK: OpName %[[#ugtRes:]] "ugtRes"
+; CHECK: OpName %[[#uleRes:]] "uleRes"
+; CHECK: OpName %[[#ugeRes:]] "ugeRes"
+; CHECK: OpName %[[#unoRes:]] "unoRes"
+; CHECK: OpName %[[#modRes:]] "modRes"
+; CHECK: OpName %[[#maxRes:]] "maxRes"
+; CHECK: OpName %[[#maxCommonRes:]] "maxCommonRes"
+; CHECK: OpDecorate %[[#subRes]] FPFastMathMode NotNaN
+; CHECK: OpDecorate %[[#mulRes]] FPFastMathMode NotInf
+; CHECK: OpDecorate %[[#divRes]] FPFastMathMode NSZ
+; CHECK: OpDecorate %[[#remRes]] FPFastMathMode AllowRecip
+; CHECK: OpDecorate %[[#negRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#oeqRes]] FPFastMathMode NotNaN|NotInf
+; CHECK: OpDecorate %[[#oneRes]] FPFastMathMode AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#oltRes]] FPFastMathMode NotNaN|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#ogtRes]] FPFastMathMode NotInf|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#oleRes]] FPFastMathMode NSZ|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#ogeRes]] FPFastMathMode AllowRecip|AllowReassoc|AllowTransform
+; CHECK: OpDecorate %[[#ordRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ueqRes]] FPFastMathMode NotNaN|NotInf|AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#uneRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ultRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ugtRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#uleRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#ugeRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#unoRes]] FPFastMathMode AllowReassoc|AllowTransform 
+; CHECK-NOT: OpDecorate %[[#modRes]] FPFastMathMode
+; CHECK: OpDecorate %[[#maxRes]] FPFastMathMode NotNaN|NotInf|NSZ|AllowRecip|AllowContract|AllowReassoc|AllowTransform 
+; CHECK: OpDecorate %[[#maxCommonRes:]] FPFastMathMode NotNaN|NotInf 
+
+target datalayout = "e-p:32:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024"
+target triple = "spir"
+
+; Function Attrs: convergent mustprogress nofree nounwind willreturn memory(none)
+declare spir_func float @_Z4fmodff(float, float)
+declare dso_local spir_func noundef nofpclass(nan inf) float @_Z16__spirv_ocl_fmaxff(float noundef nofpclass(nan inf), float noundef nofpclass(nan inf)) local_unnamed_addr #1
+declare dso_local spir_func noundef nofpclass(nan inf) float @_Z23__spirv_ocl_fmax_commonff(float noundef nofpclass(nan inf), float noundef nofpclass(nan inf)) local_unnamed_addr #1
+
+; Function Attrs: convergent mustprogress norecurse nounwind
+define weak_odr dso_local spir_kernel void @foo(float %1, float %2) {
+entry:
+  %addRes = fadd float %1,  %2
+  %subRes = fsub nnan float %1,  %2
+  %mulRes = fmul ninf float %1,  %2
+  %divRes = fdiv nsz float %1,  %2
+  %remRes = frem arcp float %1,  %2
+  %negRes = fneg fast float %1
+  %oeqRes = fcmp nnan ninf oeq float %1,  %2
+  %oneRes = fcmp one float %1,  %2, !spirv.Decorations !3
----------------
maarquitos14 wrote:

> If this code were to be pass to the optimizer, would it be possible that the metadata will be removed? Would that be a problem? Are we worried about that or is is just an acceptable lose of information?

I have been having some internal discussions with @MrSidims on how to reconcile the information when there are both math flags expressed with LLVM IR and also through metadata. I don't think there's any formal guidance on how this should be done, and what should have priority, so I think we should come up with a convention ourselves. That being said, the scenario you present is quite helpful towards building this convention: if such a code was passed to the optimizer, with both LLVM IR math flags and metadata, the optimizer knows nothing about SPIRV's metadata --as far as I'm concerned--, so it could already do some transformations/optimizations that go against what is expressed in the metadata. As a consequence, I would say we should just emit the metadata the way we find it, because at the point where we find it, it might have been violated already, but we don't really know. What do you think?

> Also, could an llvm optimization optimize the instruction in such a way that is inconsistent with the float controls? I'm guessing no. Adding Floatcontrols makes things more permissible. It is the responsibility of the code generates to make the llvm-ir option at least as restrictive as the Floatcontrols.

I think nothing prevents an optimization to go against what is expressed through metadata, because, like I said before, I don't think they're even aware of SPIRV's metadata. However, I do agree with you that the code generator should guarantee that LLVM IR flags are aligned with metadata, if any. I don't think there's a lot we can do on our side if they don't align, honestly. Like I said before, I did have a think at how to reconcile possible inconsistencies between LLVM IR flags and metadata, but I didn't see any good way of doing it, and, again, optimizations might have violated already metadata controls.


https://github.com/llvm/llvm-project/pull/146941


More information about the llvm-commits mailing list