[flang-commits] [flang] [llvm] [flang][flang-rt] Add support for non-standard TIMEF intrinsic (PR #185377)

via flang-commits flang-commits at lists.llvm.org
Mon Mar 9 03:43:40 PDT 2026


https://github.com/NimishMishra updated https://github.com/llvm/llvm-project/pull/185377

>From 22bf5067bd20110e3d09820d99453206cf731dd4 Mon Sep 17 00:00:00 2001
From: NimishMishra <neelam.nimish at gmail.com>
Date: Mon, 9 Mar 2026 12:37:26 +0530
Subject: [PATCH 1/3] [flang][flang-rt] Implement non-standard TIMEF intrinsic

---
 flang-rt/lib/runtime/extensions.cpp               | 13 +++++++++++++
 flang-rt/unittests/Runtime/Time.cpp               | 14 ++++++++++++++
 .../flang/Optimizer/Builder/IntrinsicCall.h       |  1 +
 .../flang/Optimizer/Builder/Runtime/Intrinsics.h  |  3 +++
 flang/include/flang/Runtime/time-intrinsic.h      |  3 +++
 flang/lib/Evaluate/intrinsics.cpp                 |  1 +
 flang/lib/Optimizer/Builder/IntrinsicCall.cpp     |  8 ++++++++
 .../lib/Optimizer/Builder/Runtime/Intrinsics.cpp  |  8 ++++++++
 flang/test/Lower/Intrinsics/timef.f90             | 15 +++++++++++++++
 9 files changed, 66 insertions(+)
 create mode 100644 flang/test/Lower/Intrinsics/timef.f90

diff --git a/flang-rt/lib/runtime/extensions.cpp b/flang-rt/lib/runtime/extensions.cpp
index b06b9eabe2c60..126cadadc1619 100644
--- a/flang-rt/lib/runtime/extensions.cpp
+++ b/flang-rt/lib/runtime/extensions.cpp
@@ -413,6 +413,19 @@ double RTNAME(Dsecnds)(double *refTime, const char *sourceFile, int line) {
 // GNU extension function TIME()
 std::int64_t RTNAME(time)() { return time(nullptr); }
 
+// Intel extension function TIMEF()
+// Returns number of seconds that have elapsed since the first time 
+// TIMEF was called. For the first call, it returns 0.
+double RTNAME(Timef)() {
+        static double first = -1;
+	if(first < 0){
+		first = time(nullptr);
+		return 0;
+	}
+	else
+		return time(nullptr) - first;
+}
+
 // MCLOCK: returns accumulated CPU time in ticks
 std::int32_t FORTRAN_PROCEDURE_NAME(mclock)() { return std::clock(); }
 
diff --git a/flang-rt/unittests/Runtime/Time.cpp b/flang-rt/unittests/Runtime/Time.cpp
index 548c0834e34a3..be668e9a8f3c2 100644
--- a/flang-rt/unittests/Runtime/Time.cpp
+++ b/flang-rt/unittests/Runtime/Time.cpp
@@ -31,6 +31,20 @@ TEST(TimeIntrinsics, CpuTime) {
   }
 }
 
+TEST(TimeIntrinsics, Timef) {
+  // We can't really test that we get the "right" result for Timef, but we
+  // can have a smoke test to see that we get something reasonable on the
+  // platforms where we expect to support it.
+  double start{RTNAME(Timef)()};
+  ASSERT_GE(start, 0.0);
+
+  // Loop until we get a different value from Timef
+  for (double end = start; end == start; end = RTNAME(CpuTime)()) {
+    ASSERT_GE(end, 0.0);
+    ASSERT_GE(end, start);
+  }
+}
+
 using count_t = std::int64_t;
 
 TEST(TimeIntrinsics, SystemClock) {
diff --git a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
index 3ef4045518cc4..ac1fdd8f27db9 100644
--- a/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
+++ b/flang/include/flang/Optimizer/Builder/IntrinsicCall.h
@@ -214,6 +214,7 @@ struct IntrinsicLibrary {
   void genExecuteCommandLine(mlir::ArrayRef<fir::ExtendedValue> args);
   fir::ExtendedValue genEtime(std::optional<mlir::Type>,
                               mlir::ArrayRef<fir::ExtendedValue> args);
+  mlir::Value genTimef(mlir::Type resultType, llvm::ArrayRef<mlir::Value> args);
   mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
   fir::ExtendedValue genExtendsTypeOf(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 1f751827309a4..d6f0f5051e219 100644
--- a/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
+++ b/flang/include/flang/Optimizer/Builder/Runtime/Intrinsics.h
@@ -82,6 +82,9 @@ mlir::Value genSecnds(fir::FirOpBuilder &builder, mlir::Location loc,
 /// generate time runtime call
 mlir::Value genTime(fir::FirOpBuilder &builder, mlir::Location loc);
 
+/// generate timef runtime call
+mlir::Value genTimef(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/time-intrinsic.h b/flang/include/flang/Runtime/time-intrinsic.h
index 80490a17e4559..4df151451d735 100644
--- a/flang/include/flang/Runtime/time-intrinsic.h
+++ b/flang/include/flang/Runtime/time-intrinsic.h
@@ -26,6 +26,9 @@ extern "C" {
 // real kind.
 double RTNAME(CpuTime)();
 
+// Interface for Timef()
+double RTNAME(Timef)();
+
 // Interface for the SYSTEM_CLOCK intrinsic. We break it up into 3 distinct
 // function calls, one for each of SYSTEM_CLOCK's optional output arguments.
 // Lowering converts the results to the types of the actual arguments,
diff --git a/flang/lib/Evaluate/intrinsics.cpp b/flang/lib/Evaluate/intrinsics.cpp
index 2ae1c478489c4..2082d2dd58c16 100644
--- a/flang/lib/Evaluate/intrinsics.cpp
+++ b/flang/lib/Evaluate/intrinsics.cpp
@@ -1030,6 +1030,7 @@ static const IntrinsicInterface genericIntrinsicFunction[]{
         IntrinsicClass::transformationalFunction},
     {"time", {}, TypePattern{IntType, KindCode::exactKind, 8}, Rank::scalar,
         IntrinsicClass::transformationalFunction},
+    {"timef", {}, TypePattern{RealType, KindCode::exactKind, 8}, Rank::scalar},
     {"tiny",
         {{"x", SameReal, Rank::anyOrAssumedRank, Optionality::required,
             common::Intent::In,
diff --git a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
index 9036d65f138d3..79433c56a0ee0 100644
--- a/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
+++ b/flang/lib/Optimizer/Builder/IntrinsicCall.cpp
@@ -797,6 +797,7 @@ static constexpr IntrinsicHandler handlers[]{
        {"team", asBox, handleDynamicOptional}}},
      /*isElemental=*/false},
     {"time", &I::genTime, {}, /*isElemental=*/false},
+    {"timef", &I::genTimef, {}, /*isElemental=*/false},
     {"tokenize",
      &I::genTokenize,
      {{{"string", asAddr},
@@ -8255,6 +8256,13 @@ IntrinsicLibrary::genThisImage(mlir::Type resultType,
   return builder.createConvert(loc, resultType, res);
 }
 
+// TIMEF
+mlir::Value IntrinsicLibrary::genTimef(mlir::Type resultType,
+                                       llvm::ArrayRef<mlir::Value> args) {
+  assert(args.empty() && "timef does not accept any args");
+  return fir::runtime::genTimef(builder, loc);
+}
+
 // TRAILZ
 mlir::Value IntrinsicLibrary::genTrailz(mlir::Type resultType,
                                         llvm::ArrayRef<mlir::Value> args) {
diff --git a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
index a5f16f89b260a..dc87638937d7a 100644
--- a/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
+++ b/flang/lib/Optimizer/Builder/Runtime/Intrinsics.cpp
@@ -327,6 +327,14 @@ mlir::Value fir::runtime::genTime(fir::FirOpBuilder &builder,
       .getResult(0);
 }
 
+/// generate runtime call to timef intrinsic
+mlir::Value fir::runtime::genTimef(fir::FirOpBuilder &builder,
+                                   mlir::Location loc) {
+  auto func = fir::runtime::getRuntimeFunc<mkRTKey(Timef)>(loc, builder);
+  return fir::CallOp::create(builder, loc, func, mlir::ValueRange{})
+      .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/timef.f90 b/flang/test/Lower/Intrinsics/timef.f90
new file mode 100644
index 0000000000000..5ec4a71e49d29
--- /dev/null
+++ b/flang/test/Lower/Intrinsics/timef.f90
@@ -0,0 +1,15 @@
+!RUN: bbc -emit-hlfir %s -o - | FileCheck %s
+!RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
+
+subroutine test_timef(t)
+  real(8) :: t
+  t = timef()
+end subroutine
+! CHECK-LABEL:   func.func @_QPtest_timef(
+! CHECK-SAME:                                %[[VAL_0:.*]]: !fir.ref<f64> {fir.bindc_name = "t"}) {
+! CHECK:           %[[VAL_2:.*]] = fir.dummy_scope : !fir.dscope
+! CHECK:           %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] dummy_scope %[[VAL_2]] arg {{[0-9]+}} {uniq_name = "_QFtest_timefEt"} : (!fir.ref<f64>, !fir.dscope) -> (!fir.ref<f64>, !fir.ref<f64>)
+! CHECK:           %[[VAL_4:.*]] = fir.call @_FortranATimef() fastmath<contract> : () -> f64
+! CHECK:           hlfir.assign %[[VAL_4]] to %[[VAL_3]]#0 : f64, !fir.ref<f64>
+! CHECK:           return
+! CHECK:         }

>From b0679b775022858d3ef95cf6ae80f60002379932 Mon Sep 17 00:00:00 2001
From: NimishMishra <neelam.nimish at gmail.com>
Date: Mon, 9 Mar 2026 13:45:30 +0530
Subject: [PATCH 2/3] Add documentation changes

---
 flang-rt/lib/runtime/extensions.cpp | 15 +++++++--------
 flang/docs/Intrinsics.md            | 13 +++++++++++++
 2 files changed, 20 insertions(+), 8 deletions(-)

diff --git a/flang-rt/lib/runtime/extensions.cpp b/flang-rt/lib/runtime/extensions.cpp
index 126cadadc1619..3ffeec511da31 100644
--- a/flang-rt/lib/runtime/extensions.cpp
+++ b/flang-rt/lib/runtime/extensions.cpp
@@ -414,16 +414,15 @@ double RTNAME(Dsecnds)(double *refTime, const char *sourceFile, int line) {
 std::int64_t RTNAME(time)() { return time(nullptr); }
 
 // Intel extension function TIMEF()
-// Returns number of seconds that have elapsed since the first time 
+// Returns number of seconds that have elapsed since the first time
 // TIMEF was called. For the first call, it returns 0.
 double RTNAME(Timef)() {
-        static double first = -1;
-	if(first < 0){
-		first = time(nullptr);
-		return 0;
-	}
-	else
-		return time(nullptr) - first;
+  static double first = -1;
+  if (first < 0) {
+    first = time(nullptr);
+    return 0;
+  } else
+    return time(nullptr) - first;
 }
 
 // MCLOCK: returns accumulated CPU time in ticks
diff --git a/flang/docs/Intrinsics.md b/flang/docs/Intrinsics.md
index 615d2746284ab..c6d2f92ef5d1a 100644
--- a/flang/docs/Intrinsics.md
+++ b/flang/docs/Intrinsics.md
@@ -1215,6 +1215,19 @@ PROGRAM example_time
 END PROGRAM
 ```
 
+### Non-Standard Intrinsics: TIMEF
+
+#### Description
+`TIMEF` returns the number of seconds that have 
+elapsed since the first time TIMEF was called.
+The first time it is called, TIMEF returns 0.
+
+#### Usage and Info
+
+- **Standard:** Intel extension
+- **Class:** function
+- **Syntax:** `RESULT = TIMEF()`
+
 ### Non-Standard Intrinsics: UNLINK
 
 #### Description

>From 887c54b5df89647cb2dc6115a834d04ea5665866 Mon Sep 17 00:00:00 2001
From: NimishMishra <42909663+NimishMishra at users.noreply.github.com>
Date: Mon, 9 Mar 2026 03:43:31 -0700
Subject: [PATCH 3/3] Fix typo

---
 flang-rt/unittests/Runtime/Time.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang-rt/unittests/Runtime/Time.cpp b/flang-rt/unittests/Runtime/Time.cpp
index be668e9a8f3c2..795c1ee1315b4 100644
--- a/flang-rt/unittests/Runtime/Time.cpp
+++ b/flang-rt/unittests/Runtime/Time.cpp
@@ -39,7 +39,7 @@ TEST(TimeIntrinsics, Timef) {
   ASSERT_GE(start, 0.0);
 
   // Loop until we get a different value from Timef
-  for (double end = start; end == start; end = RTNAME(CpuTime)()) {
+  for (double end = start; end == start; end = RTNAME(Timef)()) {
     ASSERT_GE(end, 0.0);
     ASSERT_GE(end, start);
   }



More information about the flang-commits mailing list