[llvm] [SPIR-V] Add support for OpFMod intrinsic (PR #193172)
Arseniy Obolenskiy via llvm-commits
llvm-commits at lists.llvm.org
Thu May 7 09:00:11 PDT 2026
https://github.com/aobolensk updated https://github.com/llvm/llvm-project/pull/193172
>From 7ec8b3bd3eb374c2528a134f55465006b66f2857 Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Tue, 21 Apr 2026 11:54:26 +0200
Subject: [PATCH 1/2] [SPIR-V] Add support for OpFMod intrinsic
Add the spv.fmod intrinsic and lower it directly to SPIRV::OpFMod covering scalar and vector cases
---
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 +
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 5 +++++
.../scalar-floating-point-arithmetic.ll | 16 +++++++++++++++-
.../vector-floating-point-arithmetic.ll | 17 ++++++++++++++++-
4 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index d2a5fa1f08724..67f890d1d6dac 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -98,6 +98,7 @@ let TargetPrefix = "spv" in {
def int_spv_degrees : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_distance : DefaultAttrsIntrinsic<[LLVMVectorElementType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_faceforward : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
+ def int_spv_fmod : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_frac : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>],
[llvm_anyfloat_ty], [IntrNoMem]>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index f1e0450bb20f9..8a4efd631e851 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -677,6 +677,7 @@ static bool intrinsicHasSideEffects(Intrinsic::ID ID) {
case Intrinsic::spv_firstbitlow:
case Intrinsic::spv_firstbitshigh:
case Intrinsic::spv_firstbituhigh:
+ case Intrinsic::spv_fmod:
case Intrinsic::spv_frac:
case Intrinsic::spv_gep:
case Intrinsic::spv_global_offset:
@@ -4763,6 +4764,10 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
case Intrinsic::spv_faceforward:
return selectExtInst(ResVReg, ResType, I, GL::FaceForward);
+ case Intrinsic::spv_fmod:
+ return selectOpWithSrcs(
+ ResVReg, ResType, I,
+ {I.getOperand(2).getReg(), I.getOperand(3).getReg()}, SPIRV::OpFMod);
case Intrinsic::spv_frac:
return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
case Intrinsic::spv_isinf:
diff --git a/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll b/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll
index b04db946f36d0..0856a33ac3bb8 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll
@@ -8,7 +8,7 @@
; CHECK-DAG: OpName [[SCALAR_FDIV:%.+]] "scalar_fdiv"
; CHECK-DAG: OpName [[SCALAR_FREM:%.+]] "scalar_frem"
; CHECK-DAG: OpName [[SCALAR_FMA:%.+]] "scalar_fma"
-;; FIXME: add test for OpFMod
+; CHECK-DAG: OpName [[SCALAR_FMOD:%.+]] "scalar_fmod"
; CHECK-NOT: DAG-FENCE
@@ -109,6 +109,20 @@ define float @scalar_frem(float %a, float %b) {
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
+;; Test fmod on scalar:
+define float @scalar_fmod(float %a, float %b) {
+ %c = call float @llvm.spv.fmod.f32(float %a, float %b)
+ ret float %c
+}
+
+; CHECK: [[SCALAR_FMOD]] = OpFunction [[SCALAR]] None [[SCALAR_FN]]
+; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[SCALAR]]
+; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[SCALAR]]
+; CHECK: OpLabel
+; CHECK: [[C:%.+]] = OpFMod [[SCALAR]] [[A]] [[B]]
+; CHECK: OpReturnValue [[C]]
+; CHECK-NEXT: OpFunctionEnd
+
declare float @llvm.fma.f32(float, float, float)
;; Test fma on scalar:
diff --git a/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll b/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll
index 0b0e505829ed1..67f427c52aeae 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll
@@ -7,7 +7,7 @@
; CHECK-DAG: OpName [[VECTOR_FMUL:%.+]] "vector_fmul"
; CHECK-DAG: OpName [[VECTOR_FDIV:%.+]] "vector_fdiv"
; CHECK-DAG: OpName [[VECTOR_FREM:%.+]] "vector_frem"
-;; TODO: add test for OpFMod
+; CHECK-DAG: OpName [[VECTOR_FMOD:%.+]] "vector_fmod"
; CHECK-NOT: DAG-FENCE
@@ -106,3 +106,18 @@ define <2 x half> @vector_frem(<2 x half> %a, <2 x half> %b) {
; CHECK: [[C:%.+]] = OpFRem [[VECTOR]] [[A]] [[B]]
; CHECK: OpReturnValue [[C]]
; CHECK-NEXT: OpFunctionEnd
+
+
+;; Test fmod on vector:
+define <2 x half> @vector_fmod(<2 x half> %a, <2 x half> %b) {
+ %c = call <2 x half> @llvm.spv.fmod.v2f16(<2 x half> %a, <2 x half> %b)
+ ret <2 x half> %c
+}
+
+; CHECK: [[VECTOR_FMOD]] = OpFunction [[VECTOR]] None [[VECTOR_FN]]
+; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[VECTOR]]
+; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[VECTOR]]
+; CHECK: OpLabel
+; CHECK: [[C:%.+]] = OpFMod [[VECTOR]] [[A]] [[B]]
+; CHECK: OpReturnValue [[C]]
+; CHECK-NEXT: OpFunctionEnd
>From 0666b30b503e84ad84ba59ac235d6c3b37be951c Mon Sep 17 00:00:00 2001
From: Arseniy Obolenskiy <arseniy.obolenskiy at amd.com>
Date: Thu, 7 May 2026 17:59:58 +0200
Subject: [PATCH 2/2] Address review comment
---
llvm/include/llvm/IR/IntrinsicsSPIRV.td | 1 -
llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp | 18 ++++++++++++++++++
llvm/lib/Target/SPIRV/SPIRVBuiltins.td | 4 ++++
.../Target/SPIRV/SPIRVInstructionSelector.cpp | 5 -----
.../scalar-floating-point-arithmetic.ll | 6 ++++--
.../vector-floating-point-arithmetic.ll | 6 ++++--
6 files changed, 30 insertions(+), 10 deletions(-)
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 67f890d1d6dac..d2a5fa1f08724 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -98,7 +98,6 @@ let TargetPrefix = "spv" in {
def int_spv_degrees : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_distance : DefaultAttrsIntrinsic<[LLVMVectorElementType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_faceforward : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem]>;
- def int_spv_fmod : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty, LLVMMatchType<0>], [IntrNoMem]>;
def int_spv_frac : DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty], [IntrNoMem]>;
def int_spv_isinf : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>],
[llvm_anyfloat_ty], [IntrNoMem]>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 1e6d3c52990f7..b0e345dcc2c59 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -2135,6 +2135,21 @@ static bool generateMulExtendedInst(const SPIRV::IncomingCall *Call,
return true;
}
+static bool generateArithmeticInst(const SPIRV::IncomingCall *Call,
+ MachineIRBuilder &MIRBuilder,
+ SPIRVGlobalRegistry *GR) {
+ const SPIRV::DemangledBuiltin *Builtin = Call->Builtin;
+ unsigned Opcode =
+ SPIRV::lookupNativeBuiltin(Builtin->Name, Builtin->Set)->Opcode;
+
+ auto MIB = MIRBuilder.buildInstr(Opcode)
+ .addDef(Call->ReturnRegister)
+ .addUse(GR->getSPIRVTypeID(Call->ReturnType));
+ for (Register Arg : Call->Arguments)
+ MIB.addUse(Arg);
+ return true;
+}
+
static bool generateGetQueryInst(const SPIRV::IncomingCall *Call,
MachineIRBuilder &MIRBuilder,
SPIRVGlobalRegistry *GR) {
@@ -3342,6 +3357,7 @@ mapBuiltinToOpcode(const StringRef DemangledCall,
case SPIRV::AsyncCopy:
case SPIRV::LoadStore:
case SPIRV::CoopMatr:
+ case SPIRV::Arithmetic:
if (const auto *R =
SPIRV::lookupNativeBuiltin(Call->Builtin->Name, Call->Builtin->Set))
return std::make_tuple(Call->Builtin->Group, R->Opcode, 0);
@@ -3455,6 +3471,8 @@ std::optional<bool> lowerBuiltin(const StringRef DemangledCall,
return generateICarryBorrowInst(Call.get(), MIRBuilder, GR);
case SPIRV::MulExtended:
return generateMulExtendedInst(Call.get(), MIRBuilder, GR);
+ case SPIRV::Arithmetic:
+ return generateArithmeticInst(Call.get(), MIRBuilder, GR);
case SPIRV::GetQuery:
return generateGetQueryInst(Call.get(), MIRBuilder, GR);
case SPIRV::ImageSizeQuery:
diff --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
index 2bebf95940033..f83f98038a55a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
@@ -72,6 +72,7 @@ def TernaryBitwiseINTEL : BuiltinGroup;
def Block2DLoadStore : BuiltinGroup;
def Pipe : BuiltinGroup;
def PredicatedLoadStore : BuiltinGroup;
+def Arithmetic : BuiltinGroup;
def ArbitraryPrecisionFixedPoint : BuiltinGroup;
def BlockingPipes : BuiltinGroup;
def ImageChannelDataTypes : BuiltinGroup;
@@ -681,6 +682,9 @@ defm : DemangledNativeBuiltin<"__spirv_ISubBorrow", OpenCL_std, ICarryBorrow, 3,
defm : DemangledNativeBuiltin<"__spirv_UMulExtended", OpenCL_std, MulExtended, 2, 3, OpUMulExtended>;
defm : DemangledNativeBuiltin<"__spirv_SMulExtended", OpenCL_std, MulExtended, 2, 3, OpSMulExtended>;
+// Arithmetic builtin records:
+defm : DemangledNativeBuiltin<"__spirv_FMod", OpenCL_std, Arithmetic, 2, 2, OpFMod>;
+
// cl_intel_split_work_group_barrier
defm : DemangledNativeBuiltin<"intel_work_group_barrier_arrive", OpenCL_std, Barrier, 1, 2, OpControlBarrierArriveINTEL>;
defm : DemangledNativeBuiltin<"__spirv_ControlBarrierArriveINTEL", OpenCL_std, Barrier, 3, 3, OpControlBarrierArriveINTEL>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 8a4efd631e851..f1e0450bb20f9 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -677,7 +677,6 @@ static bool intrinsicHasSideEffects(Intrinsic::ID ID) {
case Intrinsic::spv_firstbitlow:
case Intrinsic::spv_firstbitshigh:
case Intrinsic::spv_firstbituhigh:
- case Intrinsic::spv_fmod:
case Intrinsic::spv_frac:
case Intrinsic::spv_gep:
case Intrinsic::spv_global_offset:
@@ -4764,10 +4763,6 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
return selectExtInst(ResVReg, ResType, I, CL::degrees, GL::Degrees);
case Intrinsic::spv_faceforward:
return selectExtInst(ResVReg, ResType, I, GL::FaceForward);
- case Intrinsic::spv_fmod:
- return selectOpWithSrcs(
- ResVReg, ResType, I,
- {I.getOperand(2).getReg(), I.getOperand(3).getReg()}, SPIRV::OpFMod);
case Intrinsic::spv_frac:
return selectExtInst(ResVReg, ResType, I, CL::fract, GL::Fract);
case Intrinsic::spv_isinf:
diff --git a/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll b/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll
index 0856a33ac3bb8..bdad95a1615bc 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/scalar-floating-point-arithmetic.ll
@@ -110,11 +110,13 @@ define float @scalar_frem(float %a, float %b) {
; CHECK-NEXT: OpFunctionEnd
;; Test fmod on scalar:
-define float @scalar_fmod(float %a, float %b) {
- %c = call float @llvm.spv.fmod.f32(float %a, float %b)
+define spir_func float @scalar_fmod(float %a, float %b) {
+ %c = call spir_func float @_Z12__spirv_FModff(float %a, float %b)
ret float %c
}
+declare spir_func float @_Z12__spirv_FModff(float, float)
+
; CHECK: [[SCALAR_FMOD]] = OpFunction [[SCALAR]] None [[SCALAR_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[SCALAR]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[SCALAR]]
diff --git a/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll b/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll
index 67f427c52aeae..e79b3a6595a0f 100644
--- a/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll
+++ b/llvm/test/CodeGen/SPIRV/instructions/vector-floating-point-arithmetic.ll
@@ -109,11 +109,13 @@ define <2 x half> @vector_frem(<2 x half> %a, <2 x half> %b) {
;; Test fmod on vector:
-define <2 x half> @vector_fmod(<2 x half> %a, <2 x half> %b) {
- %c = call <2 x half> @llvm.spv.fmod.v2f16(<2 x half> %a, <2 x half> %b)
+define spir_func <2 x half> @vector_fmod(<2 x half> %a, <2 x half> %b) {
+ %c = call spir_func <2 x half> @_Z12__spirv_FModDv2_DhS_(<2 x half> %a, <2 x half> %b)
ret <2 x half> %c
}
+declare spir_func <2 x half> @_Z12__spirv_FModDv2_DhS_(<2 x half>, <2 x half>)
+
; CHECK: [[VECTOR_FMOD]] = OpFunction [[VECTOR]] None [[VECTOR_FN]]
; CHECK-NEXT: [[A:%.+]] = OpFunctionParameter [[VECTOR]]
; CHECK-NEXT: [[B:%.+]] = OpFunctionParameter [[VECTOR]]
More information about the llvm-commits
mailing list