Index: flang/runtime/time-intrinsic.cpp =================================================================== --- flang/runtime/time-intrinsic.cpp +++ flang/runtime/time-intrinsic.cpp @@ -13,6 +13,8 @@ #include // CPU_TIME (Fortran 2018 16.9.57) +// SYSTEM_CLOCK (Fortran 2018 16.9.168) +// // We can use std::clock() from the header as a fallback implementation // that should be available everywhere. This may not provide the best resolution // and is particularly troublesome on (some?) POSIX systems where CLOCKS_PER_SEC @@ -68,11 +70,60 @@ // Return some negative value to represent failure. return -1.0; } + +using count_t = + Fortran::runtime::CppTypeFor; + +// This is the fallback implementation, which should work everywhere. Note that +// in general we can't recover after std::clock has reached its maximum value. +template +count_t getSystemClockCount(fallback_implementation) { + std::clock_t timestamp{std::clock()}; + if (timestamp == static_cast(-1)) { + // Return -HUGE() to represent failure. + return -std::numeric_limits::max(); + } + + // If our return type is large enough to hold any value returned by + // std::clock, our work is done. Otherwise, we have to wrap around. + if (std::numeric_limits::max() <= + std::numeric_limits::max()) { + return static_cast(timestamp); + } else { + // Since std::clock_t could be a floating point type, we can't just use the + // % operator, so we have to wrap around manually. + auto max = std::numeric_limits::max(); + return static_cast(timestamp - max * std::floor(timestamp / max)); + } +} + +template +count_t getSystemClockCountRate(fallback_implementation) { + return CLOCKS_PER_SEC; +} + +template +count_t getSystemClockCountMax(fallback_implementation) { + return std::min(std::numeric_limits::max(), + std::numeric_limits::max()); +} } // anonymous namespace namespace Fortran::runtime { extern "C" { double RTNAME(CpuTime)() { return getCpuTime(0); } + +CppTypeFor RTNAME(SystemClockCount)() { + return getSystemClockCount(0); +} + +CppTypeFor RTNAME(SystemClockCountRate)() { + return getSystemClockCountRate(0); +} + +CppTypeFor RTNAME(SystemClockCountMax)() { + return getSystemClockCountMax(0); +} } // extern "C" } // namespace Fortran::runtime Index: flang/unittests/RuntimeGTest/Time.cpp =================================================================== --- flang/unittests/RuntimeGTest/Time.cpp +++ flang/unittests/RuntimeGTest/Time.cpp @@ -26,3 +26,33 @@ ASSERT_GE(end, start); } } + +using count_t = CppTypeFor; + +TEST(TimeIntrinsics, SystemClock) { + // We can't really test that we get the "right" result for SYSTEM_CLOCK, but + // we can have a smoke test to see that we get something reasonable on the + // platforms where we expect to support it. + + // The value of the count rate and max will vary by platform, but they should + // always be strictly positive if we have a working implementation of + // SYSTEM_CLOCK. + EXPECT_GT(RTNAME(SystemClockCountRate)(), 0); + + count_t max = RTNAME(SystemClockCountMax)(); + EXPECT_GT(max, 0); + + count_t start = RTNAME(SystemClockCount)(); + EXPECT_GE(start, 0); + EXPECT_LE(start, max); + + // Loop until we get a different value from SystemClockCount. If we don't get + // one before we time out, then we should probably look into an implementation + // for SystemClokcCount with a better timer resolution on this platform. + for (count_t end = start; end == start; end = RTNAME(SystemClockCount)()) { + EXPECT_GE(end, 0); + EXPECT_LE(end, max); + + EXPECT_GE(end, start); + } +}