Skip to content

Conversation

@JDPailleux
Copy link
Contributor

This PR adds support of RAND, IRAND and SRAND intrinsics in Flang, which are part of the GNU extension.
These intrinsics are used in the following benchmark: floatingspeed

@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Nov 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2025

@llvm/pr-subscribers-flang-semantics

@llvm/pr-subscribers-flang-fir-hlfir

Author: Jean-Didier PAILLEUX (JDPailleux)

Changes

This PR adds support of RAND, IRAND and SRAND intrinsics in Flang, which are part of the GNU extension.
These intrinsics are used in the following benchmark: floatingspeed


Full diff: https://github.com/llvm/llvm-project/pull/166780.diff

4 Files Affected:

  • (modified) flang-rt/lib/runtime/extensions.cpp (+23)
  • (modified) flang/docs/Intrinsics.md (+43)
  • (modified) flang/include/flang/Runtime/extensions.h (+9)
  • (added) flang/test/Lower/Intrinsics/rand.f90 (+41)
diff --git a/flang-rt/lib/runtime/extensions.cpp b/flang-rt/lib/runtime/extensions.cpp
index 19e75143705ab..366406d2a71e4 100644
--- a/flang-rt/lib/runtime/extensions.cpp
+++ b/flang-rt/lib/runtime/extensions.cpp
@@ -398,6 +398,29 @@ std::int64_t RTNAME(time)() { return time(nullptr); }
 // MCLOCK: returns accumulated CPU time in ticks
 std::int32_t FORTRAN_PROCEDURE_NAME(mclock)() { return std::clock(); }
 
+// IRAND(I)
+int FORTRAN_PROCEDURE_NAME(irand)(int i) {
+  switch (i) {
+  case 0:
+    break;
+  case 1:
+    FORTRAN_PROCEDURE_NAME(srand)(0);
+    break;
+  default:
+    FORTRAN_PROCEDURE_NAME(srand)(i);
+    break;
+  }
+  return rand();
+}
+
+// RAND(I)
+float FORTRAN_PROCEDURE_NAME(rand)(int i) {
+  return (float)(FORTRAN_PROCEDURE_NAME(irand)(i));
+}
+
+// SRAND(SEED)
+void FORTRAN_PROCEDURE_NAME(srand)(int seed) { srand(seed); }
+
 // Extension procedures related to I/O
 
 namespace io {
diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md
index bfda5f3253a68..af20892edd201 100644
--- a/flang/docs/Intrinsics.md
+++ b/flang/docs/Intrinsics.md
@@ -1379,3 +1379,46 @@ This is prefixed by `STRING`, a colon and a space.
 - **Standard:** GNU extension
 - **Class:** subroutine
 - **Syntax:** `CALL PERROR(STRING)`
+
+
+### Non-Standard Intrinsics: SRAND
+
+#### Description
+`SAND` reinitializes the pseudo-random number generator called by `RAND` and `IRAND`.
+The new seed used by the generator is specified by the required argument `SEED`.
+
+#### Usage and Info
+
+- **Standard:** GNU extension
+- **Class:** Subroutine
+- **Syntax:** `CALL SRAND(SEED)`
+
+### Non-Standard Intrinsics: IRAND
+
+#### Description
+`IRAND(FLAG)` returns a pseudo-random number from a uniform distribution between 0 and 1.
+If `FLAG` is 0, the next number in the current sequence is returned;
+If `FLAG` is 1, the generator is restarted by `CALL SRAND(0)`;
+If `FLAG` has any other value, it is used as a new seed with `SRAND`.
+The return value is of `INTEGER` type of kind 4.
+
+#### Usage and Info
+
+- **Standard:** GNU extension
+- **Class:** function
+- **Syntax:** `RESULT = IRAND(I)`
+
+### Non-Standard Intrinsics: RAND
+
+#### Description
+`RAND(FLAG)` returns a pseudo-random number from a uniform distribution between 0 and 1.
+If `FLAG` is 0, the next number in the current sequence is returned;
+If `FLAG` is 1, the generator is restarted by `CALL SRAND(0)`;
+If `FLAG` has any other value, it is used as a new seed with `SRAND`.
+The return value is of `REAL` type with the default kind.
+
+#### Usage and Info
+
+- **Standard:** GNU extension
+- **Class:** function
+- **Syntax:** `RESULT = RAND(I)`
diff --git a/flang/include/flang/Runtime/extensions.h b/flang/include/flang/Runtime/extensions.h
index 9fd3e118a0f22..73a458b26e2d7 100644
--- a/flang/include/flang/Runtime/extensions.h
+++ b/flang/include/flang/Runtime/extensions.h
@@ -101,5 +101,14 @@ int FORTRAN_PROCEDURE_NAME(mclock)();
 float FORTRAN_PROCEDURE_NAME(secnds)(float *refTime);
 float RTNAME(Secnds)(float *refTime, const char *sourceFile, int line);
 
+// GNU extension function IRAND(I)
+int FORTRAN_PROCEDURE_NAME(irand)(int i = 0);
+
+// GNU extension function RAND(I)
+float FORTRAN_PROCEDURE_NAME(rand)(int i = 0);
+
+// GNU extension subroutine SRAND(SEED)
+void FORTRAN_PROCEDURE_NAME(srand)(int seed);
+
 } // extern "C"
 #endif // FORTRAN_RUNTIME_EXTENSIONS_H_
diff --git a/flang/test/Lower/Intrinsics/rand.f90 b/flang/test/Lower/Intrinsics/rand.f90
new file mode 100644
index 0000000000000..488242fb9180d
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/rand.f90
@@ -0,0 +1,41 @@
+! RUN: bbc -emit-hlfir %s -o - | FileCheck --check-prefixes=CHECK %s
+! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck --check-prefixes=CHECK %s
+
+! CHECK-LABEL: func @_QPtest_srand(
+subroutine test_srand()
+  integer :: seed = 0
+  call srand(seed)
+  ! CHECK: %[[VAL_0:.*]] = fir.address_of(@_QFtest_srandEseed) : !fir.ref<i32> 
+  ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_srandEseed"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+  ! CHECK: fir.call @_QPsrand(%[[VAL_1]]#0) fastmath<contract> : (!fir.ref<i32>) -> () 
+  ! CHECK: return
+end subroutine test_srand
+
+! CHECK-LABEL: func @_QPtest_irand(
+subroutine test_irand()
+  integer :: seed = 0
+  integer :: result
+  result = irand(seed)
+  ! CHECK: %[[VAL_0:.*]] = fir.alloca i32 {bindc_name = "result", uniq_name = "_QFtest_irandEresult"} 
+  ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_irandEresult"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+  ! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QFtest_irandEseed) : !fir.ref<i32> 
+  ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFtest_irandEseed"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+  ! CHECK: %[[VAL_4:.*]] = fir.call @_QPirand(%[[VAL_3]]#0) fastmath<contract> : (!fir.ref<i32>) -> i32
+  ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_1]]#0 : i32, !fir.ref<i32>
+  ! CHECK: return
+end subroutine test_irand
+
+! CHECK-LABEL: func @_QPtest_rand(
+subroutine test_rand()
+  integer :: seed = 0
+  real :: result
+  result = rand(seed)
+  ! CHECK: %[[VAL_0:.*]] = fir.alloca f32 {bindc_name = "result", uniq_name = "_QFtest_randEresult"} 
+  ! CHECK: %[[VAL_1:.*]]:2 = hlfir.declare %[[VAL_0]] {uniq_name = "_QFtest_randEresult"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+  ! CHECK: %[[VAL_2:.*]] = fir.address_of(@_QFtest_randEseed) : !fir.ref<i32> 
+  ! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_2]] {uniq_name = "_QFtest_randEseed"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+  ! CHECK: %[[VAL_4:.*]] = fir.call @_QPrand(%[[VAL_3]]#0) fastmath<contract> : (!fir.ref<i32>) -> f32
+  ! CHECK: hlfir.assign %[[VAL_4]] to %[[VAL_1]]#0 : f32, !fir.ref<f32>
+  ! CHECK: return
+end subroutine test_rand
+

@klausler klausler removed their request for review November 6, 2025 16:26
Copy link
Contributor

@tblah tblah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with the typo fixed

@JDPailleux
Copy link
Contributor Author

Thanks

### Non-Standard Intrinsics: IRAND

#### Description
`IRAND(FLAG)` returns a pseudo-random number from a uniform distribution between 0 and 1.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

irand returns an integer. Is it only 0 or 1?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another copy past typo. It returns an integer between 0 and a system-dependent limit

### Non-Standard Intrinsics: RAND

#### Description
`RAND(FLAG)` returns a pseudo-random number from a uniform distribution between 0 and a system-dependent limit.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really "system-dependent limit"? gfortran's rand returns random numbers between 0 and 1.

@kkwli
Copy link
Collaborator

kkwli commented Nov 17, 2025

I get the same random number with rand(0).

$ cat rand.f90
do i=1, 5
  print *, rand(0)
enddo
end

$ bin/flang -frtlib-add-rpath rand.f90

$ a.out
 1.9679691E+09
 1.9679691E+09
 1.9679691E+09
 1.9679691E+09
 1.9679691E+09

gfortran gives the following output:

$ gfortran rand.f90
$ a.out
   7.62939453E-06
  0.131537676    
  0.755605221    
  0.458650112    
  0.532767057    

@JDPailleux
Copy link
Contributor Author

Hello, here is an update for RAND and IRAND.
I based the implementation of the GNU extension and no longer naively use the rand() and srand() functions.

@github-actions
Copy link

github-actions bot commented Nov 20, 2025

🐧 Linux x64 Test Results

  • 4061 tests passed
  • 202 tests skipped

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:fir-hlfir flang:semantics flang Flang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants