Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions flang-rt/cmake/modules/AddFlangRT.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
71 changes: 63 additions & 8 deletions flang-rt/lib/runtime/time-intrinsic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>
Expand All @@ -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;
Expand All @@ -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.
Expand All @@ -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) {
Expand All @@ -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;
Expand All @@ -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>
Expand All @@ -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,
Expand Down Expand Up @@ -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)

Expand Down
Loading