[flang] [llvm] [flang-rt] Runtime implementation of extended intrinsic function SECNDS() (PR #152021)

Peter Klausler via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 5 13:08:59 PDT 2025


================
@@ -303,6 +304,93 @@ void FORTRAN_PROCEDURE_NAME(qsort)(int *array, int *len, int *isize,
 // PERROR(STRING)
 void RTNAME(Perror)(const char *str) { perror(str); }
 
+// GNU extension function SECNDS(refTime)
+float FORTRAN_PROCEDURE_NAME(secnds)(float *refTime) {
+  constexpr float FAIL_SECNDS{-1.0f}; // Failure code for this function
+  // Failure code for time functions that return std::time_t
+  constexpr std::time_t FAIL_TIME{std::time_t{-1}};
+  constexpr std::time_t TIME_UNINITIALIZED{std::time_t{0}};
+  constexpr std::time_t TIME_INITIALIZING{std::time_t{1}};
+  if (!refTime) {
+    return FAIL_SECNDS;
+  }
+  std::time_t now{std::time(nullptr)};
+  if (now == FAIL_TIME) {
+    return FAIL_SECNDS;
+  }
+  // In float result, we can only precisely store 2^24 seconds, which
+  // comes out to about 194 days. Thus, need to pick a starting point.
+  // Given the description of this function, midnight of the current
+  // day is the best starting point.
+  //
+  // In addition, use atomic operations for thread safety. startingPoint
+  // also acts as a state variable that can take on the following values:
+  // TIME_UNINITIALIZED to indicate that it's not initialized,
+  // TIME_INITIALIZING to indicate that it is being initialized,
+  // any other value to indicate the starting point time.
+  static std::atomic<std::time_t> startingPoint{TIME_UNINITIALIZED};
+  std::time_t localStartingPoint{TIME_UNINITIALIZED};
+  // Use retry logic to ensure that in case of multiple threads, one thread
+  // will perform initialization and the other threads wait their turn.
+  for (;;) {
+    // "Acquire" will show writes from other threads.
+    std::time_t currentStartingPoint =
+        startingPoint.load(std::memory_order_acquire);
+    if (currentStartingPoint > TIME_INITIALIZING) {
+      // Initialization was already done, use the starting point value
+      localStartingPoint = currentStartingPoint;
+      break;
+    } else if (currentStartingPoint == TIME_INITIALIZING) {
+      // Some other thread is currently initializing
+      std::this_thread::yield();
+      continue;
+    } else if (currentStartingPoint == TIME_UNINITIALIZED) {
+      // Try to start initialization
+      std::time_t expected{TIME_UNINITIALIZED};
+      if (startingPoint.compare_exchange_strong(expected, TIME_INITIALIZING,
+              std::memory_order_acq_rel, // "Aquire and release" on success
----------------
klausler wrote:

"acquire"

https://github.com/llvm/llvm-project/pull/152021


More information about the llvm-commits mailing list