[llvm] [flang-rt] Match compiler-rt's default macos version (PR #147273)
Tom Eccles via llvm-commits
llvm-commits at lists.llvm.org
Mon Jul 7 03:42:16 PDT 2025
https://github.com/tblah created https://github.com/llvm/llvm-project/pull/147273
Followup to https://github.com/llvm/llvm-project/pull/143508
This required adding another alternative implementation of time intrinsics to match what is available in older MacOS.
With this change, flang can be used to build programs for older versions of MacOS.
>From 8d550d28c36239fd7cb48b25ae9aad081a4ca56c Mon Sep 17 00:00:00 2001
From: Tom Eccles <tom.eccles at arm.com>
Date: Fri, 27 Jun 2025 12:18:22 +0000
Subject: [PATCH] [flang-rt] Match compiler-rt's default macos version
Followup to https://github.com/llvm/llvm-project/pull/143508
This required adding another alternative implementation of time
intrinsics to match what is available in older MacOS.
With this change, flang can be used to build programs for older versions
of MacOS.
Co-authored-by: David Truby <david.truby at arm.com>
---
flang-rt/cmake/modules/AddFlangRT.cmake | 12 +++++
flang-rt/lib/runtime/time-intrinsic.cpp | 71 ++++++++++++++++++++++---
2 files changed, 75 insertions(+), 8 deletions(-)
diff --git a/flang-rt/cmake/modules/AddFlangRT.cmake b/flang-rt/cmake/modules/AddFlangRT.cmake
index 93a21277caff8..e51590fdae3d3 100644
--- a/flang-rt/cmake/modules/AddFlangRT.cmake
+++ b/flang-rt/cmake/modules/AddFlangRT.cmake
@@ -204,6 +204,14 @@ function (add_flangrt_library name)
endif ()
endforeach ()
+ set(TARGET_FLAGS)
+ if(APPLE)
+ set(DARWIN_EMBEDDED_PLATFORMS)
+ set(DARWIN_osx_BUILTIN_MIN_VER 10.7)
+ set(DARWIN_osx_BUILTIN_MIN_VER_FLAG
+ -mmacosx-version-min=${DARWIN_osx_BUILTIN_MIN_VER})
+ endif()
+
# Define how to compile and link the library.
# Some conceptionally only apply to ${srctargets} or ${libtargets}, but we
# apply them to ${alltargets}. In worst case, they are ignored by CMake.
@@ -242,6 +250,10 @@ function (add_flangrt_library name)
target_compile_options(${tgtname} PRIVATE
$<$<COMPILE_LANGUAGE:CXX>:-nogpulib -flto -fvisibility=hidden -Wno-unknown-cuda-version --cuda-feature=+ptx63>
)
+ elseif (APPLE)
+ target_compile_options(${tgtname} PRIVATE
+ $<$<COMPILE_LANGUAGE:CXX>:${DARWIN_osx_BUILTIN_MIN_VER_FLAG}>
+ )
endif ()
# Also for CUDA source when compiling with FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT=CUDA
diff --git a/flang-rt/lib/runtime/time-intrinsic.cpp b/flang-rt/lib/runtime/time-intrinsic.cpp
index 69c344f5d24bc..8988817a40064 100644
--- a/flang-rt/lib/runtime/time-intrinsic.cpp
+++ b/flang-rt/lib/runtime/time-intrinsic.cpp
@@ -60,6 +60,18 @@ template <typename Unused = void> double GetCpuTime(fallback_implementation) {
return -1.0;
}
+// struct timespec and timespec_get are not implemented in macOS 10.14. Using
+// it here limits which version of MacOS we are compatible with. Unfortunately
+// when building on newer MacOS for older MacOS it uses the new headers (with
+// a definition of struct timespec) but just errors on API calls so we can't use
+// overloading magic to trigger different implementations depending if struct
+// timespec is defined.
+#if defined __APPLE__
+#define NO_TIMESPEC
+#else
+#undef NO_TIMESPEC
+#endif
+
#if defined __MINGW32__
// clock_gettime is implemented in the pthread library for MinGW.
// Using it here would mean that all programs that link libflang_rt are
@@ -87,6 +99,7 @@ template <typename Unused = void> double GetCpuTime(fallback_implementation) {
#endif
#ifdef CLOCKID_CPU_TIME
+#ifndef NO_TIMESPEC
// POSIX implementation using clock_gettime. This is only enabled where
// clock_gettime is available.
template <typename T = int, typename U = struct timespec>
@@ -101,6 +114,7 @@ double GetCpuTime(preferred_implementation,
// Return some negative value to represent failure.
return -1.0;
}
+#endif // !NO_TIMESPEC
#endif // CLOCKID_CPU_TIME
using count_t = std::int64_t;
@@ -113,6 +127,7 @@ using unsigned_count_t = std::uint64_t;
// - nanoseconds for kinds 8, 16
constexpr unsigned_count_t DS_PER_SEC{10u};
constexpr unsigned_count_t MS_PER_SEC{1'000u};
+[[maybe_unused]] constexpr unsigned_count_t US_PER_SEC{1'000'000u};
constexpr unsigned_count_t NS_PER_SEC{1'000'000'000u};
// Computes HUGE(INT(0,kind)) as an unsigned integer value.
@@ -123,13 +138,9 @@ static constexpr inline unsigned_count_t GetHUGE(int kind) {
return (unsigned_count_t{1} << ((8 * kind) - 1)) - 1;
}
-// Function converts a std::timespec_t into the desired count to
-// be returned by the timing functions in accordance with the requested
-// kind at the call site.
-count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
+count_t ConvertSecondsNanosecondsToCount(
+ int kind, unsigned_count_t sec, unsigned_count_t nsec) {
const unsigned_count_t huge{GetHUGE(kind)};
- unsigned_count_t sec{static_cast<unsigned_count_t>(tspec.tv_sec)};
- unsigned_count_t nsec{static_cast<unsigned_count_t>(tspec.tv_nsec)};
if (kind >= 8) {
return (sec * NS_PER_SEC + nsec) % (huge + 1);
} else if (kind >= 2) {
@@ -139,8 +150,45 @@ count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
}
}
+// Less accurate implementation only accurate to the nearest microsecond
+// (instead of nanosecond) for systems where `struct timespec` is not available.
+#if defined(NO_TIMESPEC) && !defined(_WIN32)
+// Function converts a struct timeval into the desired count to
+// be returned by the timing functions in accordance with the requested
+// kind at the call site.
+count_t ConvertTimevalToCount(int kind, const struct timeval &tval) {
+ unsigned_count_t sec{static_cast<unsigned_count_t>(tval.tv_sec)};
+ unsigned_count_t nsec{static_cast<unsigned_count_t>(tval.tv_usec) * 1000};
+ return ConvertSecondsNanosecondsToCount(kind, sec, nsec);
+}
+
+template <typename Unused = void>
+count_t GetSystemClockCount(int kind, fallback_implementation) {
+ struct timeval tval;
+
+ if (gettimeofday(&tval, /*timezone=*/nullptr) != 0) {
+ // Return -HUGE(COUNT) to represent failure.
+ return -static_cast<count_t>(GetHUGE(kind));
+ }
+
+ // Compute the timestamp as seconds plus nanoseconds in accordance
+ // with the requested kind at the call site.
+ return ConvertTimevalToCount(kind, tval);
+}
+
+#else
+
+// Function converts a std::timespec_t into the desired count to
+// be returned by the timing functions in accordance with the requested
+// kind at the call site.
+count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
+ unsigned_count_t sec{static_cast<unsigned_count_t>(tspec.tv_sec)};
+ unsigned_count_t nsec{static_cast<unsigned_count_t>(tspec.tv_nsec)};
+ return ConvertSecondsNanosecondsToCount(kind, sec, nsec);
+}
+
#ifndef _AIX
-// This is the fallback implementation, which should work everywhere.
+// More accurate version with nanosecond accuracy
template <typename Unused = void>
count_t GetSystemClockCount(int kind, fallback_implementation) {
struct timespec tspec;
@@ -154,11 +202,16 @@ count_t GetSystemClockCount(int kind, fallback_implementation) {
// with the requested kind at the call site.
return ConvertTimeSpecToCount(kind, tspec);
}
-#endif
+#endif // !_AIX
+#endif // !NO_TIMESPEC
template <typename Unused = void>
count_t GetSystemClockCountRate(int kind, fallback_implementation) {
+#ifdef NO_TIMESPEC
+ return kind >= 8 ? US_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC;
+#else
return kind >= 8 ? NS_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC;
+#endif
}
template <typename Unused = void>
@@ -167,6 +220,7 @@ count_t GetSystemClockCountMax(int kind, fallback_implementation) {
return maxCount;
}
+#ifndef NO_TIMESPEC
#ifdef CLOCKID_ELAPSED_TIME
template <typename T = int, typename U = struct timespec>
count_t GetSystemClockCount(int kind, preferred_implementation,
@@ -200,6 +254,7 @@ count_t GetSystemClockCountMax(int kind, preferred_implementation,
decltype(clock_gettime(ClockId, Timespec)) *Enabled = nullptr) {
return GetHUGE(kind);
}
+#endif // !NO_TIMESPEC
// DATE_AND_TIME (Fortran 2018 16.9.59)
More information about the llvm-commits
mailing list