Skip to content

Commit fe5d94d

Browse files
tblahDavidTruby
andauthored
[flang-rt] Match compiler-rt's default macos version (#147273)
Followup to #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@arm.com>
1 parent b041a58 commit fe5d94d

File tree

2 files changed

+75
-8
lines changed

2 files changed

+75
-8
lines changed

flang-rt/cmake/modules/AddFlangRT.cmake

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,14 @@ function (add_flangrt_library name)
204204
endif ()
205205
endforeach ()
206206

207+
set(TARGET_FLAGS)
208+
if(APPLE)
209+
set(DARWIN_EMBEDDED_PLATFORMS)
210+
set(DARWIN_osx_BUILTIN_MIN_VER 10.7)
211+
set(DARWIN_osx_BUILTIN_MIN_VER_FLAG
212+
-mmacosx-version-min=${DARWIN_osx_BUILTIN_MIN_VER})
213+
endif()
214+
207215
# Define how to compile and link the library.
208216
# Some conceptionally only apply to ${srctargets} or ${libtargets}, but we
209217
# apply them to ${alltargets}. In worst case, they are ignored by CMake.
@@ -242,6 +250,10 @@ function (add_flangrt_library name)
242250
target_compile_options(${tgtname} PRIVATE
243251
$<$<COMPILE_LANGUAGE:CXX>:-nogpulib -flto -fvisibility=hidden -Wno-unknown-cuda-version --cuda-feature=+ptx63>
244252
)
253+
elseif (APPLE)
254+
target_compile_options(${tgtname} PRIVATE
255+
$<$<COMPILE_LANGUAGE:CXX>:${DARWIN_osx_BUILTIN_MIN_VER_FLAG}>
256+
)
245257
endif ()
246258

247259
# Also for CUDA source when compiling with FLANG_RT_EXPERIMENTAL_OFFLOAD_SUPPORT=CUDA

flang-rt/lib/runtime/time-intrinsic.cpp

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,18 @@ template <typename Unused = void> double GetCpuTime(fallback_implementation) {
6060
return -1.0;
6161
}
6262

63+
// struct timespec and timespec_get are not implemented in macOS 10.14. Using
64+
// it here limits which version of MacOS we are compatible with. Unfortunately
65+
// when building on newer MacOS for older MacOS it uses the new headers (with
66+
// a definition of struct timespec) but just errors on API calls so we can't use
67+
// overloading magic to trigger different implementations depending if struct
68+
// timespec is defined.
69+
#if defined __APPLE__
70+
#define NO_TIMESPEC
71+
#else
72+
#undef NO_TIMESPEC
73+
#endif
74+
6375
#if defined __MINGW32__
6476
// clock_gettime is implemented in the pthread library for MinGW.
6577
// 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) {
8799
#endif
88100

89101
#ifdef CLOCKID_CPU_TIME
102+
#ifndef NO_TIMESPEC
90103
// POSIX implementation using clock_gettime. This is only enabled where
91104
// clock_gettime is available.
92105
template <typename T = int, typename U = struct timespec>
@@ -101,6 +114,7 @@ double GetCpuTime(preferred_implementation,
101114
// Return some negative value to represent failure.
102115
return -1.0;
103116
}
117+
#endif // !NO_TIMESPEC
104118
#endif // CLOCKID_CPU_TIME
105119

106120
using count_t = std::int64_t;
@@ -113,6 +127,7 @@ using unsigned_count_t = std::uint64_t;
113127
// - nanoseconds for kinds 8, 16
114128
constexpr unsigned_count_t DS_PER_SEC{10u};
115129
constexpr unsigned_count_t MS_PER_SEC{1'000u};
130+
[[maybe_unused]] constexpr unsigned_count_t US_PER_SEC{1'000'000u};
116131
constexpr unsigned_count_t NS_PER_SEC{1'000'000'000u};
117132

118133
// Computes HUGE(INT(0,kind)) as an unsigned integer value.
@@ -123,13 +138,9 @@ static constexpr inline unsigned_count_t GetHUGE(int kind) {
123138
return (unsigned_count_t{1} << ((8 * kind) - 1)) - 1;
124139
}
125140

126-
// Function converts a std::timespec_t into the desired count to
127-
// be returned by the timing functions in accordance with the requested
128-
// kind at the call site.
129-
count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
141+
count_t ConvertSecondsNanosecondsToCount(
142+
int kind, unsigned_count_t sec, unsigned_count_t nsec) {
130143
const unsigned_count_t huge{GetHUGE(kind)};
131-
unsigned_count_t sec{static_cast<unsigned_count_t>(tspec.tv_sec)};
132-
unsigned_count_t nsec{static_cast<unsigned_count_t>(tspec.tv_nsec)};
133144
if (kind >= 8) {
134145
return (sec * NS_PER_SEC + nsec) % (huge + 1);
135146
} else if (kind >= 2) {
@@ -139,8 +150,45 @@ count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
139150
}
140151
}
141152

153+
// Less accurate implementation only accurate to the nearest microsecond
154+
// (instead of nanosecond) for systems where `struct timespec` is not available.
155+
#if defined(NO_TIMESPEC) && !defined(_WIN32)
156+
// Function converts a struct timeval into the desired count to
157+
// be returned by the timing functions in accordance with the requested
158+
// kind at the call site.
159+
count_t ConvertTimevalToCount(int kind, const struct timeval &tval) {
160+
unsigned_count_t sec{static_cast<unsigned_count_t>(tval.tv_sec)};
161+
unsigned_count_t nsec{static_cast<unsigned_count_t>(tval.tv_usec) * 1000};
162+
return ConvertSecondsNanosecondsToCount(kind, sec, nsec);
163+
}
164+
165+
template <typename Unused = void>
166+
count_t GetSystemClockCount(int kind, fallback_implementation) {
167+
struct timeval tval;
168+
169+
if (gettimeofday(&tval, /*timezone=*/nullptr) != 0) {
170+
// Return -HUGE(COUNT) to represent failure.
171+
return -static_cast<count_t>(GetHUGE(kind));
172+
}
173+
174+
// Compute the timestamp as seconds plus nanoseconds in accordance
175+
// with the requested kind at the call site.
176+
return ConvertTimevalToCount(kind, tval);
177+
}
178+
179+
#else
180+
181+
// Function converts a std::timespec_t into the desired count to
182+
// be returned by the timing functions in accordance with the requested
183+
// kind at the call site.
184+
count_t ConvertTimeSpecToCount(int kind, const struct timespec &tspec) {
185+
unsigned_count_t sec{static_cast<unsigned_count_t>(tspec.tv_sec)};
186+
unsigned_count_t nsec{static_cast<unsigned_count_t>(tspec.tv_nsec)};
187+
return ConvertSecondsNanosecondsToCount(kind, sec, nsec);
188+
}
189+
142190
#ifndef _AIX
143-
// This is the fallback implementation, which should work everywhere.
191+
// More accurate version with nanosecond accuracy
144192
template <typename Unused = void>
145193
count_t GetSystemClockCount(int kind, fallback_implementation) {
146194
struct timespec tspec;
@@ -154,11 +202,16 @@ count_t GetSystemClockCount(int kind, fallback_implementation) {
154202
// with the requested kind at the call site.
155203
return ConvertTimeSpecToCount(kind, tspec);
156204
}
157-
#endif
205+
#endif // !_AIX
206+
#endif // !NO_TIMESPEC
158207

159208
template <typename Unused = void>
160209
count_t GetSystemClockCountRate(int kind, fallback_implementation) {
210+
#ifdef NO_TIMESPEC
211+
return kind >= 8 ? US_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC;
212+
#else
161213
return kind >= 8 ? NS_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC;
214+
#endif
162215
}
163216

164217
template <typename Unused = void>
@@ -167,6 +220,7 @@ count_t GetSystemClockCountMax(int kind, fallback_implementation) {
167220
return maxCount;
168221
}
169222

223+
#ifndef NO_TIMESPEC
170224
#ifdef CLOCKID_ELAPSED_TIME
171225
template <typename T = int, typename U = struct timespec>
172226
count_t GetSystemClockCount(int kind, preferred_implementation,
@@ -200,6 +254,7 @@ count_t GetSystemClockCountMax(int kind, preferred_implementation,
200254
decltype(clock_gettime(ClockId, Timespec)) *Enabled = nullptr) {
201255
return GetHUGE(kind);
202256
}
257+
#endif // !NO_TIMESPEC
203258

204259
// DATE_AND_TIME (Fortran 2018 16.9.59)
205260

0 commit comments

Comments
 (0)