Index: flang/docs/Extensions.md =================================================================== --- flang/docs/Extensions.md +++ flang/docs/Extensions.md @@ -67,10 +67,9 @@ * If both the `COUNT=` and the `COUNT_MAX=` optional arguments are present on the same call to the intrinsic subroutine `SYSTEM_CLOCK`, we require that their types have the same integer kind, since the - kind of these arguments is used to select the clock rate. - In common with some other compilers, the clock is in milliseconds - for kinds <= 4 and nanoseconds otherwise where the target system - supports these rates. + kind of these arguments is used to select the clock rate. In common + with some other compilers, the clock rate varies from tenths of a + second to nanoseconds depending on argument kind and platform support. * If a dimension of a descriptor has zero extent in a call to `CFI_section`, `CFI_setpointer` or `CFI_allocate`, the lower bound on that dimension will be set to 1 for consistency with Index: flang/runtime/time-intrinsic.cpp =================================================================== --- flang/runtime/time-intrinsic.cpp +++ flang/runtime/time-intrinsic.cpp @@ -127,18 +127,14 @@ : static_cast(maxCount); } -// POSIX implementation using clock_gettime. This is only enabled where -// clock_gettime is available. Use a millisecond CLOCK_RATE for kinds -// of COUNT/COUNT_MAX less than 64 bits, and nanoseconds otherwise. -constexpr unsigned_count_t MILLIS_PER_SEC{1'000u}; -constexpr unsigned_count_t NSECS_PER_SEC{1'000'000'000u}; -constexpr unsigned_count_t maxSecs{ - std::numeric_limits::max() / NSECS_PER_SEC}; - -// Use a millisecond clock rate for smaller COUNT= kinds. -static inline unsigned_count_t ScaleResult(unsigned_count_t nsecs, int kind) { - return kind >= 8 ? nsecs : nsecs / (NSECS_PER_SEC / MILLIS_PER_SEC); -} +// POSIX implementation using clock_gettime where available. The clock_gettime +// result is in nanoseconds, which is converted as necessary to +// - deciseconds for kind 1 +// - milliseconds for kinds 2, 4 +// - nanoseconds for kinds 8, 16 +constexpr unsigned_count_t DS_PER_SEC{10u}; +constexpr unsigned_count_t MS_PER_SEC{1'000u}; +constexpr unsigned_count_t NS_PER_SEC{1'000'000'000u}; template count_t GetSystemClockCount(int kind, preferred_implementation, @@ -146,19 +142,19 @@ T ClockId = 0, U *Timespec = nullptr, decltype(clock_gettime(ClockId, Timespec)) *Enabled = nullptr) { struct timespec tspec; + const unsigned_count_t huge{GetHUGE(kind)}; if (clock_gettime(CLOCKID, &tspec) != 0) { - // Return -HUGE() to represent failure. - return -GetHUGE(kind); + return -huge; // failure + } + unsigned_count_t sec{static_cast(tspec.tv_sec)}; + unsigned_count_t nsec{static_cast(tspec.tv_nsec)}; + if (kind >= 8) { + return (sec * NS_PER_SEC + nsec) % (huge + 1); + } else if (kind >= 2) { + return (sec * MS_PER_SEC + (nsec / (NS_PER_SEC / MS_PER_SEC))) % (huge + 1); + } else { // kind == 1 + return (sec * DS_PER_SEC + (nsec / (NS_PER_SEC / DS_PER_SEC))) % (huge + 1); } - // Wrap around to avoid overflows. - unsigned_count_t wrappedSecs{ - static_cast(tspec.tv_sec) % maxSecs}; - unsigned_count_t unsignedNsecs{static_cast(tspec.tv_nsec) + - wrappedSecs * NSECS_PER_SEC}; - unsigned_count_t unsignedCount{ScaleResult(unsignedNsecs, kind)}; - // Return the modulus of the unsigned integral count with HUGE(COUNT)+1. - // The result is a signed integer but never negative. - return static_cast(unsignedCount % (GetHUGE(kind) + 1)); } template @@ -166,7 +162,7 @@ // We need some dummy parameters to pass to decltype(clock_gettime). T ClockId = 0, U *Timespec = nullptr, decltype(clock_gettime(ClockId, Timespec)) *Enabled = nullptr) { - return kind >= 8 ? static_cast(NSECS_PER_SEC) : MILLIS_PER_SEC; + return kind >= 8 ? NS_PER_SEC : kind >= 2 ? MS_PER_SEC : DS_PER_SEC; } template @@ -174,10 +170,7 @@ // We need some dummy parameters to pass to decltype(clock_gettime). T ClockId = 0, U *Timespec = nullptr, decltype(clock_gettime(ClockId, Timespec)) *Enabled = nullptr) { - unsigned_count_t maxClockNsec{maxSecs * NSECS_PER_SEC + NSECS_PER_SEC - 1}; - unsigned_count_t maxClock{ScaleResult(maxClockNsec, kind)}; - unsigned_count_t maxCount{GetHUGE(kind)}; - return static_cast(maxClock <= maxCount ? maxClock : maxCount); + return GetHUGE(kind); } // DATE_AND_TIME (Fortran 2018 16.9.59)