diff --git a/libc/config/baremetal/arm/entrypoints.txt b/libc/config/baremetal/arm/entrypoints.txt index 511d9d22f1450..e9a2c7fc77bbe 100644 --- a/libc/config/baremetal/arm/entrypoints.txt +++ b/libc/config/baremetal/arm/entrypoints.txt @@ -537,6 +537,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT) libc.src.stdfix.countlsuhk libc.src.stdfix.countlsuk libc.src.stdfix.countlsulk + libc.src.stdfix.idivr + libc.src.stdfix.idivlr + libc.src.stdfix.idivk + libc.src.stdfix.idivlk + libc.src.stdfix.idivur + libc.src.stdfix.idivulr + libc.src.stdfix.idivuk + libc.src.stdfix.idivulk ) endif() diff --git a/libc/config/baremetal/riscv/entrypoints.txt b/libc/config/baremetal/riscv/entrypoints.txt index bbefb75ee16b5..9a3db5ffad000 100644 --- a/libc/config/baremetal/riscv/entrypoints.txt +++ b/libc/config/baremetal/riscv/entrypoints.txt @@ -532,6 +532,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT) libc.src.stdfix.countlsuhk libc.src.stdfix.countlsuk libc.src.stdfix.countlsulk + libc.src.stdfix.idivr + libc.src.stdfix.idivlr + libc.src.stdfix.idivk + libc.src.stdfix.idivlk + libc.src.stdfix.idivur + libc.src.stdfix.idivulr + libc.src.stdfix.idivuk + libc.src.stdfix.idivulk ) endif() diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt index 9cf05ef6d5a61..b2aa3300d0f67 100644 --- a/libc/config/linux/riscv/entrypoints.txt +++ b/libc/config/linux/riscv/entrypoints.txt @@ -773,6 +773,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT) libc.src.stdfix.countlsuhk libc.src.stdfix.countlsuk libc.src.stdfix.countlsulk + libc.src.stdfix.idivr + libc.src.stdfix.idivlr + libc.src.stdfix.idivk + libc.src.stdfix.idivulk + libc.src.stdfix.idivur + libc.src.stdfix.idivulr + libc.src.stdfix.idivuk + libc.src.stdfix.idivulk ) endif() diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt index 124b80d03d846..a387f62fe009e 100644 --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -905,6 +905,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT) libc.src.stdfix.countlsuhk libc.src.stdfix.countlsuk libc.src.stdfix.countlsulk + libc.src.stdfix.idivr + libc.src.stdfix.idivlr + libc.src.stdfix.idivk + libc.src.stdfix.idivlk + libc.src.stdfix.idivur + libc.src.stdfix.idivulr + libc.src.stdfix.idivuk + libc.src.stdfix.idivulk ) endif() diff --git a/libc/docs/headers/stdfix.rst b/libc/docs/headers/stdfix.rst index 20f68b4a1ed35..a2f5e94774798 100644 --- a/libc/docs/headers/stdfix.rst +++ b/libc/docs/headers/stdfix.rst @@ -77,7 +77,7 @@ The following functions are included in the ISO/IEC TR 18037:2008 standard. +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+ | divi\* | | | | | | | | | | | | | +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+ -| idiv\* | | | | | | | | | | | | | +| idiv\* | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+ | muli | | | | | | | | | | | | | +---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+ diff --git a/libc/include/stdfix.yaml b/libc/include/stdfix.yaml index 29c4d8b5c8960..5b385124eb63d 100644 --- a/libc/include/stdfix.yaml +++ b/libc/include/stdfix.yaml @@ -238,6 +238,70 @@ functions: arguments: - type: unsigned long accum guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivr + standards: + - stdc_ext + return_type: int + arguments: + - type: fract + - type: fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivlr + standards: + - stdc_ext + return_type: long int + arguments: + - type: long fract + - type: long fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivk + standards: + - stdc_ext + return_type: int + arguments: + - type: accum + - type: accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivlk + standards: + - stdc_ext + return_type: long int + arguments: + - type: long accum + - type: long accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivur + standards: + - stdc_ext + return_type: unsigned int + arguments: + - type: unsigned fract + - type: unsigned fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivulr + standards: + - stdc_ext + return_type: unsigned long int + arguments: + - type: unsigned long fract + - type: unsigned long fract + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivuk + standards: + - stdc_ext + return_type: unsigned int + arguments: + - type: unsigned accum + - type: unsigned accum + guard: LIBC_COMPILER_HAS_FIXED_POINT + - name: idivulk + standards: + - stdc_ext + return_type: unsigned long int + arguments: + - type: unsigned long accum + - type: unsigned long accum + guard: LIBC_COMPILER_HAS_FIXED_POINT - name: roundhk standards: - stdc_ext diff --git a/libc/src/__support/fixed_point/CMakeLists.txt b/libc/src/__support/fixed_point/CMakeLists.txt index b415e2c00c488..235c03048cfa4 100644 --- a/libc/src/__support/fixed_point/CMakeLists.txt +++ b/libc/src/__support/fixed_point/CMakeLists.txt @@ -16,6 +16,7 @@ add_header_library( .fx_rep libc.include.llvm-libc-macros.stdfix_macros libc.src.__support.macros.attributes + libc.src.__support.macros.null_check libc.src.__support.macros.optimization libc.src.__support.CPP.type_traits libc.src.__support.CPP.bit diff --git a/libc/src/__support/fixed_point/fx_bits.h b/libc/src/__support/fixed_point/fx_bits.h index b05f46bd34660..00c6119b4f353 100644 --- a/libc/src/__support/fixed_point/fx_bits.h +++ b/libc/src/__support/fixed_point/fx_bits.h @@ -15,6 +15,7 @@ #include "src/__support/CPP/type_traits.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE #include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL +#include "src/__support/macros/null_check.h" // LIBC_CRASH_ON_VALUE #include "src/__support/macros/optimization.h" // LIBC_UNLIKELY #include "src/__support/math_extras.h" @@ -201,6 +202,28 @@ bitsfx(T f) { return cpp::bit_cast(f); } +// divide the two fixed-point types and return an integer result +template +LIBC_INLINE constexpr cpp::enable_if_t, XType> +idiv(T x, T y) { + using FXBits = FXBits; + using FXRep = FXRep; + using CompType = typename FXRep::CompType; + + // If the value of the second operand of the / operator is zero, the + // behavior is undefined. Ref: ISO/IEC TR 18037:2008(E) p.g. 16 + LIBC_CRASH_ON_VALUE(y, FXRep::ZERO()); + + CompType x_comp = static_cast(FXBits(x).get_bits()); + CompType y_comp = static_cast(FXBits(y).get_bits()); + + // If an integer result of one of these functions overflows, the behavior is + // undefined. Ref: ISO/IEC TR 18037:2008(E) p.g. 16 + CompType result = x_comp / y_comp; + + return static_cast(result); +} + } // namespace fixed_point } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/macros/null_check.h b/libc/src/__support/macros/null_check.h index eda19f889235e..abf65c56c404b 100644 --- a/libc/src/__support/macros/null_check.h +++ b/libc/src/__support/macros/null_check.h @@ -19,10 +19,19 @@ if (LIBC_UNLIKELY((ptr) == nullptr)) \ __builtin_trap(); \ } while (0) +#define LIBC_CRASH_ON_VALUE(var, value) \ + do { \ + if (LIBC_UNLIKELY((var) == (value))) \ + __builtin_trap(); \ + } while (0) + #else #define LIBC_CRASH_ON_NULLPTR(ptr) \ do { \ } while (0) +#define LIBC_CRASH_ON_VALUE(var, value) \ + do { \ + } while (0) #endif #endif // LLVM_LIBC_SRC___SUPPORT_MACROS_NULL_CHECK_H diff --git a/libc/src/stdfix/CMakeLists.txt b/libc/src/stdfix/CMakeLists.txt index 362af0bf0d55c..843111e3f80b1 100644 --- a/libc/src/stdfix/CMakeLists.txt +++ b/libc/src/stdfix/CMakeLists.txt @@ -75,6 +75,20 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk) ) endforeach() +foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk) + add_entrypoint_object( + idiv${suffix} + HDRS + idiv${suffix}.h + SRCS + idiv${suffix}.cpp + COMPILE_OPTIONS + ${libc_opt_high_flag} + DEPENDS + libc.src.__support.fixed_point.fx_bits + ) +endforeach() + add_entrypoint_object( uhksqrtus HDRS diff --git a/libc/src/stdfix/idivk.cpp b/libc/src/stdfix/idivk.cpp new file mode 100644 index 0000000000000..d1d758dc56995 --- /dev/null +++ b/libc/src/stdfix/idivk.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of idivk function ---------------------------------===// +// +// 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 "idivk.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // accum +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, idivk, (accum x, accum y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivk.h b/libc/src/stdfix/idivk.h new file mode 100644 index 0000000000000..a84bd0da2d533 --- /dev/null +++ b/libc/src/stdfix/idivk.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivk ------------------------*- 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_STDFIX_IDIVK_H +#define LLVM_LIBC_SRC_STDFIX_IDIVK_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // accum +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +int idivk(accum x, accum y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVK_H diff --git a/libc/src/stdfix/idivlk.cpp b/libc/src/stdfix/idivlk.cpp new file mode 100644 index 0000000000000..36e1df6cc58fb --- /dev/null +++ b/libc/src/stdfix/idivlk.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of idivlk function --------------------------------===// +// +// 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 "idivlk.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // long accum +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(long int, idivlk, (long accum x, long accum y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivlk.h b/libc/src/stdfix/idivlk.h new file mode 100644 index 0000000000000..274a61a9d82c3 --- /dev/null +++ b/libc/src/stdfix/idivlk.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivlk -----------------------*- 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_STDFIX_IDIVLK_H +#define LLVM_LIBC_SRC_STDFIX_IDIVLK_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // long accum +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +long int idivlk(long accum x, long accum y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVLK_H diff --git a/libc/src/stdfix/idivlr.cpp b/libc/src/stdfix/idivlr.cpp new file mode 100644 index 0000000000000..1c9d62d196a29 --- /dev/null +++ b/libc/src/stdfix/idivlr.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of idivlr function --------------------------------===// +// +// 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 "idivlr.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // long fract +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(long int, idivlr, (long fract x, long fract y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivlr.h b/libc/src/stdfix/idivlr.h new file mode 100644 index 0000000000000..de36035f289a4 --- /dev/null +++ b/libc/src/stdfix/idivlr.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivlr -----------------------*- 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_STDFIX_IDIVLR_H +#define LLVM_LIBC_SRC_STDFIX_IDIVLR_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // long fract +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +long int idivlr(long fract x, long fract y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVLR_H diff --git a/libc/src/stdfix/idivr.cpp b/libc/src/stdfix/idivr.cpp new file mode 100644 index 0000000000000..80dd1b2107272 --- /dev/null +++ b/libc/src/stdfix/idivr.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of idivr function ---------------------------------===// +// +// 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 "idivr.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // fract +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, idivr, (fract x, fract y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivr.h b/libc/src/stdfix/idivr.h new file mode 100644 index 0000000000000..f3a95e2d516c3 --- /dev/null +++ b/libc/src/stdfix/idivr.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivr ------------------------*- 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_STDFIX_IDIVR_H +#define LLVM_LIBC_SRC_STDFIX_IDIVR_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // fract +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +int idivr(fract x, fract y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVR_H diff --git a/libc/src/stdfix/idivuk.cpp b/libc/src/stdfix/idivuk.cpp new file mode 100644 index 0000000000000..27bf8edd80927 --- /dev/null +++ b/libc/src/stdfix/idivuk.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of idivuk function --------------------------------===// +// +// 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 "idivuk.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned accum +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(unsigned int, idivuk, (unsigned accum x, unsigned accum y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivuk.h b/libc/src/stdfix/idivuk.h new file mode 100644 index 0000000000000..a8dce0a0b4c8b --- /dev/null +++ b/libc/src/stdfix/idivuk.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivuk ------------------------*- 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_STDFIX_IDIVUK_H +#define LLVM_LIBC_SRC_STDFIX_IDIVUK_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned accum +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +unsigned int idivuk(unsigned accum x, unsigned accum y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVUK_H diff --git a/libc/src/stdfix/idivulk.cpp b/libc/src/stdfix/idivulk.cpp new file mode 100644 index 0000000000000..8b4e63c1b78fb --- /dev/null +++ b/libc/src/stdfix/idivulk.cpp @@ -0,0 +1,22 @@ +//===-- Implementation of idivulk function -------------------------------===// +// +// 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 "idivulk.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long accum +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(unsigned long int, idivulk, + (unsigned long accum x, unsigned long accum y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivulk.h b/libc/src/stdfix/idivulk.h new file mode 100644 index 0000000000000..b463e76b98f5e --- /dev/null +++ b/libc/src/stdfix/idivulk.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivlk -----------------------*- 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_STDFIX_IDIVULK_H +#define LLVM_LIBC_SRC_STDFIX_IDIVULK_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long accum +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +unsigned long int idivulk(unsigned long accum x, unsigned long accum y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVULK_H diff --git a/libc/src/stdfix/idivulr.cpp b/libc/src/stdfix/idivulr.cpp new file mode 100644 index 0000000000000..6e6a780c1b8c5 --- /dev/null +++ b/libc/src/stdfix/idivulr.cpp @@ -0,0 +1,22 @@ +//===-- Implementation of idivulr function --------------------------------===// +// +// 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 "idivulr.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long fract +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(unsigned long int, idivulr, + (unsigned long fract x, unsigned long fract y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivulr.h b/libc/src/stdfix/idivulr.h new file mode 100644 index 0000000000000..c2f6a1911bd37 --- /dev/null +++ b/libc/src/stdfix/idivulr.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivulr ----------------------*- 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_STDFIX_IDIVULR_H +#define LLVM_LIBC_SRC_STDFIX_IDIVULR_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned long fract +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +unsigned long int idivulr(unsigned long fract x, unsigned long fract y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVULR_H diff --git a/libc/src/stdfix/idivur.cpp b/libc/src/stdfix/idivur.cpp new file mode 100644 index 0000000000000..319817b9662d3 --- /dev/null +++ b/libc/src/stdfix/idivur.cpp @@ -0,0 +1,21 @@ +//===-- Implementation of idivur function --------------------------------===// +// +// 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 "idivur.h" +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned fract +#include "src/__support/common.h" // LLVM_LIBC_FUNCTION +#include "src/__support/fixed_point/fx_bits.h" // fixed_point +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(unsigned int, idivur, (unsigned fract x, unsigned fract y)) { + return fixed_point::idiv(x, y); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdfix/idivur.h b/libc/src/stdfix/idivur.h new file mode 100644 index 0000000000000..f69db20bcf512 --- /dev/null +++ b/libc/src/stdfix/idivur.h @@ -0,0 +1,21 @@ +//===-- Implementation header for idivur -----------------------*- 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_STDFIX_IDIVUR_H +#define LLVM_LIBC_SRC_STDFIX_IDIVUR_H + +#include "include/llvm-libc-macros/stdfix-macros.h" // unsigned fract +#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL + +namespace LIBC_NAMESPACE_DECL { + +unsigned int idivur(unsigned fract x, unsigned fract y); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_STDFIX_IDIVUR_H diff --git a/libc/test/src/stdfix/CMakeLists.txt b/libc/test/src/stdfix/CMakeLists.txt index a3dc25762f549..e2b4bc1805f7c 100644 --- a/libc/test/src/stdfix/CMakeLists.txt +++ b/libc/test/src/stdfix/CMakeLists.txt @@ -104,6 +104,22 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk) ) endforeach() +foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk) + add_libc_test( + idiv${suffix}_test + SUITE + libc-stdfix-tests + HDRS + IdivTest.h + SRCS + idiv${suffix}_test.cpp + DEPENDS + libc.src.stdfix.idiv${suffix} + libc.src.__support.fixed_point.fx_bits + libc.hdr.signal_macros + ) +endforeach() + add_libc_test( uhksqrtus_test SUITE diff --git a/libc/test/src/stdfix/IdivTest.h b/libc/test/src/stdfix/IdivTest.h new file mode 100644 index 0000000000000..6bfe9dff01a39 --- /dev/null +++ b/libc/test/src/stdfix/IdivTest.h @@ -0,0 +1,91 @@ +//===-- Utility class to test idivfx functions ------------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "test/UnitTest/Test.h" + +#include "src/__support/fixed_point/fx_rep.h" +#include "src/__support/macros/sanitizer.h" + +#include "hdr/signal_macros.h" + +template +class IdivTest : public LIBC_NAMESPACE::testing::Test { + + using FXRep = LIBC_NAMESPACE::fixed_point::FXRep; + + static constexpr T zero = FXRep::ZERO(); + static constexpr T max = FXRep::MAX(); + static constexpr T min = FXRep::MIN(); + static constexpr T one_half = FXRep::ONE_HALF(); + static constexpr T one_fourth = FXRep::ONE_FOURTH(); + +public: + typedef XType (*IdivFunc)(T, T); + + void testSpecialNumbers(IdivFunc func) { + constexpr bool is_signed = (FXRep::SIGN_LEN > 0); + constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0); + + EXPECT_EQ(func(one_half, one_fourth), static_cast(2)); + EXPECT_EQ(func(one_half, one_half), static_cast(1)); + EXPECT_EQ(func(one_fourth, one_half), static_cast(0)); + EXPECT_EQ(func(0.75, 0.25), static_cast(3)); + EXPECT_EQ(func(0.625, 0.125), static_cast(5)); + + if constexpr (is_signed) { + EXPECT_EQ(func(min, one_half), static_cast(min) * 2); + } else { + EXPECT_EQ(func(min, one_half), static_cast(0)); + } + + if constexpr (has_integral && min <= 7 && max >= 5) { + EXPECT_EQ(func(6.9, 4.2), static_cast(1)); + EXPECT_EQ(func(4.2, 6.9), static_cast(0)); + EXPECT_EQ(func(4.5, 2.2), static_cast(2)); + EXPECT_EQ(func(2.2, 1.1), static_cast(2)); + EXPECT_EQ(func(2.25, 1.0), static_cast(2)); + EXPECT_EQ(func(2.25, 3.0), static_cast(0)); + + if constexpr (is_signed) { + EXPECT_EQ(func(4.2, -6.9), static_cast(0)); + EXPECT_EQ(func(-6.9, 4.2), static_cast(-1)); + EXPECT_EQ(func(-2.5, 1.25), static_cast(-2)); + EXPECT_EQ(func(-2.25, 1.0), static_cast(-2)); + EXPECT_EQ(func(2.25, -3.0), static_cast(0)); + } + } + } + + void testInvalidNumbers(IdivFunc func) { + constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0); + + EXPECT_DEATH([func] { func(0.5, 0.0); }, WITH_SIGNAL(SIGILL)); + if constexpr (has_integral) { + EXPECT_DEATH([func] { func(2.5, 0.0); }, WITH_SIGNAL(SIGSEGV)); + } + } +}; + +#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER) +#define LIST_IDIV_TESTS(Name, T, XTYpe, func) \ + using LlvmLibcIdiv##Name##Test = IdivTest; \ + TEST_F(LlvmLibcIdiv##Name##Test, InvalidNumbers) { \ + testInvalidNumbers(&func); \ + } \ + TEST_F(LlvmLibcIdiv##Name##Test, SpecialNumbers) { \ + testSpecialNumbers(&func); \ + } \ + static_assert(true, "Require semicolon.") +#else +#define LIST_IDIV_TESTS(Name, T, XType, func) \ + using LlvmLibcIdiv##Name##Test = IdivTest; \ + TEST_F(LlvmLibcIdiv##Name##Test, SpecialNumbers) { \ + testSpecialNumbers(&func); \ + } \ + static_assert(true, "Require semicolon.") +#endif // LIBC_HAS_ADDRESS_SANITIZER diff --git a/libc/test/src/stdfix/idivk_test.cpp b/libc/test/src/stdfix/idivk_test.cpp new file mode 100644 index 0000000000000..b10a43ed6135a --- /dev/null +++ b/libc/test/src/stdfix/idivk_test.cpp @@ -0,0 +1,14 @@ +//===-- Unittests for idivk -----------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // accum +#include "src/stdfix/idivk.h" + +LIST_IDIV_TESTS(k, accum, int, LIBC_NAMESPACE::idivk); diff --git a/libc/test/src/stdfix/idivlk_test.cpp b/libc/test/src/stdfix/idivlk_test.cpp new file mode 100644 index 0000000000000..dcd4ccbcc4a78 --- /dev/null +++ b/libc/test/src/stdfix/idivlk_test.cpp @@ -0,0 +1,14 @@ +//===-- Unittests for idivlk ----------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // long accum +#include "src/stdfix/idivlk.h" + +LIST_IDIV_TESTS(lk, long accum, long int, LIBC_NAMESPACE::idivlk); diff --git a/libc/test/src/stdfix/idivlr_test.cpp b/libc/test/src/stdfix/idivlr_test.cpp new file mode 100644 index 0000000000000..0fdb1e3a19e8f --- /dev/null +++ b/libc/test/src/stdfix/idivlr_test.cpp @@ -0,0 +1,14 @@ +//===-- Unittests for idivlr ----------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // long fract +#include "src/stdfix/idivlr.h" + +LIST_IDIV_TESTS(lr, long fract, long int, LIBC_NAMESPACE::idivlr); diff --git a/libc/test/src/stdfix/idivr_test.cpp b/libc/test/src/stdfix/idivr_test.cpp new file mode 100644 index 0000000000000..82bec5c7be069 --- /dev/null +++ b/libc/test/src/stdfix/idivr_test.cpp @@ -0,0 +1,14 @@ +//===-- Unittests for idivr -----------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // fract +#include "src/stdfix/idivr.h" + +LIST_IDIV_TESTS(r, fract, int, LIBC_NAMESPACE::idivr); diff --git a/libc/test/src/stdfix/idivuk_test.cpp b/libc/test/src/stdfix/idivuk_test.cpp new file mode 100644 index 0000000000000..2bfd93da3ed4a --- /dev/null +++ b/libc/test/src/stdfix/idivuk_test.cpp @@ -0,0 +1,14 @@ +//===-- Unittests for idivuk ----------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // unsigned accum +#include "src/stdfix/idivuk.h" + +LIST_IDIV_TESTS(uk, unsigned accum, unsigned int, LIBC_NAMESPACE::idivuk); diff --git a/libc/test/src/stdfix/idivulk_test.cpp b/libc/test/src/stdfix/idivulk_test.cpp new file mode 100644 index 0000000000000..31eb96114a0ce --- /dev/null +++ b/libc/test/src/stdfix/idivulk_test.cpp @@ -0,0 +1,15 @@ +//===-- Unittests for idivulk ---------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // unsigned long accum +#include "src/stdfix/idivulk.h" + +LIST_IDIV_TESTS(ulk, unsigned long accum, unsigned long int, + LIBC_NAMESPACE::idivulk); diff --git a/libc/test/src/stdfix/idivulr_test.cpp b/libc/test/src/stdfix/idivulr_test.cpp new file mode 100644 index 0000000000000..6f43df149a127 --- /dev/null +++ b/libc/test/src/stdfix/idivulr_test.cpp @@ -0,0 +1,15 @@ +//===-- Unittests for idivulr ---------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // unsigned long fract +#include "src/stdfix/idivulr.h" + +LIST_IDIV_TESTS(ulr, unsigned long fract, unsigned long int, + LIBC_NAMESPACE::idivulr); diff --git a/libc/test/src/stdfix/idivur_test.cpp b/libc/test/src/stdfix/idivur_test.cpp new file mode 100644 index 0000000000000..c2d2f9caf19d9 --- /dev/null +++ b/libc/test/src/stdfix/idivur_test.cpp @@ -0,0 +1,14 @@ +//===-- Unittests for idivur ----------------------------------------------===// +// +// 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 "IdivTest.h" + +#include "llvm-libc-macros/stdfix-macros.h" // unsigned fract +#include "src/stdfix/idivur.h" + +LIST_IDIV_TESTS(ur, unsigned fract, unsigned int, LIBC_NAMESPACE::idivur);