diff options
author | LLVM libc <llvm-libc@google.com> | 2024-05-10 16:38:13 -0500 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2024-05-11 02:10:01 -0700 |
commit | af661192d780c55f7cf7e4e346559bddebaba9f4 (patch) | |
tree | 8215ccfc3d5f7ee558ac2e303cac36f7f19505a0 | |
parent | 5c76e7b22aaa87ac1d8f0ae7e100327ff29eb427 (diff) | |
download | llvm-libc-main.tar.gz |
Project import generated by Copybara.main
GitOrigin-RevId: fb3f4b013c3acab0ea3cb14c4d29f4e6d9caa33c
Change-Id: Id51b0538150a61ebfd370348c8ed47881798cf7d
61 files changed, 814 insertions, 491 deletions
diff --git a/include/llvm-libc-macros/fenv-macros.h b/include/llvm-libc-macros/fenv-macros.h index 72ac660cd98c..1826723f9349 100644 --- a/include/llvm-libc-macros/fenv-macros.h +++ b/include/llvm-libc-macros/fenv-macros.h @@ -9,11 +9,12 @@ #ifndef LLVM_LIBC_MACROS_FENV_MACROS_H #define LLVM_LIBC_MACROS_FENV_MACROS_H -#define FE_DIVBYZERO 1 -#define FE_INEXACT 2 -#define FE_INVALID 4 -#define FE_OVERFLOW 8 -#define FE_UNDERFLOW 16 +#define FE_DIVBYZERO 0x1 +#define FE_INEXACT 0x2 +#define FE_INVALID 0x4 +#define FE_OVERFLOW 0x8 +#define FE_UNDERFLOW 0x10 +#define __FE_DENORM 0x20 #define FE_ALL_EXCEPT \ (FE_DIVBYZERO | FE_INEXACT | FE_INVALID | FE_OVERFLOW | FE_UNDERFLOW) diff --git a/libc/hdr/fenv_macros.h b/libc/hdr/fenv_macros.h index 1ad28cc278a9..a2e4462ef02d 100644 --- a/libc/hdr/fenv_macros.h +++ b/libc/hdr/fenv_macros.h @@ -17,6 +17,52 @@ #include <fenv.h> +// In some environment, FE_ALL_EXCEPT is set to 0 and the remaining exceptions +// FE_* are missing. +#if (FE_ALL_EXCEPT == 0) +#ifndef FE_DIVBYZERO +#define FE_DIVBYZERO 0 +#endif // FE_DIVBYZERO + +#ifndef FE_INEXACT +#define FE_INEXACT 0 +#endif // FE_INEXACT + +#ifndef FE_INVALID +#define FE_INVALID 0 +#endif // FE_INVALID + +#ifndef FE_OVERFLOW +#define FE_OVERFLOW 0 +#endif // FE_OVERFLOW + +#ifndef FE_UNDERFLOW +#define FE_UNDERFLOW 0 +#endif // FE_UNDERFLOW +#else +// If this is not provided by the system, define it for use internally. +#ifndef __FE_DENORM +#define __FE_DENORM (1 << 6) +#endif +#endif + +// Rounding mode macros might be missing. +#ifndef FE_DOWNWARD +#define FE_DOWNWARD 0x400 +#endif // FE_DOWNWARD + +#ifndef FE_TONEAREST +#define FE_TONEAREST 0 +#endif // FE_TONEAREST + +#ifndef FE_TOWARDZERO +#define FE_TOWARDZERO 0xC00 +#endif // FE_TOWARDZERO + +#ifndef FE_UPWARD +#define FE_UPWARD 0x800 +#endif // FE_UPWARD + #endif // LLVM_LIBC_FULL_BUILD #endif // LLVM_LIBC_HDR_FENV_MACROS_H diff --git a/libc/hdr/time_macros.h b/libc/hdr/time_macros.h new file mode 100644 index 000000000000..dc36fe66f7a8 --- /dev/null +++ b/libc/hdr/time_macros.h @@ -0,0 +1,22 @@ +//===-- Definition of macros from time.h ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TIME_MACROS_H +#define LLVM_LIBC_HDR_TIME_MACROS_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-macros/time-macros.h" + +#else // Overlay mode + +#include <time.h> + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TIME_MACROS_H diff --git a/libc/hdr/types/clock_t.h b/libc/hdr/types/clock_t.h new file mode 100644 index 000000000000..b0b658e96c3d --- /dev/null +++ b/libc/hdr/types/clock_t.h @@ -0,0 +1,22 @@ +//===-- Proxy for clock_t -------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_CLOCK_T_H +#define LLVM_LIBC_HDR_TYPES_CLOCK_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/clock_t.h" + +#else // Overlay mode + +#include <sys/types.h> + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_CLOCK_T_H diff --git a/libc/hdr/types/clockid_t.h b/libc/hdr/types/clockid_t.h new file mode 100644 index 000000000000..333342072a2f --- /dev/null +++ b/libc/hdr/types/clockid_t.h @@ -0,0 +1,22 @@ +//===-- Proxy for clockid_t -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_CLOCKID_T_H +#define LLVM_LIBC_HDR_TYPES_CLOCKID_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/clockid_t.h" + +#else // Overlay mode + +#include <sys/types.h> + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_CLOCKID_T_H diff --git a/libc/hdr/types/struct_timeval.h b/libc/hdr/types/struct_timeval.h new file mode 100644 index 000000000000..8fc321a52d71 --- /dev/null +++ b/libc/hdr/types/struct_timeval.h @@ -0,0 +1,21 @@ +//===-- Proxy for struct timeval ----------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef LLVM_LIBC_HDR_TYPES_STRUCT_TIMEVAL_H +#define LLVM_LIBC_HDR_TYPES_STRUCT_TIMEVAL_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/struct_timeval.h" + +#else + +#include <sys/time.h> + +#endif // LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_STRUCT_TIMEVAL_H diff --git a/libc/hdr/types/suseconds_t.h b/libc/hdr/types/suseconds_t.h new file mode 100644 index 000000000000..72e54a965f75 --- /dev/null +++ b/libc/hdr/types/suseconds_t.h @@ -0,0 +1,22 @@ +//===-- Proxy for suseconds_t ---------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TIMES_SUSECONDS_T_H +#define LLVM_LIBC_HDR_TIMES_SUSECONDS_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/suseconds_t.h" + +#else // Overlay mode + +#include <sys/types.h> + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // #ifndef LLVM_LIBC_HDR_TIMES_SUSECONDS_T_H diff --git a/libc/hdr/types/time_t.h b/libc/hdr/types/time_t.h new file mode 100644 index 000000000000..fc9a1506a2cd --- /dev/null +++ b/libc/hdr/types/time_t.h @@ -0,0 +1,22 @@ +//===-- Proxy for time_t --------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_HDR_TYPES_TIME_T_H +#define LLVM_LIBC_HDR_TYPES_TIME_T_H + +#ifdef LIBC_FULL_BUILD + +#include "include/llvm-libc-types/time_t.h" + +#else // Overlay mode + +#include <time.h> + +#endif // LLVM_LIBC_FULL_BUILD + +#endif // LLVM_LIBC_HDR_TYPES_TIME_T_H diff --git a/src/__support/CPP/atomic.h b/src/__support/CPP/atomic.h index 5e428940565b..e273d998c070 100644 --- a/src/__support/CPP/atomic.h +++ b/src/__support/CPP/atomic.h @@ -101,6 +101,36 @@ public: int(mem_ord), int(mem_ord)); } + // Atomic compare exchange (separate success and failure memory orders) + bool compare_exchange_strong( + T &expected, T desired, MemoryOrder success_order, + MemoryOrder failure_order, + [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) { + return __atomic_compare_exchange_n(&val, &expected, desired, false, + static_cast<int>(success_order), + static_cast<int>(failure_order)); + } + + // Atomic compare exchange (weak version) + bool compare_exchange_weak( + T &expected, T desired, MemoryOrder mem_ord = MemoryOrder::SEQ_CST, + [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) { + return __atomic_compare_exchange_n(&val, &expected, desired, true, + static_cast<int>(mem_ord), + static_cast<int>(mem_ord)); + } + + // Atomic compare exchange (weak version with separate success and failure + // memory orders) + bool compare_exchange_weak( + T &expected, T desired, MemoryOrder success_order, + MemoryOrder failure_order, + [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) { + return __atomic_compare_exchange_n(&val, &expected, desired, true, + static_cast<int>(success_order), + static_cast<int>(failure_order)); + } + T exchange(T desired, MemoryOrder mem_ord = MemoryOrder::SEQ_CST, [[maybe_unused]] MemoryScope mem_scope = MemoryScope::DEVICE) { #if __has_builtin(__scoped_atomic_exchange_n) diff --git a/src/__support/CPP/mutex.h b/src/__support/CPP/mutex.h new file mode 100644 index 000000000000..ff9c9f43a43c --- /dev/null +++ b/src/__support/CPP/mutex.h @@ -0,0 +1,49 @@ +//===--- A self contained equivalent of std::mutex --------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H +#define LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H + +namespace LIBC_NAMESPACE { +namespace cpp { + +// Assume the calling thread has already obtained mutex ownership. +struct adopt_lock_t { + explicit adopt_lock_t() = default; +}; + +// Tag used to make a scoped lock take ownership of a locked mutex. +constexpr adopt_lock_t adopt_lock{}; + +// An RAII class for easy locking and unlocking of mutexes. +template <typename MutexType> class lock_guard { + MutexType &mutex; + +public: + // Calls `m.lock()` upon resource acquisition. + explicit lock_guard(MutexType &m) : mutex(m) { mutex.lock(); } + + // Acquires ownership of the mutex object `m` without attempting to lock + // it. The behavior is undefined if the current thread does not hold the + // lock on `m`. Does not call `m.lock()` upon resource acquisition. + lock_guard(MutexType &m, adopt_lock_t /* t */) : mutex(m) {} + + ~lock_guard() { mutex.unlock(); } + + // non-copyable + lock_guard &operator=(const lock_guard &) = delete; + lock_guard(const lock_guard &) = delete; +}; + +// Deduction guide for lock_guard to suppress CTAD warnings. +template <typename T> lock_guard(T &) -> lock_guard<T>; + +} // namespace cpp +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC___SUPPORT_CPP_MUTEX_H diff --git a/src/__support/FPUtil/FMA.h b/src/__support/FPUtil/FMA.h index 0e1ede02d5cc..c277da49538b 100644 --- a/src/__support/FPUtil/FMA.h +++ b/src/__support/FPUtil/FMA.h @@ -9,25 +9,31 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FMA_H #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FMA_H +#include "src/__support/CPP/type_traits.h" #include "src/__support/macros/properties/architectures.h" #include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA #if defined(LIBC_TARGET_CPU_HAS_FMA) -#if defined(LIBC_TARGET_ARCH_IS_X86_64) -#include "x86_64/FMA.h" -#elif defined(LIBC_TARGET_ARCH_IS_AARCH64) -#include "aarch64/FMA.h" -#elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) -#include "riscv/FMA.h" -#elif defined(LIBC_TARGET_ARCH_IS_GPU) -#include "gpu/FMA.h" -#endif +namespace LIBC_NAMESPACE { +namespace fputil { + +template <typename T> +LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, float>, T> fma(T x, T y, T z) { + return __builtin_fmaf(x, y, z); +} + +template <typename T> +LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, double>, T> fma(T x, T y, T z) { + return __builtin_fma(x, y, z); +} + +} // namespace fputil +} // namespace LIBC_NAMESPACE #else // FMA instructions are not available #include "generic/FMA.h" -#include "src/__support/CPP/type_traits.h" namespace LIBC_NAMESPACE { namespace fputil { diff --git a/src/__support/FPUtil/aarch64/FEnvImpl.h b/src/__support/FPUtil/aarch64/FEnvImpl.h index d1d92169475d..cd8a5970edd6 100644 --- a/src/__support/FPUtil/aarch64/FEnvImpl.h +++ b/src/__support/FPUtil/aarch64/FEnvImpl.h @@ -53,19 +53,19 @@ struct FEnv { static constexpr uint32_t ExceptionControlFlagsBitPosition = 8; LIBC_INLINE static uint32_t getStatusValueForExcept(int excepts) { - return (excepts & FE_INVALID ? INVALID : 0) | - (excepts & FE_DIVBYZERO ? DIVBYZERO : 0) | - (excepts & FE_OVERFLOW ? OVERFLOW : 0) | - (excepts & FE_UNDERFLOW ? UNDERFLOW : 0) | - (excepts & FE_INEXACT ? INEXACT : 0); + return ((excepts & FE_INVALID) ? INVALID : 0) | + ((excepts & FE_DIVBYZERO) ? DIVBYZERO : 0) | + ((excepts & FE_OVERFLOW) ? OVERFLOW : 0) | + ((excepts & FE_UNDERFLOW) ? UNDERFLOW : 0) | + ((excepts & FE_INEXACT) ? INEXACT : 0); } LIBC_INLINE static int exceptionStatusToMacro(uint32_t status) { - return (status & INVALID ? FE_INVALID : 0) | - (status & DIVBYZERO ? FE_DIVBYZERO : 0) | - (status & OVERFLOW ? FE_OVERFLOW : 0) | - (status & UNDERFLOW ? FE_UNDERFLOW : 0) | - (status & INEXACT ? FE_INEXACT : 0); + return ((status & INVALID) ? FE_INVALID : 0) | + ((status & DIVBYZERO) ? FE_DIVBYZERO : 0) | + ((status & OVERFLOW) ? FE_OVERFLOW : 0) | + ((status & UNDERFLOW) ? FE_UNDERFLOW : 0) | + ((status & INEXACT) ? FE_INEXACT : 0); } static uint32_t getControlWord() { diff --git a/src/__support/FPUtil/aarch64/FMA.h b/src/__support/FPUtil/aarch64/FMA.h deleted file mode 100644 index 6254a0673ff4..000000000000 --- a/src/__support/FPUtil/aarch64/FMA.h +++ /dev/null @@ -1,50 +0,0 @@ -//===-- Aarch64 implementations of the fma function -------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_AARCH64_FMA_H -#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_AARCH64_FMA_H - -#include "src/__support/macros/attributes.h" // LIBC_INLINE -#include "src/__support/macros/properties/architectures.h" -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA - -#if !defined(LIBC_TARGET_ARCH_IS_AARCH64) -#error "Invalid include" -#endif - -#if !defined(LIBC_TARGET_CPU_HAS_FMA) -#error "FMA instructions are not supported" -#endif - -#include "src/__support/CPP/type_traits.h" - -namespace LIBC_NAMESPACE { -namespace fputil { - -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, float>, T> fma(T x, T y, T z) { - float result; - LIBC_INLINE_ASM("fmadd %s0, %s1, %s2, %s3\n\t" - : "=w"(result) - : "w"(x), "w"(y), "w"(z)); - return result; -} - -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, double>, T> fma(T x, T y, T z) { - double result; - LIBC_INLINE_ASM("fmadd %d0, %d1, %d2, %d3\n\t" - : "=w"(result) - : "w"(x), "w"(y), "w"(z)); - return result; -} - -} // namespace fputil -} // namespace LIBC_NAMESPACE - -#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_AARCH64_FMA_H diff --git a/src/__support/FPUtil/aarch64/fenv_darwin_impl.h b/src/__support/FPUtil/aarch64/fenv_darwin_impl.h index 5b59ba38d67b..feb48e3719bf 100644 --- a/src/__support/FPUtil/aarch64/fenv_darwin_impl.h +++ b/src/__support/FPUtil/aarch64/fenv_darwin_impl.h @@ -63,39 +63,39 @@ struct FEnv { // located in a different place from FE_FLUSHTOZERO status bit relative to // the other exceptions. LIBC_INLINE static uint32_t exception_value_from_status(int status) { - return (status & FE_INVALID ? EX_INVALID : 0) | - (status & FE_DIVBYZERO ? EX_DIVBYZERO : 0) | - (status & FE_OVERFLOW ? EX_OVERFLOW : 0) | - (status & FE_UNDERFLOW ? EX_UNDERFLOW : 0) | - (status & FE_INEXACT ? EX_INEXACT : 0) | - (status & FE_FLUSHTOZERO ? EX_FLUSHTOZERO : 0); + return ((status & FE_INVALID) ? EX_INVALID : 0) | + ((status & FE_DIVBYZERO) ? EX_DIVBYZERO : 0) | + ((status & FE_OVERFLOW) ? EX_OVERFLOW : 0) | + ((status & FE_UNDERFLOW) ? EX_UNDERFLOW : 0) | + ((status & FE_INEXACT) ? EX_INEXACT : 0) | + ((status & FE_FLUSHTOZERO) ? EX_FLUSHTOZERO : 0); } LIBC_INLINE static uint32_t exception_value_from_control(int control) { - return (control & __fpcr_trap_invalid ? EX_INVALID : 0) | - (control & __fpcr_trap_divbyzero ? EX_DIVBYZERO : 0) | - (control & __fpcr_trap_overflow ? EX_OVERFLOW : 0) | - (control & __fpcr_trap_underflow ? EX_UNDERFLOW : 0) | - (control & __fpcr_trap_inexact ? EX_INEXACT : 0) | - (control & __fpcr_flush_to_zero ? EX_FLUSHTOZERO : 0); + return ((control & __fpcr_trap_invalid) ? EX_INVALID : 0) | + ((control & __fpcr_trap_divbyzero) ? EX_DIVBYZERO : 0) | + ((control & __fpcr_trap_overflow) ? EX_OVERFLOW : 0) | + ((control & __fpcr_trap_underflow) ? EX_UNDERFLOW : 0) | + ((control & __fpcr_trap_inexact) ? EX_INEXACT : 0) | + ((control & __fpcr_flush_to_zero) ? EX_FLUSHTOZERO : 0); } LIBC_INLINE static int exception_value_to_status(uint32_t excepts) { - return (excepts & EX_INVALID ? FE_INVALID : 0) | - (excepts & EX_DIVBYZERO ? FE_DIVBYZERO : 0) | - (excepts & EX_OVERFLOW ? FE_OVERFLOW : 0) | - (excepts & EX_UNDERFLOW ? FE_UNDERFLOW : 0) | - (excepts & EX_INEXACT ? FE_INEXACT : 0) | - (excepts & EX_FLUSHTOZERO ? FE_FLUSHTOZERO : 0); + return ((excepts & EX_INVALID) ? FE_INVALID : 0) | + ((excepts & EX_DIVBYZERO) ? FE_DIVBYZERO : 0) | + ((excepts & EX_OVERFLOW) ? FE_OVERFLOW : 0) | + ((excepts & EX_UNDERFLOW) ? FE_UNDERFLOW : 0) | + ((excepts & EX_INEXACT) ? FE_INEXACT : 0) | + ((excepts & EX_FLUSHTOZERO) ? FE_FLUSHTOZERO : 0); } LIBC_INLINE static int exception_value_to_control(uint32_t excepts) { - return (excepts & EX_INVALID ? __fpcr_trap_invalid : 0) | - (excepts & EX_DIVBYZERO ? __fpcr_trap_divbyzero : 0) | - (excepts & EX_OVERFLOW ? __fpcr_trap_overflow : 0) | - (excepts & EX_UNDERFLOW ? __fpcr_trap_underflow : 0) | - (excepts & EX_INEXACT ? __fpcr_trap_inexact : 0) | - (excepts & EX_FLUSHTOZERO ? __fpcr_flush_to_zero : 0); + return ((excepts & EX_INVALID) ? __fpcr_trap_invalid : 0) | + ((excepts & EX_DIVBYZERO) ? __fpcr_trap_divbyzero : 0) | + ((excepts & EX_OVERFLOW) ? __fpcr_trap_overflow : 0) | + ((excepts & EX_UNDERFLOW) ? __fpcr_trap_underflow : 0) | + ((excepts & EX_INEXACT) ? __fpcr_trap_inexact : 0) | + ((excepts & EX_FLUSHTOZERO) ? __fpcr_flush_to_zero : 0); } LIBC_INLINE static uint32_t get_control_word() { return __arm_rsr("fpcr"); } diff --git a/src/__support/FPUtil/arm/FEnvImpl.h b/src/__support/FPUtil/arm/FEnvImpl.h index 78fbda4f7aff..cb8d31d683af 100644 --- a/src/__support/FPUtil/arm/FEnvImpl.h +++ b/src/__support/FPUtil/arm/FEnvImpl.h @@ -50,35 +50,35 @@ struct FEnv { } LIBC_INLINE static int exception_enable_bits_to_macro(uint32_t status) { - return (status & INVALID_ENABLE ? FE_INVALID : 0) | - (status & DIVBYZERO_ENABLE ? FE_DIVBYZERO : 0) | - (status & OVERFLOW_ENABLE ? FE_OVERFLOW : 0) | - (status & UNDERFLOW_ENABLE ? FE_UNDERFLOW : 0) | - (status & INEXACT_ENABLE ? FE_INEXACT : 0); + return ((status & INVALID_ENABLE) ? FE_INVALID : 0) | + ((status & DIVBYZERO_ENABLE) ? FE_DIVBYZERO : 0) | + ((status & OVERFLOW_ENABLE) ? FE_OVERFLOW : 0) | + ((status & UNDERFLOW_ENABLE) ? FE_UNDERFLOW : 0) | + ((status & INEXACT_ENABLE) ? FE_INEXACT : 0); } LIBC_INLINE static uint32_t exception_macro_to_enable_bits(int except) { - return (except & FE_INVALID ? INVALID_ENABLE : 0) | - (except & FE_DIVBYZERO ? DIVBYZERO_ENABLE : 0) | - (except & FE_OVERFLOW ? OVERFLOW_ENABLE : 0) | - (except & FE_UNDERFLOW ? UNDERFLOW_ENABLE : 0) | - (except & FE_INEXACT ? INEXACT_ENABLE : 0); + return ((except & FE_INVALID) ? INVALID_ENABLE : 0) | + ((except & FE_DIVBYZERO) ? DIVBYZERO_ENABLE : 0) | + ((except & FE_OVERFLOW) ? OVERFLOW_ENABLE : 0) | + ((except & FE_UNDERFLOW) ? UNDERFLOW_ENABLE : 0) | + ((except & FE_INEXACT) ? INEXACT_ENABLE : 0); } LIBC_INLINE static uint32_t exception_macro_to_status_bits(int except) { - return (except & FE_INVALID ? INVALID_STATUS : 0) | - (except & FE_DIVBYZERO ? DIVBYZERO_STATUS : 0) | - (except & FE_OVERFLOW ? OVERFLOW_STATUS : 0) | - (except & FE_UNDERFLOW ? UNDERFLOW_STATUS : 0) | - (except & FE_INEXACT ? INEXACT_STATUS : 0); + return ((except & FE_INVALID) ? INVALID_STATUS : 0) | + ((except & FE_DIVBYZERO) ? DIVBYZERO_STATUS : 0) | + ((except & FE_OVERFLOW) ? OVERFLOW_STATUS : 0) | + ((except & FE_UNDERFLOW) ? UNDERFLOW_STATUS : 0) | + ((except & FE_INEXACT) ? INEXACT_STATUS : 0); } LIBC_INLINE static uint32_t exception_status_bits_to_macro(int status) { - return (status & INVALID_STATUS ? FE_INVALID : 0) | - (status & DIVBYZERO_STATUS ? FE_DIVBYZERO : 0) | - (status & OVERFLOW_STATUS ? FE_OVERFLOW : 0) | - (status & UNDERFLOW_STATUS ? FE_UNDERFLOW : 0) | - (status & INEXACT_STATUS ? FE_INEXACT : 0); + return ((status & INVALID_STATUS) ? FE_INVALID : 0) | + ((status & DIVBYZERO_STATUS) ? FE_DIVBYZERO : 0) | + ((status & OVERFLOW_STATUS) ? FE_OVERFLOW : 0) | + ((status & UNDERFLOW_STATUS) ? FE_UNDERFLOW : 0) | + ((status & INEXACT_STATUS) ? FE_INEXACT : 0); } }; diff --git a/src/__support/FPUtil/gpu/FMA.h b/src/__support/FPUtil/gpu/FMA.h deleted file mode 100644 index ef1cd26a72dd..000000000000 --- a/src/__support/FPUtil/gpu/FMA.h +++ /dev/null @@ -1,36 +0,0 @@ -//===-- GPU implementations of the fma function -----------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_GPU_FMA_H -#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_GPU_FMA_H - -#include "src/__support/CPP/type_traits.h" - -// These intrinsics map to the FMA instructions in the target ISA for the GPU. -// The default rounding mode generated from these will be to the nearest even. -#if !__has_builtin(__builtin_fma) || !__has_builtin(__builtin_fmaf) -#error "FMA builtins must be defined"); -#endif - -namespace LIBC_NAMESPACE { -namespace fputil { - -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, float>, T> fma(T x, T y, T z) { - return __builtin_fmaf(x, y, z); -} - -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, double>, T> fma(T x, T y, T z) { - return __builtin_fma(x, y, z); -} - -} // namespace fputil -} // namespace LIBC_NAMESPACE - -#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_GPU_FMA_H diff --git a/src/__support/FPUtil/riscv/FEnvImpl.h b/src/__support/FPUtil/riscv/FEnvImpl.h index e7aee3ba4b91..1de464a89de4 100644 --- a/src/__support/FPUtil/riscv/FEnvImpl.h +++ b/src/__support/FPUtil/riscv/FEnvImpl.h @@ -65,19 +65,19 @@ struct FEnv { } LIBC_INLINE static int exception_bits_to_macro(uint32_t status) { - return (status & INVALID ? FE_INVALID : 0) | - (status & DIVBYZERO ? FE_DIVBYZERO : 0) | - (status & OVERFLOW ? FE_OVERFLOW : 0) | - (status & UNDERFLOW ? FE_UNDERFLOW : 0) | - (status & INEXACT ? FE_INEXACT : 0); + return ((status & INVALID) ? FE_INVALID : 0) | + ((status & DIVBYZERO) ? FE_DIVBYZERO : 0) | + ((status & OVERFLOW) ? FE_OVERFLOW : 0) | + ((status & UNDERFLOW) ? FE_UNDERFLOW : 0) | + ((status & INEXACT) ? FE_INEXACT : 0); } LIBC_INLINE static uint32_t exception_macro_to_bits(int except) { - return (except & FE_INVALID ? INVALID : 0) | - (except & FE_DIVBYZERO ? DIVBYZERO : 0) | - (except & FE_OVERFLOW ? OVERFLOW : 0) | - (except & FE_UNDERFLOW ? UNDERFLOW : 0) | - (except & FE_INEXACT ? INEXACT : 0); + return ((except & FE_INVALID) ? INVALID : 0) | + ((except & FE_DIVBYZERO) ? DIVBYZERO : 0) | + ((except & FE_OVERFLOW) ? OVERFLOW : 0) | + ((except & FE_UNDERFLOW) ? UNDERFLOW : 0) | + ((except & FE_INEXACT) ? INEXACT : 0); } }; diff --git a/src/__support/FPUtil/riscv/FMA.h b/src/__support/FPUtil/riscv/FMA.h deleted file mode 100644 index f01962174f16..000000000000 --- a/src/__support/FPUtil/riscv/FMA.h +++ /dev/null @@ -1,54 +0,0 @@ -//===-- RISCV implementations of the fma function ---------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FMA_H -#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FMA_H - -#include "src/__support/macros/attributes.h" // LIBC_INLINE -#include "src/__support/macros/properties/architectures.h" -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA - -#if !defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) -#error "Invalid include" -#endif - -#if !defined(LIBC_TARGET_CPU_HAS_FMA) -#error "FMA instructions are not supported" -#endif - -#include "src/__support/CPP/type_traits.h" - -namespace LIBC_NAMESPACE { -namespace fputil { - -#ifdef __riscv_flen -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, float>, T> fma(T x, T y, T z) { - float result; - LIBC_INLINE_ASM("fmadd.s %0, %1, %2, %3\n\t" - : "=f"(result) - : "f"(x), "f"(y), "f"(z)); - return result; -} - -#if __riscv_flen >= 64 -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, double>, T> fma(T x, T y, T z) { - double result; - LIBC_INLINE_ASM("fmadd.d %0, %1, %2, %3\n\t" - : "=f"(result) - : "f"(x), "f"(y), "f"(z)); - return result; -} -#endif // __riscv_flen >= 64 -#endif // __riscv_flen - -} // namespace fputil -} // namespace LIBC_NAMESPACE - -#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_RISCV_FMA_H diff --git a/src/__support/FPUtil/x86_64/FEnvImpl.h b/src/__support/FPUtil/x86_64/FEnvImpl.h index 0595658d7df3..a157b81aaaf3 100644 --- a/src/__support/FPUtil/x86_64/FEnvImpl.h +++ b/src/__support/FPUtil/x86_64/FEnvImpl.h @@ -72,25 +72,25 @@ static constexpr uint16_t MXCSR_EXCEPTION_CONTOL_BIT_POISTION = 7; LIBC_INLINE uint16_t get_status_value_for_except(int excepts) { // We will make use of the fact that exception control bits are single // bit flags in the control registers. - return (excepts & FE_INVALID ? ExceptionFlags::INVALID_F : 0) | + return ((excepts & FE_INVALID) ? ExceptionFlags::INVALID_F : 0) | #ifdef __FE_DENORM - (excepts & __FE_DENORM ? ExceptionFlags::DENORMAL_F : 0) | + ((excepts & __FE_DENORM) ? ExceptionFlags::DENORMAL_F : 0) | #endif // __FE_DENORM - (excepts & FE_DIVBYZERO ? ExceptionFlags::DIV_BY_ZERO_F : 0) | - (excepts & FE_OVERFLOW ? ExceptionFlags::OVERFLOW_F : 0) | - (excepts & FE_UNDERFLOW ? ExceptionFlags::UNDERFLOW_F : 0) | - (excepts & FE_INEXACT ? ExceptionFlags::INEXACT_F : 0); + ((excepts & FE_DIVBYZERO) ? ExceptionFlags::DIV_BY_ZERO_F : 0) | + ((excepts & FE_OVERFLOW) ? ExceptionFlags::OVERFLOW_F : 0) | + ((excepts & FE_UNDERFLOW) ? ExceptionFlags::UNDERFLOW_F : 0) | + ((excepts & FE_INEXACT) ? ExceptionFlags::INEXACT_F : 0); } LIBC_INLINE int exception_status_to_macro(uint16_t status) { - return (status & ExceptionFlags::INVALID_F ? FE_INVALID : 0) | + return ((status & ExceptionFlags::INVALID_F) ? FE_INVALID : 0) | #ifdef __FE_DENORM - (status & ExceptionFlags::DENORMAL_F ? __FE_DENORM : 0) | + ((status & ExceptionFlags::DENORMAL_F) ? __FE_DENORM : 0) | #endif // __FE_DENORM - (status & ExceptionFlags::DIV_BY_ZERO_F ? FE_DIVBYZERO : 0) | - (status & ExceptionFlags::OVERFLOW_F ? FE_OVERFLOW : 0) | - (status & ExceptionFlags::UNDERFLOW_F ? FE_UNDERFLOW : 0) | - (status & ExceptionFlags::INEXACT_F ? FE_INEXACT : 0); + ((status & ExceptionFlags::DIV_BY_ZERO_F) ? FE_DIVBYZERO : 0) | + ((status & ExceptionFlags::OVERFLOW_F) ? FE_OVERFLOW : 0) | + ((status & ExceptionFlags::UNDERFLOW_F) ? FE_UNDERFLOW : 0) | + ((status & ExceptionFlags::INEXACT_F) ? FE_INEXACT : 0); } struct X87StateDescriptor { diff --git a/src/__support/FPUtil/x86_64/FMA.h b/src/__support/FPUtil/x86_64/FMA.h deleted file mode 100644 index 91ef7f96ff4d..000000000000 --- a/src/__support/FPUtil/x86_64/FMA.h +++ /dev/null @@ -1,55 +0,0 @@ -//===-- x86_64 implementations of the fma function --------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FMA_H -#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FMA_H - -#include "src/__support/macros/attributes.h" // LIBC_INLINE -#include "src/__support/macros/properties/architectures.h" -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA - -#if !defined(LIBC_TARGET_ARCH_IS_X86_64) -#error "Invalid include" -#endif - -#if !defined(LIBC_TARGET_CPU_HAS_FMA) -#error "FMA instructions are not supported" -#endif - -#include "src/__support/CPP/type_traits.h" -#include <immintrin.h> - -namespace LIBC_NAMESPACE { -namespace fputil { - -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, float>, T> fma(T x, T y, T z) { - float result; - __m128 xmm = _mm_load_ss(&x); // NOLINT - __m128 ymm = _mm_load_ss(&y); // NOLINT - __m128 zmm = _mm_load_ss(&z); // NOLINT - __m128 r = _mm_fmadd_ss(xmm, ymm, zmm); // NOLINT - _mm_store_ss(&result, r); // NOLINT - return result; -} - -template <typename T> -LIBC_INLINE cpp::enable_if_t<cpp::is_same_v<T, double>, T> fma(T x, T y, T z) { - double result; - __m128d xmm = _mm_load_sd(&x); // NOLINT - __m128d ymm = _mm_load_sd(&y); // NOLINT - __m128d zmm = _mm_load_sd(&z); // NOLINT - __m128d r = _mm_fmadd_sd(xmm, ymm, zmm); // NOLINT - _mm_store_sd(&result, r); // NOLINT - return result; -} - -} // namespace fputil -} // namespace LIBC_NAMESPACE - -#endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_X86_64_FMA_H diff --git a/src/__support/File/dir.cpp b/src/__support/File/dir.cpp index 9ff639a777e2..e0f7695b3932 100644 --- a/src/__support/File/dir.cpp +++ b/src/__support/File/dir.cpp @@ -8,6 +8,7 @@ #include "dir.h" +#include "src/__support/CPP/mutex.h" // lock_guard #include "src/__support/CPP/new.h" #include "src/__support/error_or.h" #include "src/errno/libc_errno.h" // For error macros @@ -27,7 +28,7 @@ ErrorOr<Dir *> Dir::open(const char *path) { } ErrorOr<struct ::dirent *> Dir::read() { - MutexLock lock(&mutex); + cpp::lock_guard lock(mutex); if (readptr >= fillsize) { auto readsize = platform_fetch_dirents(fd, buffer); if (!readsize) @@ -51,7 +52,7 @@ ErrorOr<struct ::dirent *> Dir::read() { int Dir::close() { { - MutexLock lock(&mutex); + cpp::lock_guard lock(mutex); int retval = platform_closedir(fd); if (retval != 0) return retval; diff --git a/src/__support/GPU/amdgpu/utils.h b/src/__support/GPU/amdgpu/utils.h index 9b520a6bcf38..5f8ad74f6aea 100644 --- a/src/__support/GPU/amdgpu/utils.h +++ b/src/__support/GPU/amdgpu/utils.h @@ -140,6 +140,11 @@ LIBC_INLINE uint32_t get_lane_size() { __builtin_amdgcn_fence(__ATOMIC_ACQUIRE, "workgroup"); } +/// Waits for all pending memory operations to complete in program order. +[[clang::convergent]] LIBC_INLINE void memory_fence() { + __builtin_amdgcn_fence(__ATOMIC_ACQ_REL, ""); +} + /// Wait for all threads in the wavefront to converge, this is a noop on AMDGPU. [[clang::convergent]] LIBC_INLINE void sync_lane(uint64_t) { __builtin_amdgcn_wave_barrier(); diff --git a/src/__support/GPU/nvptx/utils.h b/src/__support/GPU/nvptx/utils.h index 3f19afb83648..88b8ee2e31d3 100644 --- a/src/__support/GPU/nvptx/utils.h +++ b/src/__support/GPU/nvptx/utils.h @@ -118,9 +118,13 @@ LIBC_INLINE uint32_t get_lane_size() { return 32; } uint32_t mask = static_cast<uint32_t>(lane_mask); return __nvvm_vote_ballot_sync(mask, x); } + /// Waits for all the threads in the block to converge and issues a fence. [[clang::convergent]] LIBC_INLINE void sync_threads() { __syncthreads(); } +/// Waits for all pending memory operations to complete in program order. +[[clang::convergent]] LIBC_INLINE void memory_fence() { __nvvm_membar_sys(); } + /// Waits for all threads in the warp to reconverge for independent scheduling. [[clang::convergent]] LIBC_INLINE void sync_lane(uint64_t mask) { __nvvm_bar_warp_sync(static_cast<uint32_t>(mask)); diff --git a/src/__support/threads/fork_callbacks.cpp b/src/__support/threads/fork_callbacks.cpp index 54fda676f281..6efaf62f135a 100644 --- a/src/__support/threads/fork_callbacks.cpp +++ b/src/__support/threads/fork_callbacks.cpp @@ -8,6 +8,7 @@ #include "fork_callbacks.h" +#include "src/__support/CPP/mutex.h" // lock_guard #include "src/__support/threads/mutex.h" #include <stddef.h> // For size_t @@ -35,7 +36,7 @@ public: constexpr AtForkCallbackManager() : mtx(false, false, false), next_index(0) {} bool register_triple(const ForkCallbackTriple &triple) { - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); if (next_index >= CALLBACK_SIZE) return false; list[next_index] = triple; @@ -44,7 +45,7 @@ public: } void invoke_prepare() { - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); for (size_t i = 0; i < next_index; ++i) { auto prepare = list[i].prepare; if (prepare) @@ -53,7 +54,7 @@ public: } void invoke_parent() { - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); for (size_t i = 0; i < next_index; ++i) { auto parent = list[i].parent; if (parent) @@ -62,7 +63,7 @@ public: } void invoke_child() { - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); for (size_t i = 0; i < next_index; ++i) { auto child = list[i].child; if (child) diff --git a/src/__support/threads/linux/callonce.cpp b/src/__support/threads/linux/callonce.cpp index b6a5ab8c0d07..b48a514a4487 100644 --- a/src/__support/threads/linux/callonce.cpp +++ b/src/__support/threads/linux/callonce.cpp @@ -6,15 +6,9 @@ // //===----------------------------------------------------------------------===// -#include "futex_word.h" - -#include "src/__support/CPP/atomic.h" -#include "src/__support/CPP/limits.h" // INT_MAX -#include "src/__support/OSUtil/syscall.h" // For syscall functions. #include "src/__support/threads/callonce.h" - -#include <linux/futex.h> -#include <sys/syscall.h> // For syscall numbers. +#include "src/__support/macros/optimization.h" +#include "src/__support/threads/linux/futex_utils.h" namespace LIBC_NAMESPACE { @@ -24,31 +18,30 @@ static constexpr FutexWordType WAITING = 0x22; static constexpr FutexWordType FINISH = 0x33; int callonce(CallOnceFlag *flag, CallOnceCallback *func) { - auto *futex_word = reinterpret_cast<cpp::Atomic<FutexWordType> *>(flag); + auto *futex_word = reinterpret_cast<Futex *>(flag); FutexWordType not_called = NOT_CALLED; + // Avoid cmpxchg operation if the function has already been called. + // The destination operand of cmpxchg may receive a write cycle without + // regard to the result of the comparison + if (LIBC_LIKELY(futex_word->load(cpp::MemoryOrder::RELAXED) == FINISH)) + return 0; + // The call_once call can return only after the called function |func| // returns. So, we use futexes to synchronize calls with the same flag value. if (futex_word->compare_exchange_strong(not_called, START)) { func(); auto status = futex_word->exchange(FINISH); - if (status == WAITING) { - LIBC_NAMESPACE::syscall_impl<long>(FUTEX_SYSCALL_ID, &futex_word->val, - FUTEX_WAKE_PRIVATE, - INT_MAX, // Wake all waiters. - 0, 0, 0); - } + if (status == WAITING) + futex_word->notify_all(); return 0; } FutexWordType status = START; if (futex_word->compare_exchange_strong(status, WAITING) || status == WAITING) { - LIBC_NAMESPACE::syscall_impl<long>( - FUTEX_SYSCALL_ID, &futex_word->val, FUTEX_WAIT_PRIVATE, - WAITING, // Block only if status is still |WAITING|. - 0, 0, 0); + futex_word->wait(WAITING); } return 0; diff --git a/src/__support/threads/linux/futex_utils.h b/src/__support/threads/linux/futex_utils.h new file mode 100644 index 000000000000..1fbce4f7bf43 --- /dev/null +++ b/src/__support/threads/linux/futex_utils.h @@ -0,0 +1,90 @@ +//===--- Futex Wrapper ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H + +#include "hdr/types/struct_timespec.h" +#include "src/__support/CPP/atomic.h" +#include "src/__support/CPP/limits.h" +#include "src/__support/CPP/optional.h" +#include "src/__support/OSUtil/syscall.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/threads/linux/futex_word.h" +#include <linux/errno.h> +#include <linux/futex.h> + +namespace LIBC_NAMESPACE { +class Futex : public cpp::Atomic<FutexWordType> { +public: + struct Timeout { + timespec abs_time; + bool is_realtime; + }; + LIBC_INLINE constexpr Futex(FutexWordType value) + : cpp::Atomic<FutexWordType>(value) {} + LIBC_INLINE Futex &operator=(FutexWordType value) { + cpp::Atomic<FutexWordType>::store(value); + return *this; + } + LIBC_INLINE long wait(FutexWordType expected, + cpp::optional<Timeout> timeout = cpp::nullopt, + bool is_shared = false) { + // use bitset variants to enforce abs_time + uint32_t op = is_shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE; + if (timeout && timeout->is_realtime) { + op |= FUTEX_CLOCK_REALTIME; + } + for (;;) { + if (this->load(cpp::MemoryOrder::RELAXED) != expected) + return 0; + + long ret = syscall_impl<long>( + /* syscall number */ FUTEX_SYSCALL_ID, + /* futex address */ this, + /* futex operation */ op, + /* expected value */ expected, + /* timeout */ timeout ? &timeout->abs_time : nullptr, + /* ignored */ nullptr, + /* bitset */ FUTEX_BITSET_MATCH_ANY); + + // continue waiting if interrupted; otherwise return the result + // which should normally be 0 or -ETIMEOUT + if (ret == -EINTR) + continue; + + return ret; + } + } + LIBC_INLINE long notify_one(bool is_shared = false) { + return syscall_impl<long>( + /* syscall number */ FUTEX_SYSCALL_ID, + /* futex address */ this, + /* futex operation */ is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, + /* wake up limit */ 1, + /* ignored */ nullptr, + /* ignored */ nullptr, + /* ignored */ 0); + } + LIBC_INLINE long notify_all(bool is_shared = false) { + return syscall_impl<long>( + /* syscall number */ FUTEX_SYSCALL_ID, + /* futex address */ this, + /* futex operation */ is_shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, + /* wake up limit */ cpp::numeric_limits<int>::max(), + /* ignored */ nullptr, + /* ignored */ nullptr, + /* ignored */ 0); + } +}; + +static_assert(__is_standard_layout(Futex), + "Futex must be a standard layout type."); +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_FUTEX_UTILS_H diff --git a/src/__support/threads/linux/futex_word.h b/src/__support/threads/linux/futex_word.h index 67159b81b561..acdd33bcdaaf 100644 --- a/src/__support/threads/linux/futex_word.h +++ b/src/__support/threads/linux/futex_word.h @@ -11,7 +11,6 @@ #include <stdint.h> #include <sys/syscall.h> - namespace LIBC_NAMESPACE { // Futexes are 32 bits in size on all platforms, including 64-bit platforms. diff --git a/src/__support/threads/linux/mutex.h b/src/__support/threads/linux/mutex.h index 618698db0d25..6702de465168 100644 --- a/src/__support/threads/linux/mutex.h +++ b/src/__support/threads/linux/mutex.h @@ -9,17 +9,10 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H #define LLVM_LIBC_SRC___SUPPORT_THREADS_LINUX_MUTEX_H -#include "src/__support/CPP/atomic.h" -#include "src/__support/OSUtil/syscall.h" // For syscall functions. -#include "src/__support/threads/linux/futex_word.h" +#include "src/__support/threads/linux/futex_utils.h" #include "src/__support/threads/mutex_common.h" -#include <linux/futex.h> -#include <stdint.h> -#include <sys/syscall.h> // For syscall numbers. - namespace LIBC_NAMESPACE { - struct Mutex { unsigned char timed; unsigned char recursive; @@ -28,7 +21,7 @@ struct Mutex { void *owner; unsigned long long lock_count; - cpp::Atomic<FutexWordType> futex_word; + Futex futex_word; enum class LockState : FutexWordType { Free, @@ -76,9 +69,7 @@ public: // futex syscall will block if the futex data is still // `LockState::Waiting` (the 4th argument to the syscall function // below.) - LIBC_NAMESPACE::syscall_impl<long>( - FUTEX_SYSCALL_ID, &futex_word.val, FUTEX_WAIT_PRIVATE, - FutexWordType(LockState::Waiting), 0, 0, 0); + futex_word.wait(FutexWordType(LockState::Waiting)); was_waiting = true; // Once woken up/unblocked, try everything all over. continue; @@ -91,9 +82,7 @@ public: // we will wait for the futex to be woken up. Note again that the // following syscall will block only if the futex data is still // `LockState::Waiting`. - LIBC_NAMESPACE::syscall_impl<long>( - FUTEX_SYSCALL_ID, &futex_word, FUTEX_WAIT_PRIVATE, - FutexWordType(LockState::Waiting), 0, 0, 0); + futex_word.wait(FutexWordType(LockState::Waiting)); was_waiting = true; } continue; @@ -110,8 +99,7 @@ public: if (futex_word.compare_exchange_strong(mutex_status, FutexWordType(LockState::Free))) { // If any thread is waiting to be woken up, then do it. - LIBC_NAMESPACE::syscall_impl<long>(FUTEX_SYSCALL_ID, &futex_word, - FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); + futex_word.notify_one(); return MutexError::NONE; } diff --git a/src/__support/threads/linux/thread.cpp b/src/__support/threads/linux/thread.cpp index fcf87cc587a5..1d986ff38cff 100644 --- a/src/__support/threads/linux/thread.cpp +++ b/src/__support/threads/linux/thread.cpp @@ -14,15 +14,14 @@ #include "src/__support/OSUtil/syscall.h" // For syscall functions. #include "src/__support/common.h" #include "src/__support/error_or.h" -#include "src/__support/threads/linux/futex_word.h" // For FutexWordType -#include "src/errno/libc_errno.h" // For error macros +#include "src/__support/threads/linux/futex_utils.h" // For FutexWordType +#include "src/errno/libc_errno.h" // For error macros #ifdef LIBC_TARGET_ARCH_IS_AARCH64 #include <arm_acle.h> #endif #include <fcntl.h> -#include <linux/futex.h> #include <linux/param.h> // For EXEC_PAGESIZE. #include <linux/prctl.h> // For PR_SET_NAME #include <linux/sched.h> // For CLONE_* flags. @@ -247,8 +246,7 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, // stack memory. static constexpr size_t INTERNAL_STACK_DATA_SIZE = - sizeof(StartArgs) + sizeof(ThreadAttributes) + - sizeof(cpp::Atomic<FutexWordType>); + sizeof(StartArgs) + sizeof(ThreadAttributes) + sizeof(Futex); // This is pretty arbitrary, but at the moment we don't adjust user provided // stacksize (or default) to account for this data as its assumed minimal. If @@ -288,9 +286,9 @@ int Thread::run(ThreadStyle style, ThreadRunner runner, void *arg, void *stack, start_args->runner = runner; start_args->arg = arg; - auto clear_tid = reinterpret_cast<cpp::Atomic<FutexWordType> *>( + auto clear_tid = reinterpret_cast<Futex *>( adjusted_stack + sizeof(StartArgs) + sizeof(ThreadAttributes)); - clear_tid->val = CLEAR_TID_VALUE; + clear_tid->set(CLEAR_TID_VALUE); attrib->platform_data = clear_tid; // The clone syscall takes arguments in an architecture specific order. @@ -374,14 +372,11 @@ void Thread::wait() { // The kernel should set the value at the clear tid address to zero. // If not, it is a spurious wake and we should continue to wait on // the futex. - auto *clear_tid = - reinterpret_cast<cpp::Atomic<FutexWordType> *>(attrib->platform_data); - while (clear_tid->load() != 0) { - // We cannot do a FUTEX_WAIT_PRIVATE here as the kernel does a - // FUTEX_WAKE and not a FUTEX_WAKE_PRIVATE. - LIBC_NAMESPACE::syscall_impl<long>(FUTEX_SYSCALL_ID, &clear_tid->val, - FUTEX_WAIT, CLEAR_TID_VALUE, nullptr); - } + auto *clear_tid = reinterpret_cast<Futex *>(attrib->platform_data); + // We cannot do a FUTEX_WAIT_PRIVATE here as the kernel does a + // FUTEX_WAKE and not a FUTEX_WAKE_PRIVATE. + while (clear_tid->load() != 0) + clear_tid->wait(CLEAR_TID_VALUE, cpp::nullopt, true); } bool Thread::operator==(const Thread &thread) const { diff --git a/src/__support/threads/mutex.h b/src/__support/threads/mutex.h index fa2bd64b6b51..9dded2e3f952 100644 --- a/src/__support/threads/mutex.h +++ b/src/__support/threads/mutex.h @@ -38,9 +38,9 @@ // want the constructors of the Mutex classes to be constexprs. #if defined(__linux__) -#include "linux/mutex.h" +#include "src/__support/threads/linux/mutex.h" #elif defined(LIBC_TARGET_ARCH_IS_GPU) -#include "gpu/mutex.h" +#include "src/__support/threads/gpu/mutex.h" #endif // __linux__ namespace LIBC_NAMESPACE { diff --git a/src/__support/threads/thread.cpp b/src/__support/threads/thread.cpp index 62aa86b7aef7..7b02f8246e24 100644 --- a/src/__support/threads/thread.cpp +++ b/src/__support/threads/thread.cpp @@ -6,10 +6,11 @@ // //===----------------------------------------------------------------------===// -#include "thread.h" -#include "mutex.h" +#include "src/__support/threads/thread.h" +#include "src/__support/threads/mutex.h" #include "src/__support/CPP/array.h" +#include "src/__support/CPP/mutex.h" // lock_guard #include "src/__support/CPP/optional.h" #include "src/__support/fixedvector.h" #include "src/__support/macros/attributes.h" @@ -56,7 +57,7 @@ public: constexpr TSSKeyMgr() : mtx(false, false, false) {} cpp::optional<unsigned int> new_key(TSSDtor *dtor) { - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); for (unsigned int i = 0; i < TSS_KEY_COUNT; ++i) { TSSKeyUnit &u = units[i]; if (!u.active) { @@ -70,20 +71,20 @@ public: TSSDtor *get_dtor(unsigned int key) { if (key >= TSS_KEY_COUNT) return nullptr; - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); return units[key].dtor; } bool remove_key(unsigned int key) { if (key >= TSS_KEY_COUNT) return false; - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); units[key].reset(); return true; } bool is_valid_key(unsigned int key) { - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); return units[key].active; } }; @@ -113,7 +114,7 @@ public: constexpr ThreadAtExitCallbackMgr() : mtx(false, false, false) {} int add_callback(AtExitCallback *callback, void *obj) { - MutexLock lock(&mtx); + cpp::lock_guard lock(mtx); return callback_list.push_back({callback, obj}); } diff --git a/src/time/linux/clockGetTimeImpl.h b/src/__support/time/linux/clock_gettime.cpp index 8c8c9fcf845c..7f266b282a39 100644 --- a/src/time/linux/clockGetTimeImpl.h +++ b/src/__support/time/linux/clock_gettime.cpp @@ -1,4 +1,4 @@ -//===- Linux implementation of the POSIX clock_gettime function -*- C++ -*-===// +//===--- clock_gettime linux implementation ---------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,23 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_TIME_LINUX_CLOCKGETTIMEIMPL_H -#define LLVM_LIBC_SRC_TIME_LINUX_CLOCKGETTIMEIMPL_H - -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. -#include "src/__support/common.h" -#include "src/__support/error_or.h" -#include "src/errno/libc_errno.h" - -#include <stdint.h> // For int64_t. -#include <sys/syscall.h> // For syscall numbers. -#include <time.h> - +#include "src/__support/time/linux/clock_gettime.h" +#include "src/__support/OSUtil/syscall.h" +#include <sys/syscall.h> namespace LIBC_NAMESPACE { namespace internal { - -LIBC_INLINE ErrorOr<int> clock_gettimeimpl(clockid_t clockid, - struct timespec *ts) { +ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts) { #if SYS_clock_gettime int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_clock_gettime, static_cast<long>(clockid), @@ -44,5 +33,3 @@ LIBC_INLINE ErrorOr<int> clock_gettimeimpl(clockid_t clockid, } // namespace internal } // namespace LIBC_NAMESPACE - -#endif // LLVM_LIBC_SRC_TIME_LINUX_CLOCKGETTIMEIMPL_H diff --git a/src/__support/time/linux/clock_gettime.h b/src/__support/time/linux/clock_gettime.h new file mode 100644 index 000000000000..b1572726f630 --- /dev/null +++ b/src/__support/time/linux/clock_gettime.h @@ -0,0 +1,23 @@ +//===--- clock_gettime linux implementation ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H +#define LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H +#include "hdr/types/clockid_t.h" +#include "hdr/types/struct_timespec.h" +#include "src/__support/common.h" + +#include "src/__support/error_or.h" + +namespace LIBC_NAMESPACE { +namespace internal { +ErrorOr<int> clock_gettime(clockid_t clockid, timespec *ts); +} +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC___SUPPORT_TIME_LINUX_CLOCK_GETTIME_H diff --git a/src/__support/time/units.h b/src/__support/time/units.h new file mode 100644 index 000000000000..f6bd19f9b139 --- /dev/null +++ b/src/__support/time/units.h @@ -0,0 +1,38 @@ +//===--- Time units conversion ----------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_TIME_UNITS_H +#define LLVM_LIBC_SRC___SUPPORT_TIME_UNITS_H + +#include "hdr/types/time_t.h" +#include "src/__support/common.h" + +namespace LIBC_NAMESPACE { +namespace time_units { +LIBC_INLINE constexpr time_t operator""_s_ns(unsigned long long s) { + return s * 1'000'000'000; +} +LIBC_INLINE constexpr time_t operator""_s_us(unsigned long long s) { + return s * 1'000'000; +} +LIBC_INLINE constexpr time_t operator""_s_ms(unsigned long long s) { + return s * 1'000; +} +LIBC_INLINE constexpr time_t operator""_ms_ns(unsigned long long ms) { + return ms * 1'000'000; +} +LIBC_INLINE constexpr time_t operator""_ms_us(unsigned long long ms) { + return ms * 1'000; +} +LIBC_INLINE constexpr time_t operator""_us_ns(unsigned long long us) { + return us * 1'000; +} +} // namespace time_units +} // namespace LIBC_NAMESPACE + +#endif // LLVM_LIBC_SRC___SUPPORT_TIME_UNITS_H diff --git a/src/math/generic/powf.cpp b/src/math/generic/powf.cpp index 0450ffd711ff..59efc3f424c7 100644 --- a/src/math/generic/powf.cpp +++ b/src/math/generic/powf.cpp @@ -528,7 +528,7 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { // So if |y| > 151 * 2^24, and x is finite: // |y * log2(x)| = 0 or > 151. // Hence x^y will either overflow or underflow if x is not zero. - if (LIBC_UNLIKELY((y_abs & 0x007f'ffff) == 0) || (y_abs > 0x4f170000)) { + if (LIBC_UNLIKELY((y_abs & 0x0007'ffff) == 0) || (y_abs > 0x4f170000)) { // Exceptional exponents. switch (y_abs) { case 0x0000'0000: { // y = +-0.0f @@ -572,6 +572,26 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { // case 0xbf00'0000: // pow(x, -1/2) = rsqrt(x) // return rsqrt(x); } + if (is_integer(y) && (y_u > 0x4000'0000) && (y_u <= 0x41c0'0000)) { + // Check for exact cases when 2 < y < 25 and y is an integer. + int msb = + (x_abs == 0) ? (FloatBits::TOTAL_LEN - 2) : cpp::countl_zero(x_abs); + msb = (msb > FloatBits::EXP_LEN) ? msb : FloatBits::EXP_LEN; + int lsb = (x_abs == 0) ? 0 : cpp::countr_zero(x_abs); + lsb = (lsb > FloatBits::FRACTION_LEN) ? FloatBits::FRACTION_LEN : lsb; + int extra_bits = FloatBits::TOTAL_LEN - 2 - lsb - msb; + int iter = static_cast<int>(y); + + if (extra_bits * iter <= FloatBits::FRACTION_LEN + 2) { + // The result is either exact or exactly half-way. + // But it is exactly representable in double precision. + double x_d = static_cast<double>(x); + double result = x_d; + for (int i = 1; i < iter; ++i) + result *= x_d; + return static_cast<float>(result); + } + } if (y_abs > 0x4f17'0000) { if (y_abs > 0x7f80'0000) { // y is NaN @@ -834,7 +854,6 @@ LLVM_LIBC_FUNCTION(float, powf, (float x, float y)) { return static_cast<float>( powf_double_double(idx_x, dx, y6, lo6_hi, exp2_hi_mid_dd)) + 0.0f; - // return static_cast<float>(r); } } // namespace LIBC_NAMESPACE diff --git a/src/stdlib/atexit.cpp b/src/stdlib/atexit.cpp index fa072b2fdf8d..4f0497444773 100644 --- a/src/stdlib/atexit.cpp +++ b/src/stdlib/atexit.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/stdlib/atexit.h" +#include "src/__support/CPP/mutex.h" // lock_guard #include "src/__support/blockstore.h" #include "src/__support/common.h" #include "src/__support/fixedvector.h" @@ -68,7 +69,7 @@ void call_exit_callbacks() { } int add_atexit_unit(const AtExitUnit &unit) { - MutexLock lock(&handler_list_mtx); + cpp::lock_guard lock(handler_list_mtx); if (exit_callbacks.push_back(unit)) return 0; return -1; diff --git a/src/threads/linux/CndVar.h b/src/threads/linux/CndVar.h index b4afdef9f9eb..c08ffa393856 100644 --- a/src/threads/linux/CndVar.h +++ b/src/threads/linux/CndVar.h @@ -10,8 +10,10 @@ #define LLVM_LIBC_SRC_THREADS_LINUX_CNDVAR_H #include "src/__support/CPP/atomic.h" +#include "src/__support/CPP/mutex.h" // lock_guard +#include "src/__support/CPP/optional.h" #include "src/__support/OSUtil/syscall.h" // For syscall functions. -#include "src/__support/threads/linux/futex_word.h" +#include "src/__support/threads/linux/futex_utils.h" #include "src/__support/threads/mutex.h" #include <linux/futex.h> // For futex operations. @@ -28,7 +30,7 @@ struct CndVar { }; struct CndWaiter { - cpp::Atomic<uint32_t> futex_word = WS_Waiting; + Futex futex_word = WS_Waiting; CndWaiter *next = nullptr; }; @@ -58,7 +60,7 @@ struct CndVar { CndWaiter waiter; { - MutexLock ml(&qmtx); + cpp::lock_guard ml(qmtx); CndWaiter *old_back = nullptr; if (waitq_front == nullptr) { waitq_front = waitq_back = &waiter; @@ -84,8 +86,7 @@ struct CndVar { } } - LIBC_NAMESPACE::syscall_impl<long>(FUTEX_SYSCALL_ID, &waiter.futex_word.val, - FUTEX_WAIT, WS_Waiting, 0, 0, 0); + waiter.futex_word.wait(WS_Waiting, cpp::nullopt, true); // At this point, if locking |m| fails, we can simply return as the // queued up waiter would have been removed from the queue. @@ -109,6 +110,7 @@ struct CndVar { qmtx.futex_word = FutexWordType(Mutex::LockState::Free); + // this is a special WAKE_OP, so we use syscall directly LIBC_NAMESPACE::syscall_impl<long>( FUTEX_SYSCALL_ID, &qmtx.futex_word.val, FUTEX_WAKE_OP, 1, 1, &first->futex_word.val, @@ -117,7 +119,7 @@ struct CndVar { } int broadcast() { - MutexLock ml(&qmtx); + cpp::lock_guard ml(qmtx); uint32_t dummy_futex_word; CndWaiter *waiter = waitq_front; waitq_front = waitq_back = nullptr; diff --git a/src/time/clock.h b/src/time/clock.h index d4af7656644a..f5d14d036e13 100644 --- a/src/time/clock.h +++ b/src/time/clock.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_SRC_TIME_CLOCK_H #define LLVM_LIBC_SRC_TIME_CLOCK_H -#include <time.h> +#include "hdr/types/clock_t.h" namespace LIBC_NAMESPACE { diff --git a/src/time/clock_gettime.h b/src/time/clock_gettime.h index 72e2e1949feb..48e81a355429 100644 --- a/src/time/clock_gettime.h +++ b/src/time/clock_gettime.h @@ -9,11 +9,12 @@ #ifndef LLVM_LIBC_SRC_TIME_CLOCK_GETTIME_H #define LLVM_LIBC_SRC_TIME_CLOCK_GETTIME_H -#include <time.h> +#include "hdr/types/clockid_t.h" +#include "hdr/types/struct_timespec.h" namespace LIBC_NAMESPACE { -int clock_gettime(clockid_t clockid, struct timespec *tp); +int clock_gettime(clockid_t clockid, timespec *tp); } // namespace LIBC_NAMESPACE diff --git a/src/time/gettimeofday.h b/src/time/gettimeofday.h index 880b94cee731..62ee31edcad6 100644 --- a/src/time/gettimeofday.h +++ b/src/time/gettimeofday.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_SRC_TIME_GETTIMEOFDAY_H #define LLVM_LIBC_SRC_TIME_GETTIMEOFDAY_H -#include <time.h> +#include "hdr/types/struct_timeval.h" namespace LIBC_NAMESPACE { diff --git a/src/time/gpu/clock.cpp b/src/time/gpu/clock.cpp index 86cc97e2a3bf..8ddfc27975bb 100644 --- a/src/time/gpu/clock.cpp +++ b/src/time/gpu/clock.cpp @@ -6,9 +6,8 @@ // //===----------------------------------------------------------------------===// -#include "time_utils.h" - #include "src/time/clock.h" +#include "src/time/gpu/time_utils.h" namespace LIBC_NAMESPACE { diff --git a/src/time/gpu/time_utils.h b/src/time/gpu/time_utils.h index 8a9a5f0f65b8..3f1fd11c1791 100644 --- a/src/time/gpu/time_utils.h +++ b/src/time/gpu/time_utils.h @@ -9,8 +9,9 @@ #ifndef LLVM_LIBC_SRC_TIME_GPU_TIME_UTILS_H #define LLVM_LIBC_SRC_TIME_GPU_TIME_UTILS_H +#include "hdr/time_macros.h" +#include "hdr/types/clock_t.h" #include "src/__support/GPU/utils.h" - namespace LIBC_NAMESPACE { #if defined(LIBC_TARGET_ARCH_IS_AMDGPU) diff --git a/src/time/linux/clock.cpp b/src/time/linux/clock.cpp index 1e95f0526bc9..2c1eee8e5d60 100644 --- a/src/time/linux/clock.cpp +++ b/src/time/linux/clock.cpp @@ -7,21 +7,19 @@ //===----------------------------------------------------------------------===// #include "src/time/clock.h" - +#include "hdr/time_macros.h" #include "src/__support/CPP/limits.h" -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/time/linux/clock_gettime.h" +#include "src/__support/time/units.h" #include "src/errno/libc_errno.h" -#include "src/time/linux/clockGetTimeImpl.h" - -#include <sys/syscall.h> // For syscall numbers. -#include <time.h> namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(clock_t, clock, ()) { + using namespace time_units; struct timespec ts; - auto result = internal::clock_gettimeimpl(CLOCK_PROCESS_CPUTIME_ID, &ts); + auto result = internal::clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); if (!result.has_value()) { libc_errno = result.error(); return -1; @@ -34,15 +32,15 @@ LLVM_LIBC_FUNCTION(clock_t, clock, ()) { cpp::numeric_limits<clock_t>::max() / CLOCKS_PER_SEC; if (ts.tv_sec > CLOCK_SECS_MAX) return clock_t(-1); - if (ts.tv_nsec / 1000000000 > CLOCK_SECS_MAX - ts.tv_sec) + if (ts.tv_nsec / 1_s_ns > CLOCK_SECS_MAX - ts.tv_sec) return clock_t(-1); // For the integer computation converting tv_nsec to clocks to work // correctly, we want CLOCKS_PER_SEC to be less than 1000000000. - static_assert(1000000000 > CLOCKS_PER_SEC, - "Expected CLOCKS_PER_SEC to be less than 1000000000."); + static_assert(1_s_ns > CLOCKS_PER_SEC, + "Expected CLOCKS_PER_SEC to be less than 1'000'000'000."); return clock_t(ts.tv_sec * CLOCKS_PER_SEC + - ts.tv_nsec / (1000000000 / CLOCKS_PER_SEC)); + ts.tv_nsec / (1_s_ns / CLOCKS_PER_SEC)); } } // namespace LIBC_NAMESPACE diff --git a/src/time/linux/clock_gettime.cpp b/src/time/linux/clock_gettime.cpp index 47e974a866c8..d7b8cfd245bc 100644 --- a/src/time/linux/clock_gettime.cpp +++ b/src/time/linux/clock_gettime.cpp @@ -7,21 +7,16 @@ //===----------------------------------------------------------------------===// #include "src/time/clock_gettime.h" - -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. #include "src/__support/common.h" +#include "src/__support/time/linux/clock_gettime.h" #include "src/errno/libc_errno.h" -#include "src/time/linux/clockGetTimeImpl.h" - -#include <sys/syscall.h> // For syscall numbers. -#include <time.h> namespace LIBC_NAMESPACE { // TODO(michaelrj): Move this into time/linux with the other syscalls. LLVM_LIBC_FUNCTION(int, clock_gettime, (clockid_t clockid, struct timespec *ts)) { - auto result = internal::clock_gettimeimpl(clockid, ts); + auto result = internal::clock_gettime(clockid, ts); // A negative return value indicates an error with the magnitude of the // value being the error code. diff --git a/src/time/linux/gettimeofday.cpp b/src/time/linux/gettimeofday.cpp index 07ab4d579176..f868f5ff4d4b 100644 --- a/src/time/linux/gettimeofday.cpp +++ b/src/time/linux/gettimeofday.cpp @@ -7,24 +7,24 @@ //===----------------------------------------------------------------------===// #include "src/time/gettimeofday.h" - -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "hdr/time_macros.h" +#include "hdr/types/suseconds_t.h" #include "src/__support/common.h" +#include "src/__support/time/linux/clock_gettime.h" +#include "src/__support/time/units.h" #include "src/errno/libc_errno.h" -#include "src/time/linux/clockGetTimeImpl.h" - -#include <sys/syscall.h> // For syscall numbers. namespace LIBC_NAMESPACE { // TODO(michaelrj): Move this into time/linux with the other syscalls. LLVM_LIBC_FUNCTION(int, gettimeofday, (struct timeval * tv, [[maybe_unused]] void *unused)) { + using namespace time_units; if (tv == nullptr) return 0; struct timespec ts; - auto result = internal::clock_gettimeimpl(CLOCK_REALTIME, &ts); + auto result = internal::clock_gettime(CLOCK_REALTIME, &ts); // A negative return value indicates an error with the magnitude of the // value being the error code. @@ -34,7 +34,7 @@ LLVM_LIBC_FUNCTION(int, gettimeofday, } tv->tv_sec = ts.tv_sec; - tv->tv_usec = static_cast<suseconds_t>(ts.tv_nsec / 1000); + tv->tv_usec = static_cast<suseconds_t>(ts.tv_nsec / 1_us_ns); return 0; } diff --git a/src/time/linux/time.cpp b/src/time/linux/time.cpp index e286fae095b2..32f531efb6d1 100644 --- a/src/time/linux/time.cpp +++ b/src/time/linux/time.cpp @@ -6,22 +6,18 @@ // //===----------------------------------------------------------------------===// -#include "src/time/time_func.h" - -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "hdr/time_macros.h" #include "src/__support/common.h" +#include "src/__support/time/linux/clock_gettime.h" #include "src/errno/libc_errno.h" -#include "src/time/linux/clockGetTimeImpl.h" - -#include <sys/syscall.h> // For syscall numbers. -#include <time.h> +#include "src/time/time_func.h" namespace LIBC_NAMESPACE { LLVM_LIBC_FUNCTION(time_t, time, (time_t * tp)) { // TODO: Use the Linux VDSO to fetch the time and avoid the syscall. struct timespec ts; - auto result = internal::clock_gettimeimpl(CLOCK_REALTIME, &ts); + auto result = internal::clock_gettime(CLOCK_REALTIME, &ts); if (!result.has_value()) { libc_errno = result.error(); return -1; diff --git a/src/time/nanosleep.h b/src/time/nanosleep.h index 757394232c07..2309666b2304 100644 --- a/src/time/nanosleep.h +++ b/src/time/nanosleep.h @@ -9,11 +9,11 @@ #ifndef LLVM_LIBC_SRC_TIME_NANOSLEEP_H #define LLVM_LIBC_SRC_TIME_NANOSLEEP_H -#include <time.h> +#include "hdr/types/struct_timespec.h" namespace LIBC_NAMESPACE { -int nanosleep(const struct timespec *req, struct timespec *rem); +int nanosleep(const timespec *req, timespec *rem); } // namespace LIBC_NAMESPACE diff --git a/src/time/time_func.h b/src/time/time_func.h index beb02020b575..2a5239220942 100644 --- a/src/time/time_func.h +++ b/src/time/time_func.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_SRC_TIME_TIME_FUNC_H #define LLVM_LIBC_SRC_TIME_TIME_FUNC_H -#include <time.h> +#include "hdr/types/time_t.h" // Note this header file is named time_func.h to avoid conflicts with the // public header file time.h. diff --git a/test/UnitTest/FPMatcher.h b/test/UnitTest/FPMatcher.h index c58c322c981e..26af5cec02b5 100644 --- a/test/UnitTest/FPMatcher.h +++ b/test/UnitTest/FPMatcher.h @@ -159,18 +159,18 @@ template <typename T> struct FPTest : public Test { #define EXPECT_FP_EXCEPTION(expected) \ do { \ if (math_errhandling & MATH_ERREXCEPT) { \ - EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \ - (expected), \ - expected); \ + EXPECT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \ + ((expected) ? (expected) : FE_ALL_EXCEPT), \ + (expected)); \ } \ } while (0) #define ASSERT_FP_EXCEPTION(expected) \ do { \ if (math_errhandling & MATH_ERREXCEPT) { \ - ASSERT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \ - (expected), \ - expected); \ + ASSERT_EQ(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \ + ((expected) ? (expected) : FE_ALL_EXCEPT), \ + (expected)); \ } \ } while (0) @@ -178,24 +178,14 @@ template <typename T> struct FPTest : public Test { do { \ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \ EXPECT_FP_EQ(expected_val, actual_val); \ - if (math_errhandling & MATH_ERREXCEPT) { \ - EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \ - (expected_except), \ - expected_except); \ - LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \ - } \ + EXPECT_FP_EXCEPTION(expected_except); \ } while (0) #define EXPECT_FP_IS_NAN_WITH_EXCEPTION(actual_val, expected_except) \ do { \ LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \ EXPECT_FP_IS_NAN(actual_val); \ - if (math_errhandling & MATH_ERREXCEPT) { \ - EXPECT_GE(LIBC_NAMESPACE::fputil::test_except(FE_ALL_EXCEPT) & \ - (expected_except), \ - expected_except); \ - LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \ - } \ + EXPECT_FP_EXCEPTION(expected_except); \ } while (0) #define EXPECT_FP_EQ_ALL_ROUNDING(expected, actual) \ diff --git a/test/src/__support/CPP/mutex_test.cpp b/test/src/__support/CPP/mutex_test.cpp new file mode 100644 index 000000000000..a68c84cfc78a --- /dev/null +++ b/test/src/__support/CPP/mutex_test.cpp @@ -0,0 +1,79 @@ +//===-- Unittests for mutex -----------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/CPP/mutex.h" +#include "test/UnitTest/Test.h" + +using LIBC_NAMESPACE::cpp::adopt_lock; +using LIBC_NAMESPACE::cpp::lock_guard; + +// Simple struct for testing cpp::lock_guard. It defines methods 'lock' and +// 'unlock' which are required for the cpp::lock_guard class template. +struct Mutex { + // Flag to show whether this mutex is locked. + bool locked = false; + + // Flag to show if this mutex has been double locked. + bool double_locked = false; + + // Flag to show if this mutex has been double unlocked. + bool double_unlocked = false; + + Mutex() {} + + void lock() { + if (locked) + double_locked = true; + + locked = true; + } + + void unlock() { + if (!locked) + double_unlocked = true; + + locked = false; + } +}; + +TEST(LlvmLibcMutexTest, Basic) { + Mutex m; + ASSERT_FALSE(m.locked); + ASSERT_FALSE(m.double_locked); + ASSERT_FALSE(m.double_unlocked); + + { + lock_guard lg(m); + ASSERT_TRUE(m.locked); + ASSERT_FALSE(m.double_locked); + } + + ASSERT_FALSE(m.locked); + ASSERT_FALSE(m.double_unlocked); +} + +TEST(LlvmLibcMutexTest, AcquireLocked) { + Mutex m; + ASSERT_FALSE(m.locked); + ASSERT_FALSE(m.double_locked); + ASSERT_FALSE(m.double_unlocked); + + // Lock the mutex before placing a lock guard on it. + m.lock(); + ASSERT_TRUE(m.locked); + ASSERT_FALSE(m.double_locked); + + { + lock_guard lg(m, adopt_lock); + ASSERT_TRUE(m.locked); + ASSERT_FALSE(m.double_locked); + } + + ASSERT_FALSE(m.locked); + ASSERT_FALSE(m.double_unlocked); +} diff --git a/test/src/math/FModTest.h b/test/src/math/FModTest.h index f1015d6497fc..32c009ab8828 100644 --- a/test/src/math/FModTest.h +++ b/test/src/math/FModTest.h @@ -18,10 +18,10 @@ #include "hdr/math_macros.h" #define TEST_SPECIAL(x, y, expected, dom_err, expected_exception) \ + LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); \ EXPECT_FP_EQ(expected, f(x, y)); \ EXPECT_MATH_ERRNO((dom_err) ? EDOM : 0); \ - EXPECT_FP_EXCEPTION(expected_exception); \ - LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT) + EXPECT_FP_EXCEPTION(expected_exception) #define TEST_REGULAR(x, y, expected) TEST_SPECIAL(x, y, expected, false, 0) diff --git a/test/src/math/RoundToIntegerTest.h b/test/src/math/RoundToIntegerTest.h index 0f052ba42a46..d40e15080087 100644 --- a/test/src/math/RoundToIntegerTest.h +++ b/test/src/math/RoundToIntegerTest.h @@ -57,12 +57,13 @@ private: ASSERT_EQ(func(input), expected); + // TODO: Handle the !expectError case. It used to expect + // 0 for errno and exceptions, but this doesn't hold for + // all math functions using RoundToInteger test: + // https://github.com/llvm/llvm-project/pull/88816 if (expectError) { ASSERT_FP_EXCEPTION(FE_INVALID); ASSERT_MATH_ERRNO(EDOM); - } else { - ASSERT_FP_EXCEPTION(0); - ASSERT_MATH_ERRNO(0); } } diff --git a/test/src/math/atanf_test.cpp b/test/src/math/atanf_test.cpp index 4fa7badaf736..376b4724b5a3 100644 --- a/test/src/math/atanf_test.cpp +++ b/test/src/math/atanf_test.cpp @@ -21,21 +21,29 @@ using LlvmLibcAtanfTest = LIBC_NAMESPACE::testing::FPTest<float>; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; +// TODO: This test needs to have its checks for exceptions, errno +// tightened TEST_F(LlvmLibcAtanfTest, SpecialNumbers) { LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanf(aNaN)); - EXPECT_FP_EXCEPTION(0); + // TODO: Uncomment these checks later, RoundingMode affects running + // tests in this way https://github.com/llvm/llvm-project/issues/90653. + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanf(0.0f)); - EXPECT_FP_EXCEPTION(0); + // TODO: Uncomment these checks later, RoundingMode affects running + // tests in this way https://github.com/llvm/llvm-project/issues/90653. + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanf(-0.0f)); - EXPECT_FP_EXCEPTION(0); + // TODO: Uncomment these checks later, RoundingMode affects running + // tests in this way https://github.com/llvm/llvm-project/issues/90653. + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); } diff --git a/test/src/math/atanhf_test.cpp b/test/src/math/atanhf_test.cpp index 7fc8c70d1386..b0505e4c1182 100644 --- a/test/src/math/atanhf_test.cpp +++ b/test/src/math/atanhf_test.cpp @@ -21,32 +21,40 @@ using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest<float>; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; +// TODO: This test needs to have its checks for exceptions, errno +// tightened https://github.com/llvm/llvm-project/issues/88819. TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) { LIBC_NAMESPACE::libc_errno = 0; LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(aNaN)); - EXPECT_FP_EXCEPTION(0); + // TODO: Uncomment these checks later, RoundingMode affects running + // tests in this way https://github.com/llvm/llvm-project/issues/90653. + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanhf(0.0f)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanhf(-0.0f)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(inf, LIBC_NAMESPACE::atanhf(1.0f)); - EXPECT_FP_EXCEPTION(FE_DIVBYZERO); + // See above TODO + // EXPECT_FP_EXCEPTION(FE_DIVBYZERO); EXPECT_MATH_ERRNO(ERANGE); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(neg_inf, LIBC_NAMESPACE::atanhf(-1.0f)); - EXPECT_FP_EXCEPTION(FE_DIVBYZERO); + // See above TODO + // EXPECT_FP_EXCEPTION(FE_DIVBYZERO); EXPECT_MATH_ERRNO(ERANGE); auto bt = FPBits(1.0f); @@ -54,33 +62,37 @@ TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) { LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(bt.get_val())); - EXPECT_FP_EXCEPTION(FE_INVALID); + // EXPECT_FP_EXCEPTION(FE_INVALID); EXPECT_MATH_ERRNO(EDOM); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); bt.set_sign(Sign::NEG); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(bt.get_val())); - EXPECT_FP_EXCEPTION(FE_INVALID); + // See above TODO + // EXPECT_FP_EXCEPTION(FE_INVALID); EXPECT_MATH_ERRNO(EDOM); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(2.0f)); - EXPECT_FP_EXCEPTION(FE_INVALID); + // See above TODO + // EXPECT_FP_EXCEPTION(FE_INVALID); EXPECT_MATH_ERRNO(EDOM); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(-2.0f)); - EXPECT_FP_EXCEPTION(FE_INVALID); + // EXPECT_FP_EXCEPTION(FE_INVALID); EXPECT_MATH_ERRNO(EDOM); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(inf)); - EXPECT_FP_EXCEPTION(FE_INVALID); + // See above TODO + // EXPECT_FP_EXCEPTION(FE_INVALID); EXPECT_MATH_ERRNO(EDOM); bt.set_sign(Sign::NEG); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(neg_inf)); - EXPECT_FP_EXCEPTION(FE_INVALID); + // See above TODO + // EXPECT_FP_EXCEPTION(FE_INVALID); EXPECT_MATH_ERRNO(EDOM); } diff --git a/test/src/math/powf_test.cpp b/test/src/math/powf_test.cpp index 69135593cd32..797913e5b7ee 100644 --- a/test/src/math/powf_test.cpp +++ b/test/src/math/powf_test.cpp @@ -22,14 +22,21 @@ using LIBC_NAMESPACE::testing::tlog; namespace mpfr = LIBC_NAMESPACE::testing::mpfr; TEST_F(LlvmLibcPowfTest, TrickyInputs) { - constexpr int N = 11; + constexpr int N = 13; constexpr mpfr::BinaryInput<float> INPUTS[N] = { - {0x1.290bbp-124f, 0x1.1e6d92p-25f}, {0x1.2e9fb6p+5f, -0x1.1b82b6p-18f}, - {0x1.6877f6p+60f, -0x1.75f1c6p-4f}, {0x1.0936acp-63f, -0x1.55200ep-15f}, - {0x1.d6d72ap+43f, -0x1.749ccap-5f}, {0x1.4afb2ap-40f, 0x1.063198p+0f}, - {0x1.0124dep+0f, -0x1.fdb016p+9f}, {0x1.1058p+0f, 0x1.ap+64f}, - {0x1.1058p+0f, -0x1.ap+64f}, {0x1.1058p+0f, 0x1.ap+64f}, + {0x1.290bbp-124f, 0x1.1e6d92p-25f}, + {0x1.2e9fb6p+5f, -0x1.1b82b6p-18f}, + {0x1.6877f6p+60f, -0x1.75f1c6p-4f}, + {0x1.0936acp-63f, -0x1.55200ep-15f}, + {0x1.d6d72ap+43f, -0x1.749ccap-5f}, + {0x1.4afb2ap-40f, 0x1.063198p+0f}, + {0x1.0124dep+0f, -0x1.fdb016p+9f}, + {0x1.1058p+0f, 0x1.ap+64f}, + {0x1.1058p+0f, -0x1.ap+64f}, + {0x1.1058p+0f, 0x1.ap+64f}, {0x1.fa32d4p-1f, 0x1.67a62ep+12f}, + {-0x1.8p-49, 0x1.8p+1}, + {0x1.8p-48, 0x1.8p+1}, }; for (int i = 0; i < N; ++i) { diff --git a/test/src/math/smoke/NextAfterTest.h b/test/src/math/smoke/NextAfterTest.h index 65dba9338285..d65ccdf8e70c 100644 --- a/test/src/math/smoke/NextAfterTest.h +++ b/test/src/math/smoke/NextAfterTest.h @@ -18,6 +18,8 @@ #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" +// TODO: Strengthen errno,exception checks and remove these assert macros +// after new matchers/test fixtures are added #define ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, expected_exception) \ ASSERT_FP_EQ(result, expected); \ ASSERT_FP_EXCEPTION(expected_exception); \ diff --git a/test/src/math/smoke/NextTowardTest.h b/test/src/math/smoke/NextTowardTest.h index 1894d324b085..a24ec9ff6bd8 100644 --- a/test/src/math/smoke/NextTowardTest.h +++ b/test/src/math/smoke/NextTowardTest.h @@ -19,6 +19,8 @@ #include "test/UnitTest/FPMatcher.h" #include "test/UnitTest/Test.h" +// TODO: Strengthen errno,exception checks and remove these assert macros +// after new matchers/test fixtures are added #define ASSERT_FP_EQ_WITH_EXCEPTION(result, expected, expected_exception) \ ASSERT_FP_EQ(result, expected); \ ASSERT_FP_EXCEPTION(expected_exception); \ diff --git a/test/src/math/smoke/RoundToIntegerTest.h b/test/src/math/smoke/RoundToIntegerTest.h index 50bcd4a6a76c..3ff311f46b05 100644 --- a/test/src/math/smoke/RoundToIntegerTest.h +++ b/test/src/math/smoke/RoundToIntegerTest.h @@ -28,14 +28,7 @@ public: typedef I (*RoundToIntegerFunc)(F); private: - using FPBits = LIBC_NAMESPACE::fputil::FPBits<F>; - using StorageType = typename FPBits::StorageType; - - const F zero = FPBits::zero(Sign::POS).get_val(); - const F neg_zero = FPBits::zero(Sign::NEG).get_val(); - const F inf = FPBits::inf(Sign::POS).get_val(); - const F neg_inf = FPBits::inf(Sign::NEG).get_val(); - const F nan = FPBits::quiet_nan().get_val(); + DECLARE_SPECIAL_CONSTANTS(F) static constexpr StorageType MAX_SUBNORMAL = FPBits::max_subnormal().uintval(); @@ -52,12 +45,13 @@ private: ASSERT_EQ(func(input), expected); + // TODO: Handle the !expectError case. It used to expect + // 0 for errno and exceptions, but this doesn't hold for + // all math functions using RoundToInteger test: + // https://github.com/llvm/llvm-project/pull/88816 if (expectError) { ASSERT_FP_EXCEPTION(FE_INVALID); ASSERT_MATH_ERRNO(EDOM); - } else { - ASSERT_FP_EXCEPTION(0); - ASSERT_MATH_ERRNO(0); } } @@ -81,7 +75,7 @@ public: // libc/CMakeLists.txt is not forwarded to C++. #if LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR // Result is not well-defined, we always returns INTEGER_MAX - test_one_input(func, nan, INTEGER_MAX, true); + test_one_input(func, aNaN, INTEGER_MAX, true); #endif // LIBC_COPT_IMPLEMENTATION_DEFINED_TEST_BEHAVIOR } diff --git a/test/src/math/smoke/atan2f_test.cpp b/test/src/math/smoke/atan2f_test.cpp index f81d140fefc5..32a28cfdfeaa 100644 --- a/test/src/math/smoke/atan2f_test.cpp +++ b/test/src/math/smoke/atan2f_test.cpp @@ -18,33 +18,43 @@ using LlvmLibcAtan2fTest = LIBC_NAMESPACE::testing::FPTest<float>; TEST_F(LlvmLibcAtan2fTest, SpecialNumbers) { LIBC_NAMESPACE::libc_errno = 0; + // TODO: Strengthen errno,exception checks and remove these assert macros + // after new matchers/test fixtures are added see: + // https://github.com/llvm/llvm-project/issues/90653. LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atan2f(aNaN, zero)); - EXPECT_FP_EXCEPTION(0); + // TODO: Uncomment these checks later, RoundingMode affects running + // tests in this way https://github.com/llvm/llvm-project/issues/90653. + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atan2f(1.0f, aNaN)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atan2f(zero, zero)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atan2f(-0.0f, zero)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atan2f(1.0f, inf)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atan2f(-1.0f, inf)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); } diff --git a/test/src/math/smoke/atanf_test.cpp b/test/src/math/smoke/atanf_test.cpp index 3800c2334b92..56bf2f951b33 100644 --- a/test/src/math/smoke/atanf_test.cpp +++ b/test/src/math/smoke/atanf_test.cpp @@ -21,18 +21,25 @@ using LlvmLibcAtanfTest = LIBC_NAMESPACE::testing::FPTest<float>; TEST_F(LlvmLibcAtanfTest, SpecialNumbers) { LIBC_NAMESPACE::libc_errno = 0; + // TODO: Strengthen errno,exception checks and remove these assert macros + // after new matchers/test fixtures are added + // https://github.com/llvm/llvm-project/issues/90653 LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanf(aNaN)); - EXPECT_FP_EXCEPTION(0); + // TODO: Uncomment these checks later, RoundingMode affects running + // tests in this way https://github.com/llvm/llvm-project/issues/90653. + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanf(0.0f)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanf(-0.0f)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); } diff --git a/test/src/math/smoke/atanhf_test.cpp b/test/src/math/smoke/atanhf_test.cpp index fc3e2dd9bc54..2d2acfeeab4e 100644 --- a/test/src/math/smoke/atanhf_test.cpp +++ b/test/src/math/smoke/atanhf_test.cpp @@ -19,22 +19,28 @@ using LlvmLibcAtanhfTest = LIBC_NAMESPACE::testing::FPTest<float>; TEST_F(LlvmLibcAtanhfTest, SpecialNumbers) { - LIBC_NAMESPACE::libc_errno = 0; + // TODO: Strengthen errno,exception checks and remove these assert macros + // after new matchers/test fixtures are added, see: + // https://github.com/llvm/llvm-project/issues/90653 LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(aNaN, LIBC_NAMESPACE::atanhf(aNaN)); - EXPECT_FP_EXCEPTION(0); + // TODO: Uncomment these checks later, RoundingMode affects running + // tests in this way https://github.com/llvm/llvm-project/issues/90653. + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(0.0f, LIBC_NAMESPACE::atanhf(0.0f)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); LIBC_NAMESPACE::fputil::clear_except(FE_ALL_EXCEPT); EXPECT_FP_EQ_ALL_ROUNDING(-0.0f, LIBC_NAMESPACE::atanhf(-0.0f)); - EXPECT_FP_EXCEPTION(0); + // See above TODO + // EXPECT_FP_EXCEPTION(0); EXPECT_MATH_ERRNO(0); EXPECT_FP_EQ_WITH_EXCEPTION(inf, LIBC_NAMESPACE::atanhf(1.0f), FE_DIVBYZERO); |