[flang] [llvm] [flang][intrinsics] Implement the time intrinsic (PR #133823)

Andre Kuhlenschmidt via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 31 16:20:59 PDT 2025


https://github.com/akuhlens created https://github.com/llvm/llvm-project/pull/133823

This PR implements the nonstandard intrinsic time.


>From 1dbdd5586c181704c4c2ed071ad4dfdcbf90fea2 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Mon, 31 Mar 2025 11:21:42 -0700
Subject: [PATCH] initial commit

---
 flang-rt/lib/runtime/extensions.cpp           |  5 ++++
 flang/docs/Intrinsics.md                      | 23 +++++++++++++++++++
 .../flang/Optimizer/Builder/IntrinsicCall.h   |  1 +
 .../Optimizer/Builder/Runtime/Intrinsics.h    |  3 +++
 flang/include/flang/Runtime/extensions.h      |  3 +++
 flang/lib/Evaluate/intrinsics.cpp             |  1 +
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp | 11 +++++++++
 .../Optimizer/Builder/Runtime/Intrinsics.cpp  |  7 ++++++
 flang/test/Lower/Intrinsics/time.f90          | 20 ++++++++++++++++
 9 files changed, 74 insertions(+)
 create mode 100644 flang/test/Lower/Intrinsics/time.f90

diff --git a/flang-rt/lib/runtime/extensions.cpp b/flang-rt/lib/runtime/extensions.cpp
index 7e9e512778a75..0a6ba6d38f828 100644
--- a/flang-rt/lib/runtime/extensions.cpp
+++ b/flang-rt/lib/runtime/extensions.cpp
@@ -268,5 +268,10 @@ void FORTRAN_PROCEDURE_NAME(qsort)(int *array, int *len, int *isize,
   qsort(array, *len, *isize, compar);
 }
 
+// GNU extension function TIME()
+std::int64_t RTNAME(time)() {
+  return time(nullptr);
+}
+
 } // namespace Fortran::runtime
 } // extern "C"
diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md
index c5c45c2f87d35..38d4e3988a869 100644
--- a/flang/docs/Intrinsics.md
+++ b/flang/docs/Intrinsics.md
@@ -1085,6 +1085,29 @@ end program rename_proc
 This intrinsic is an alias for `CPU_TIME`: supporting both a subroutine and a
 function form.
 
+### Non-Standard Intrinsics: TIME
+
+#### Description
+`TIME()` returns the current time of the system as a INTEGER(8). 
+
+FIXME: Add portability warning.
+
+#### Usage and Info
+
+- **Standard:** GNU extension
+- **Class:** function
+- **Syntax:** `RESULT = TIME()`
+
+#### Example
+```Fortran
+PROGRAM example_time
+  print *, TIME()
+  print *, TIME()
+  call SLEEP(10)
+  print *, TIME()
+END PROGRAM
+```
+
 ### Non-standard Intrinsics: LNBLNK
 This intrinsic is an alias for `LEN_TRIM`, without the optional KIND argument.
 
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index cdbb78224e3b4..9aa4c3a6690b4 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -428,6 +428,7 @@ struct IntrinsicLibrary {
                                mlir::ArrayRef<fir::ExtendedValue> args);
   void genSystemClock(llvm::ArrayRef<fir::ExtendedValue>);
   mlir::Value genTand(mlir::Type, llvm::ArrayRef<mlir::Value>);
+  mlir::Value genTime(mlir::Type, llvm::ArrayRef<mlir::Value>);
   mlir::Value genTrailz(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genTransfer(mlir::Type,
                                  llvm::ArrayRef<fir::ExtendedValue>);
diff --git a/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h b/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
index 51d2dc82f98ae..2e5adf6bd0ab7 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
@@ -65,6 +65,9 @@ void genRandomSeed(fir::FirOpBuilder &, mlir::Location, mlir::Value size,
 void genRename(fir::FirOpBuilder &builder, mlir::Location loc,
                mlir::Value path1, mlir::Value path2, mlir::Value status);
 
+/// generate time runtime call
+mlir::Value genTime(fir::FirOpBuilder &builder, mlir::Location loc);
+
 /// generate runtime call to transfer intrinsic with no size argument
 void genTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
                  mlir::Value resultBox, mlir::Value sourceBox,
diff --git a/flang/include/flang/Runtime/extensions.h b/flang/include/flang/Runtime/extensions.h
index 4e96f253a6c2c..e2da65c98487f 100644
--- a/flang/include/flang/Runtime/extensions.h
+++ b/flang/include/flang/Runtime/extensions.h
@@ -65,6 +65,9 @@ std::int64_t RTNAME(Signal)(std::int64_t number, void (*handler)(int));
 // GNU extension subroutine SLEEP(SECONDS)
 void RTNAME(Sleep)(std::int64_t seconds);
 
+// GNU extension function TIME()
+std::int64_t RTNAME(time)();
+
 // GNU extension function ACCESS(NAME, MODE)
 // TODO: not supported on Windows
 #ifndef _WIN32
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index ae77dc8d11f44..81852cfb4ff02 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -975,6 +975,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
         DefaultInt, Rank::vector, IntrinsicClass::transformationalFunction},
     {"this_image", {OptionalTEAM}, DefaultInt, Rank::scalar,
         IntrinsicClass::transformationalFunction},
+    {"time", {}, TypePattern{IntType, KindCode::exactKind, 8}, Rank::scalar, IntrinsicClass::transformationalFunction},
     {"tiny",
         {{"x", SameReal, Rank::anyOrAssumedRank, Optionality::required,
             common::Intent::In, {ArgFlag::canBeMoldNull}}},
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index e1e2fa875bff3..d4f380379930b 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -904,6 +904,7 @@ static constexpr IntrinsicHandler handlers[]{
     {"threadfence", &I::genThreadFence, {}, /*isElemental=*/false},
     {"threadfence_block", &I::genThreadFenceBlock, {}, /*isElemental=*/false},
     {"threadfence_system", &I::genThreadFenceSystem, {}, /*isElemental=*/false},
+    {"time", &I::genTime, {}, /*isElemental=*/false},
     {"trailz", &I::genTrailz},
     {"transfer",
      &I::genTransfer,
@@ -8371,6 +8372,16 @@ void IntrinsicLibrary::genThreadFenceSystem(
   builder.create<fir::CallOp>(loc, funcOp, noArgs);
 }
 
+// TIME
+mlir::Value
+IntrinsicLibrary::genTime(mlir::Type resultType,
+                          llvm::ArrayRef<mlir::Value> args) {
+  assert(args.size() == 0);
+  return builder.createConvert(loc, resultType, 
+    fir::runtime::genTime(builder, loc));
+}
+
+
 // TRIM
 fir::ExtendedValue
 IntrinsicLibrary::genTrim(mlir::Type resultType,
diff --git a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
index 2f46e7605fe91..183eb03768775 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
@@ -252,6 +252,13 @@ void fir::runtime::genRename(fir::FirOpBuilder &builder, mlir::Location loc,
   builder.create<fir::CallOp>(loc, runtimeFunc, args);
 }
 
+/// generate runtime call to time intrinsic
+mlir::Value fir::runtime::genTime(fir::FirOpBuilder &builder, 
+                                  mlir::Location loc) {
+  auto func = fir::runtime::getRuntimeFunc<mkRTKey(time)>(loc, builder);
+  return builder.create<fir::CallOp>(loc, func, std::nullopt).getResult(0);
+}
+
 /// generate runtime call to transfer intrinsic with no size argument
 void fir::runtime::genTransfer(fir::FirOpBuilder &builder, mlir::Location loc,
                                mlir::Value resultBox, mlir::Value sourceBox,
diff --git a/flang/test/Lower/Intrinsics/time.f90 b/flang/test/Lower/Intrinsics/time.f90
new file mode 100644
index 0000000000000..950a801fc275b
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/time.f90
@@ -0,0 +1,20 @@
+!RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
+
+!CHECK-LABEL: func.func @_QPhostnm_test
+!CHECK-SAME:    %[[dummyHn:.*]]: !fir.boxchar<1> {fir.bindc_name = "hn"}) -> i32 {
+function time_test())
+  Integer, kind(8) :: time_test 
+
+  ! Check that _FortranAHostnm is called with boxed char 255, some other char
+  ! string of variable length (source file path) and some integer (source line)
+  !CHECK-DAG:   %[[func_result:.*]] = fir.alloca i64 {bindc_name = "time_test", uniq_name = "_QFtime_testEtime_test"}
+  !CHECK-DAG:   %[[func_result_decl:.*]]:{{.*}} = hlfir.declare %[[func_result]] {uniq_name = "_QFtime_testEtime_test"} : {{.*}}fir.ref<i64>{{.*}}
+  !CHECK:     %[[call_result:.*]] = fir.call @_FortranAtime()
+  !CHECK-SAME:  -> i64
+
+  ! Check _FortranAHostnm result code handling
+  !CHECK-DAG:   hlfir.assign %[[call_result]] to %[[func_result_decl]]{{.*}}i64{{.*}}
+  !CHECK-DAG:   %[[load_result:.*]] = fir.load %[[func_result_decl]]{{.*}}i64{{.*}}
+  !CHECK:     return %[[load_result]] : i64
+  time_test = time()
+end function time_test



More information about the llvm-commits mailing list