diff --git a/stl/inc/__msvc_chrono.hpp b/stl/inc/__msvc_chrono.hpp index 45b9f75f782..581d2e74f0d 100644 --- a/stl/inc/__msvc_chrono.hpp +++ b/stl/inc/__msvc_chrono.hpp @@ -666,18 +666,37 @@ namespace chrono { using time_point = _CHRONO time_point; static constexpr bool is_steady = true; +#if defined(_M_ARM) || defined(_M_ARM64) // vvv ARM or ARM64 arch vvv +#define _LIKELY_ARM_ARM64 _LIKELY +#define _LIKELY_X86_X64 +#elif defined(_M_IX86) || defined(_M_X64) // ^^^ ARM or ARM64 arch / x86 or x64 arch vvv +#define _LIKELY_ARM_ARM64 +#define _LIKELY_X86_X64 _LIKELY +#else // ^^^ x86 or x64 arch / other arch vvv +#define _LIKELY_ARM_ARM64 +#define _LIKELY_X86_X64 +#endif // ^^^ other arch ^^^ _NODISCARD static time_point now() noexcept { // get current time const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot const long long _Ctr = _Query_perf_counter(); static_assert(period::num == 1, "This assumes period::num == 1."); - // 10 MHz is a very common QPC frequency on modern PCs. Optimizing for - // this specific frequency can double the performance of this function by - // avoiding the expensive frequency conversion path. - constexpr long long _TenMHz = 10'000'000; - if (_Freq == _TenMHz) { + // The compiler recognizes the constants for frequency and time period and uses shifts and + // multiplies instead of divides to calculate the nanosecond value. + constexpr long long _TenMHz = 10'000'000; + constexpr long long _TwentyFourMHz = 24'000'000; + // clang-format off + if (_Freq == _TenMHz) _LIKELY_X86_X64 { + // 10 MHz is a very common QPC frequency on modern x86/x64 PCs. Optimizing for + // this specific frequency can double the performance of this function by + // avoiding the expensive frequency conversion path. static_assert(period::den % _TenMHz == 0, "It should never fail."); constexpr long long _Multiplier = period::den / _TenMHz; return time_point(duration(_Ctr * _Multiplier)); + } else if (_Freq == _TwentyFourMHz) _LIKELY_ARM_ARM64 { + // 24 MHz is a common frequency on ARM/ARM64, including cases where it emulates x86/x64. + const long long _Whole = (_Ctr / _TwentyFourMHz) * period::den; + const long long _Part = (_Ctr % _TwentyFourMHz) * period::den / _TwentyFourMHz; + return time_point(duration(_Whole + _Part)); } else { // Instead of just having "(_Ctr * period::den) / _Freq", // the algorithm below prevents overflow when _Ctr is sufficiently large. @@ -688,7 +707,10 @@ namespace chrono { const long long _Part = (_Ctr % _Freq) * period::den / _Freq; return time_point(duration(_Whole + _Part)); } + // clang-format on } +#undef _LIKELY_ARM_ARM64 +#undef _LIKELY_X86_X64 }; _EXPORT_STD using high_resolution_clock = steady_clock; diff --git a/stl/inc/yvals_core.h b/stl/inc/yvals_core.h index ceb2fce5ed8..13789b3be78 100644 --- a/stl/inc/yvals_core.h +++ b/stl/inc/yvals_core.h @@ -525,6 +525,20 @@ #define _FALLTHROUGH #endif +#ifndef __has_cpp_attribute // vvv no attributes vvv +#define _LIKELY +#define _UNLIKELY +#elif __has_cpp_attribute(likely) >= 201803L && __has_cpp_attribute(unlikely) >= 201803L // ^^^ no attr / C++20 attr vvv +#define _LIKELY [[likely]] +#define _UNLIKELY [[unlikely]] +#elif defined(__clang__) // ^^^ C++20 attributes / clang attributes and C++17 or C++14 vvv +#define _LIKELY [[__likely__]] +#define _UNLIKELY [[__unlikely__]] +#else // ^^^ clang attributes and C++17 or C++14 / C1XX attributes and C++17 or C++14 vvv +#define _LIKELY +#define _UNLIKELY +#endif // ^^^ C1XX attributes and C++17 or C++14 ^^^ + // _HAS_NODISCARD (in vcruntime.h) controls: // [[nodiscard]] attributes on STL functions