[Mlir-commits] [mlir] ee33e90 - [mlir][llvm] Add llvm.intr.modf intrinsic (#222355)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Mon Sep 14 23:46:48 PDT 2026


Author: Letu Ren
Date: 2026-09-15T08:46:43+02:00
New Revision: ee33e90d1a1a064a0e21d28a27fbdb450490686c

URL: https://github.com/llvm/llvm-project/commit/ee33e90d1a1a064a0e21d28a27fbdb450490686c
DIFF: https://github.com/llvm/llvm-project/commit/ee33e90d1a1a064a0e21d28a27fbdb450490686c.diff

LOG: [mlir][llvm] Add llvm.intr.modf intrinsic (#222355)

Assisted-by: grok-4.6 and gpt-5.6-sol

---------

Signed-off-by: Letu Ren <fantasquex at gmail.com>

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/test/Dialect/LLVMIR/invalid.mlir
    mlir/test/Dialect/LLVMIR/roundtrip.mlir
    mlir/test/Target/LLVMIR/Import/fastmath.ll
    mlir/test/Target/LLVMIR/Import/intrinsic.ll
    mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
index d185260126abe..785dd40a174ff 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
@@ -231,6 +231,16 @@ def LLVM_SincosOp : LLVM_TwoResultIntrOp<"sincos", [], [0],
       "functional-type(operands, results)";
   let hasVerifier = 1;
 }
+def LLVM_ModfOp : LLVM_TwoResultIntrOp<"modf", [], [0],
+  [Pure], /*requiresFastmath=*/1> {
+  let arguments =
+      (ins LLVM_ScalarOrVectorOf<LLVM_AnyFloat>:$val,
+      DefaultValuedAttr<LLVM_FastmathFlagsAttr, "{}">:$fastmathFlags);
+  let assemblyFormat = "`(` operands `)` (`fastmath` `` $fastmathFlags^)? "
+      "attr-dict `:` "
+      "functional-type(operands, results)";
+  let hasVerifier = 1;
+}
 
 def LLVM_ASinOp : LLVM_UnaryIntrOpF<"asin">;
 def LLVM_ACosOp : LLVM_UnaryIntrOpF<"acos">;

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 52cd73f521326..114800058f7e6 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -4444,24 +4444,35 @@ void mlir::LLVM::printIndirectBrOpSucessors(
 }
 
 //===----------------------------------------------------------------------===//
-// SincosOp (intrinsic)
+// SincosOp and ModfOp (intrinsics)
 //===----------------------------------------------------------------------===//
 
-LogicalResult LLVM::SincosOp::verify() {
-  auto operandType = getOperand().getType();
-  auto resultType = getResult().getType();
+static LogicalResult verifyHomogeneousStructResult(Operation *op,
+                                                   Type operandType,
+                                                   Type resultType) {
   auto resultStructType =
       mlir::dyn_cast<mlir::LLVM::LLVMStructType>(resultType);
   if (!resultStructType || resultStructType.getBody().size() != 2 ||
       resultStructType.getBody()[0] != operandType ||
       resultStructType.getBody()[1] != operandType) {
-    return emitOpError("expected result type to be an homogeneous struct with "
-                       "two elements matching the operand type, but got ")
+    return op->emitOpError(
+               "expected result type to be a homogeneous struct with "
+               "two elements matching the operand type, but got ")
            << resultType;
   }
   return success();
 }
 
+LogicalResult LLVM::SincosOp::verify() {
+  return verifyHomogeneousStructResult(getOperation(), getVal().getType(),
+                                       getResult().getType());
+}
+
+LogicalResult LLVM::ModfOp::verify() {
+  return verifyHomogeneousStructResult(getOperation(), getVal().getType(),
+                                       getResult().getType());
+}
+
 //===----------------------------------------------------------------------===//
 // AssumeOp (intrinsic)
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index 4ac160aa9f0fb..c2d59c1564a42 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -2299,26 +2299,47 @@ llvm.mlir.ifunc external @foo : !llvm.func<void (ptr, i32)>, !llvm.ptr @alias_re
 // -----
 
 llvm.func @invalid_sincos_nonhomogeneous_return_type(%f: f32) -> () {
-  // expected-error at +1 {{op expected result type to be an homogeneous struct with two elements matching the operand type}}
+  // expected-error at +1 {{op expected result type to be a homogeneous struct with two elements matching the operand type}}
   llvm.intr.sincos(%f) : (f32) -> !llvm.struct<(f32, f64)>
 }
 
 // -----
 
 llvm.func @invalid_sincos_non_struct_return_type(%f: f32) -> () {
-  // expected-error at +1 {{op expected result type to be an homogeneous struct with two elements matching the operand type}}
+  // expected-error at +1 {{op expected result type to be a homogeneous struct with two elements matching the operand type}}
   llvm.intr.sincos(%f) : (f32) -> f32
 }
 
 // -----
 
 llvm.func @invalid_sincos_gt_2_element_struct_return_type(%f: f32) -> () {
-  // expected-error at +1 {{op expected result type to be an homogeneous struct with two elements matching the operand type}}
+  // expected-error at +1 {{op expected result type to be a homogeneous struct with two elements matching the operand type}}
   llvm.intr.sincos(%f) : (f32) -> !llvm.struct<(f32, f32, f32)>
 }
 
 // -----
 
+llvm.func @invalid_modf_nonhomogeneous_return_type(%f: f32) -> () {
+  // expected-error at +1 {{op expected result type to be a homogeneous struct with two elements matching the operand type}}
+  llvm.intr.modf(%f) : (f32) -> !llvm.struct<(f32, f64)>
+}
+
+// -----
+
+llvm.func @invalid_modf_non_struct_return_type(%f: f32) -> () {
+  // expected-error at +1 {{op expected result type to be a homogeneous struct with two elements matching the operand type}}
+  llvm.intr.modf(%f) : (f32) -> f32
+}
+
+// -----
+
+llvm.func @invalid_modf_gt_2_element_struct_return_type(%f: f32) -> () {
+  // expected-error at +1 {{op expected result type to be a homogeneous struct with two elements matching the operand type}}
+  llvm.intr.modf(%f) : (f32) -> !llvm.struct<(f32, f32, f32)>
+}
+
+// -----
+
 module {
   // expected-error at +1 {{'llvm.blockaddress' op expects an existing block label target in the referenced function}}
   %0 = llvm.blockaddress <function = @missing_func, tag = <id = 1>> : !llvm.ptr

diff  --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 59a810116a040..f33cce1b8928e 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -770,6 +770,8 @@ func.func @fastmathFlags(%arg0: f32, %arg1: f32, %arg2: i32, %arg3: vector<2 x f
   %11 = llvm.intr.sin(%arg0) fastmath<fast> : (f32) -> f32
 // CHECK: {{.*}} = llvm.intr.sin(%arg0) fastmath<afn> : (f32) -> f32
   %12 = llvm.intr.sin(%arg0) fastmath<afn> : (f32) -> f32
+// CHECK: {{.*}} = llvm.intr.modf(%arg0) fastmath<ninf> : (f32) -> !llvm.struct<(f32, f32)>
+  %modf = llvm.intr.modf(%arg0) fastmath<ninf> : (f32) -> !llvm.struct<(f32, f32)>
 
 // CHECK: {{.*}} = llvm.intr.vector.reduce.fmin(%arg3) fastmath<nnan> : (vector<2xf32>) -> f32
   %13 = llvm.intr.vector.reduce.fmin(%arg3) fastmath<nnan> : (vector<2xf32>) -> f32

diff  --git a/mlir/test/Target/LLVMIR/Import/fastmath.ll b/mlir/test/Target/LLVMIR/Import/fastmath.ll
index 03d028d491615..89dc10b9b9814 100644
--- a/mlir/test/Target/LLVMIR/Import/fastmath.ll
+++ b/mlir/test/Target/LLVMIR/Import/fastmath.ll
@@ -58,6 +58,7 @@ declare float @llvm.vector.reduce.fmin.v2f32(<2 x float>)
 declare float @llvm.vector.reduce.fmax.v2f32(<2 x float>)
 declare float @llvm.vector.reduce.fminimum.v2f32(<2 x float>)
 declare float @llvm.vector.reduce.fmaximum.v2f32(<2 x float>)
+declare { float, float } @llvm.modf.f32(float)
 
 ; CHECK-LABEL: @fastmath_intr
 define void @fastmath_intr(float %arg1, i32 %arg2, <2 x float> %arg3) {
@@ -77,6 +78,8 @@ define void @fastmath_intr(float %arg1, i32 %arg2, <2 x float> %arg3) {
   %7 = call nnan float @llvm.vector.reduce.fminimum.v2f32(<2 x float> %arg3)
   ; CHECK: %{{.*}} = llvm.intr.vector.reduce.fmaximum({{.*}}) fastmath<nnan> : (vector<2xf32>) -> f32
   %8 = call nnan float @llvm.vector.reduce.fmaximum.v2f32(<2 x float> %arg3)
+  ; CHECK: llvm.intr.modf(%{{.*}}) fastmath<ninf> : (f32) -> !llvm.struct<(f32, f32)>
+  %9 = call ninf { float, float } @llvm.modf.f32(float %arg1)
 
   ret void
 }

diff  --git a/mlir/test/Target/LLVMIR/Import/intrinsic.ll b/mlir/test/Target/LLVMIR/Import/intrinsic.ll
index 694d21c2f9f53..dbc124b339169 100644
--- a/mlir/test/Target/LLVMIR/Import/intrinsic.ll
+++ b/mlir/test/Target/LLVMIR/Import/intrinsic.ll
@@ -69,6 +69,15 @@ define void @frexp_test(float %0, <8 x float> %1) {
   ret void
 }
 
+; CHECK-LABEL:  llvm.func @modf_test
+define void @modf_test(float %0, <8 x float> %1) {
+  ; CHECK:  llvm.intr.modf(%{{.*}}) : (f32) -> !llvm.struct<(f32, f32)>
+  %3 = call { float, float } @llvm.modf.f32(float %0)
+  ; CHECK:  llvm.intr.modf(%{{.*}}) : (vector<8xf32>) -> !llvm.struct<(vector<8xf32>, vector<8xf32>)>
+  %4 = call { <8 x float>, <8 x float> } @llvm.modf.v8f32(<8 x float> %1)
+  ret void
+}
+
 ; CHECK-LABEL:  llvm.func @log_test
 define void @log_test(float %0, <8 x float> %1) {
   ; CHECK:  llvm.intr.log(%{{.*}}) : (f32) -> f32
@@ -1757,6 +1766,8 @@ declare float @llvm.ldexp.f32.i32(float, i32)
 declare <8 x float> @llvm.ldexp.v8f32.i32(<8 x float>, i32)
 declare { float, i32 } @llvm.frexp.f32.i32(float)
 declare { <8 x float>, i32 } @llvm.frexp.v8f32.i32(<8 x float>)
+declare { float, float } @llvm.modf.f32(float)
+declare { <8 x float>, <8 x float> } @llvm.modf.v8f32(<8 x float>)
 declare float @llvm.log.f32(float)
 declare <8 x float> @llvm.log.v8f32(<8 x float>)
 declare float @llvm.log10.f32(float)

diff  --git a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir
index 5268a2772a506..e5a7ec566268e 100644
--- a/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-intrinsics.mlir
@@ -67,6 +67,17 @@ llvm.func @frexp_test(%arg0: f32, %arg1: vector<8xf32>) {
   llvm.return
 }
 
+// CHECK-LABEL: @modf_test
+llvm.func @modf_test(%arg0: f32, %arg1: vector<8xf32>) {
+  // CHECK: call { float, float } @llvm.modf.f32(float %{{.*}})
+  llvm.intr.modf(%arg0) : (f32) -> !llvm.struct<(f32, f32)>
+  // CHECK: call { <8 x float>, <8 x float> } @llvm.modf.v8f32(<8 x float> %{{.*}})
+  llvm.intr.modf(%arg1) : (vector<8xf32>) -> !llvm.struct<(vector<8xf32>, vector<8xf32>)>
+  // CHECK: call ninf { float, float } @llvm.modf.f32(float %{{.*}})
+  llvm.intr.modf(%arg0) fastmath<ninf> : (f32) -> !llvm.struct<(f32, f32)>
+  llvm.return
+}
+
 // CHECK-LABEL: @log_test
 llvm.func @log_test(%arg0: f32, %arg1: vector<8xf32>) {
   // CHECK: call float @llvm.log.f32
@@ -2014,6 +2025,8 @@ llvm.func @vector_scmp(%a: vector<4 x i32>, %b: vector<4 x i32>) -> vector<4 x i
 // CHECK-DAG: declare <8 x float> @llvm.ldexp.v8f32.i32(<8 x float>, i32)
 // CHECK-DAG: declare { float, i32 } @llvm.frexp.f32.i32(float)
 // CHECK-DAG: declare { <8 x float>, i32 } @llvm.frexp.v8f32.i32(<8 x float>)
+// CHECK-DAG: declare { float, float } @llvm.modf.f32(float)
+// CHECK-DAG: declare { <8 x float>, <8 x float> } @llvm.modf.v8f32(<8 x float>)
 // CHECK-DAG: declare float @llvm.log.f32(float)
 // CHECK-DAG: declare <8 x float> @llvm.log.v8f32(<8 x float>)
 // CHECK-DAG: declare float @llvm.log10.f32(float)


        


More information about the Mlir-commits mailing list