You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
POCL: contract fast-math flags lost through SPIR-V, no FMAs emitted #865
Julia's contract flags don't survive the SPIR-V path in the POCL backend, so PoCL emits separate vmulsd/vaddsd instead of FMAs. Seen in Trixi.jl's KA kernels (trixi-framework/Trixi.jl#3321). A prototype fusing mul+add into llvm.fmuladd before SPIR-V generation gave 2–9% speedups. Options: emit llvm.fmuladd pre-translation, or carry contraction via SPIR-V FPFastMathMode. Related: #860, #862.
using KernelAbstractions
import KernelAbstractions.POCL as P
@kernelfunctionaxpy!(y, @Const(a), @Const(x))
i =@index(Global)
@inbounds y[i] =muladd(a[i], x[i], y[i])
end
y =rand(1024); a =rand(1024); x =rand(1024)
k =axpy!(POCLBackend(), 64)
P.@device_code_llvmk(y, a, x; ndrange=1024) # fmul contract + fadd contract
P.@device_code_nativek(y, a, x; ndrange=1024) # OpFMul + OpFAdd, entry point has ContractionOff
With POCL_CACHE_DIR set, PoCL's .so.o contains vmulsd/vaddsd (and vmulpd/vaddpd), no vfmadd.
There are two causes:
Base SPIR-V can't carry the per-instruction contract flag. AllowContract only exists in SPV_KHR_float_controls2.
The LLVM SPIR-V back-end adds ContractionOff to every kernel entry point unless the module has !opencl.enable.FP_CONTRACT (SPIRVAsmPrinter::outputExecutionMode). Clang emits that metadata for OpenCL C; GPUCompiler doesn't.
I tested these variants with a hook in POCL's compiler job (SPIRV_LLVM_Backend_jll 23.1.1, pocl_standalone_jll, x86 with FMA):
Variant
SPIR-V
PoCL x86
baseline
FMul + FAdd, ContractionOff
vmulsd/vaddsd
add !opencl.enable.FP_CONTRACT
FMul + FAdd, no ContractionOff
still vmulsd/vaddsd
fuse fmul contract + fadd contract into llvm.fmuladd before codegen
OpExtInst fma
vfmadd213sd, vfmadd231pd
The metadata alone doesn't help. PoCL won't contract plain fmul/fadd, and it would also be the wrong semantics, since it allows contracting any fmul/fadd.
Proposed fix: run an IR pass in GPUCompiler's SPIR-V finish_ir! (next to lower_minimum_maximum!) that fuses single-use contract-flagged fmul + fadd/fsub into llvm.fmuladd. This fixes all SPIR-V consumers (OpenCL.jl, oneAPI.jl, POCL). One caveat: the back-end lowers fmuladd to OpenCL.std fma, not mad, which is slow on devices without hardware FMA.
Longer term, emit SPV_KHR_float_controls2 (FPFastMathMode AllowContract) and have PoCL accept it. I'm looking into the PoCL side.
PoCL side: pocl/pocl#2393 (draft) enables SPV_KHR_float_controls2 for the CPU devices with LLVM >= 23. With it, FPFastMathMode AllowContract reaches PoCL as contract and a test kernel compiles to vfmadd. To use this from KA, GPUCompiler still needs to pass +SPV_KHR_float_controls2 to the SPIR-V back-end when the device reports it. I haven't yet checked that the back-end then emits AllowContract on each instruction. Until then, the llvm.fmuladd fusion above is the fix that works today.
Activity
vchuravy commentedon Oct 11, 2026
MWE:
With
POCL_CACHE_DIRset, PoCL's.so.ocontainsvmulsd/vaddsd(andvmulpd/vaddpd), novfmadd.There are two causes:
contractflag.AllowContractonly exists inSPV_KHR_float_controls2.ContractionOffto every kernel entry point unless the module has!opencl.enable.FP_CONTRACT(SPIRVAsmPrinter::outputExecutionMode). Clang emits that metadata for OpenCL C; GPUCompiler doesn't.I tested these variants with a hook in POCL's compiler job (
SPIRV_LLVM_Backend_jll23.1.1, pocl_standalone_jll, x86 with FMA):ContractionOffvmulsd/vaddsd!opencl.enable.FP_CONTRACTContractionOffvmulsd/vaddsdfmul contract+fadd contractintollvm.fmuladdbefore codegenOpExtInst fmavfmadd213sd,vfmadd231pdThe metadata alone doesn't help. PoCL won't contract plain fmul/fadd, and it would also be the wrong semantics, since it allows contracting any fmul/fadd.
Proposed fix: run an IR pass in GPUCompiler's SPIR-V
finish_ir!(next tolower_minimum_maximum!) that fuses single-use contract-flaggedfmul+fadd/fsubintollvm.fmuladd. This fixes all SPIR-V consumers (OpenCL.jl, oneAPI.jl, POCL). One caveat: the back-end lowersfmuladdto OpenCL.stdfma, notmad, which is slow on devices without hardware FMA.Longer term, emit
SPV_KHR_float_controls2(FPFastMathMode AllowContract) and have PoCL accept it. I'm looking into the PoCL side.vchuravy commentedon Oct 11, 2026
PoCL side: pocl/pocl#2393 (draft) enables
SPV_KHR_float_controls2for the CPU devices with LLVM >= 23. With it,FPFastMathMode AllowContractreaches PoCL ascontractand a test kernel compiles tovfmadd. To use this from KA, GPUCompiler still needs to pass+SPV_KHR_float_controls2to the SPIR-V back-end when the device reports it. I haven't yet checked that the back-end then emitsAllowContracton each instruction. Until then, thellvm.fmuladdfusion above is the fix that works today.