[flang-commits] [flang] [flang] Use llvm.llround for an INTEGER(8) NINT result (PR #224580)

Martin Schlipf via flang-commits flang-commits at lists.llvm.org
Fri Sep 18 02:46:01 PDT 2026


https://github.com/martin-schlipf created https://github.com/llvm/llvm-project/pull/224580

NINT with an INTEGER(8) result lowered to llvm.lround, which lowers to a call to lround. lround returns a C long, so it is only 64 bits wide on an LP64 target. On an ILP32 target the call returns 32 bits where an i64 is expected: on i386 the result is silently truncated, and the WebAssembly backend emits an invalid module ("local.set's value type must be correct") rather than diagnosing the mismatch.

llround returns a long long and is therefore 64 bits everywhere. The REAL(16) row of the same table already uses LlroundF128 for its INTEGER(8) result, so this makes the REAL(4) and REAL(8) rows consistent with it.

The INTEGER(4) rows keep llvm.lround, which is correct: a C int and a C long are both at least 32 bits on every supported target.

>From e1261ebb53ef2bf6de1b58d55bfc23480445ccff Mon Sep 17 00:00:00 2001
From: Martin Schlipf <martin.schlipf at vasp.at>
Date: Tue, 8 Sep 2026 12:03:40 +0200
Subject: [PATCH] [flang] Use llvm.llround for an INTEGER(8) NINT result

NINT with an INTEGER(8) result lowered to llvm.lround, which lowers to a
call to lround. lround returns a C long, so it is only 64 bits wide on an
LP64 target. On an ILP32 target the call returns 32 bits where an i64 is
expected: on i386 the result is silently truncated, and the WebAssembly
backend emits an invalid module ("local.set's value type must be correct")
rather than diagnosing the mismatch.

llround returns a long long and is therefore 64 bits everywhere. The
REAL(16) row of the same table already uses LlroundF128 for its INTEGER(8)
result, so this makes the REAL(4) and REAL(8) rows consistent with it.

The INTEGER(4) rows keep llvm.lround, which is correct: a C int and a C
long are both at least 32 bits on every supported target.
---
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp |  7 +++++--
 flang/test/Lower/Intrinsics/nint.f90          | 11 ++++++++++-
 flang/test/Lower/math-lowering/nint.f90       |  8 ++++----
 3 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 2bdbad156c0b0..ef30071f3c96f 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -1456,9 +1456,12 @@ static constexpr MathOperation mathOperations[] = {
     {"nearbyint", RTNAME_STRING(NearbyintF128), FuncTypeReal16Real16,
      genLibF128Call},
     // llvm.lround behaves the same way as libm's lround.
-    {"nint", "llvm.lround.i64.f64", genFuncType<Ty::Integer<8>, Ty::Real<8>>,
+    // An INTEGER(8) result must use llvm.llround: llvm.lround lowers to a call
+    // to lround, which returns a C long and is therefore only 64 bits wide on
+    // LP64 targets. llround returns a long long and is 64 bits everywhere.
+    {"nint", "llvm.llround.i64.f64", genFuncType<Ty::Integer<8>, Ty::Real<8>>,
      genLibCall},
-    {"nint", "llvm.lround.i64.f32", genFuncType<Ty::Integer<8>, Ty::Real<4>>,
+    {"nint", "llvm.llround.i64.f32", genFuncType<Ty::Integer<8>, Ty::Real<4>>,
      genLibCall},
     {"nint", RTNAME_STRING(LlroundF128), FuncTypeInteger8Real16,
      genLibF128Call},
diff --git a/flang/test/Lower/Intrinsics/nint.f90 b/flang/test/Lower/Intrinsics/nint.f90
index 166fdac90d8e1..7ccf3397463e7 100644
--- a/flang/test/Lower/Intrinsics/nint.f90
+++ b/flang/test/Lower/Intrinsics/nint.f90
@@ -12,5 +12,14 @@ subroutine nint_test2(i, a)
     integer(8) :: i
     real(8) :: a
     i = nint(a, 8)
-    ! CHECK: fir.call @llvm.lround.i64.f64
+    ! An INTEGER(8) result must not use lround: it returns a C long, which is
+    ! 32 bits wide on an ILP32 target.
+    ! CHECK: fir.call @llvm.llround.i64.f64
+  end subroutine
+  ! CHECK-LABEL: nint_test3
+  subroutine nint_test3(i, a)
+    integer(8) :: i
+    real(4) :: a
+    i = nint(a, 8)
+    ! CHECK: fir.call @llvm.llround.i64.f32
   end subroutine
diff --git a/flang/test/Lower/math-lowering/nint.f90 b/flang/test/Lower/math-lowering/nint.f90
index f5f5bc44ae329..55276aba83053 100644
--- a/flang/test/Lower/math-lowering/nint.f90
+++ b/flang/test/Lower/math-lowering/nint.f90
@@ -12,7 +12,7 @@ function test_real4(x)
 
 ! ALL-LABEL: @_QPtest_real4
 ! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i32.f32({{%[A-Za-z0-9._]+}}) {{.*}}: (f32) -> i32
-! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i64.f32({{%[A-Za-z0-9._]+}}) {{.*}}: (f32) -> i64
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.llround.i64.f32({{%[A-Za-z0-9._]+}}) {{.*}}: (f32) -> i64
 
 function test_real8(x)
   real(8) :: x, test_real8
@@ -21,9 +21,9 @@ function test_real8(x)
 
 ! ALL-LABEL: @_QPtest_real8
 ! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i32.f64({{%[A-Za-z0-9._]+}}) {{.*}}: (f64) -> i32
-! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.lround.i64.f64({{%[A-Za-z0-9._]+}}) {{.*}}: (f64) -> i64
+! ALL: {{%[A-Za-z0-9._]+}} = fir.call @llvm.llround.i64.f64({{%[A-Za-z0-9._]+}}) {{.*}}: (f64) -> i64
 
 ! ALL-DAG: func.func private @llvm.lround.i32.f32(f32) -> i32 attributes {fir.bindc_name = "llvm.lround.i32.f32", fir.runtime}
-! ALL-DAG: func.func private @llvm.lround.i64.f32(f32) -> i64 attributes {fir.bindc_name = "llvm.lround.i64.f32", fir.runtime}
+! ALL-DAG: func.func private @llvm.llround.i64.f32(f32) -> i64 attributes {fir.bindc_name = "llvm.llround.i64.f32", fir.runtime}
 ! ALL-DAG: func.func private @llvm.lround.i32.f64(f64) -> i32 attributes {fir.bindc_name = "llvm.lround.i32.f64", fir.runtime}
-! ALL-DAG: func.func private @llvm.lround.i64.f64(f64) -> i64 attributes {fir.bindc_name = "llvm.lround.i64.f64", fir.runtime}
+! ALL-DAG: func.func private @llvm.llround.i64.f64(f64) -> i64 attributes {fir.bindc_name = "llvm.llround.i64.f64", fir.runtime}



More information about the flang-commits mailing list