[libc][stdfix] Implement divifx functions in LLVM libc (#206115)

Fixes #129124
This commit is contained in:
sohail 2026-07-16 09:54:19 +05:30 committed by GitHub
parent bedbc79101
commit 48607d2984
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
36 changed files with 808 additions and 1 deletions

View file

@ -974,6 +974,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivulr
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.divir
libc.src.stdfix.divilr
libc.src.stdfix.divik
libc.src.stdfix.divilk
libc.src.stdfix.diviur
libc.src.stdfix.diviulr
libc.src.stdfix.diviuk
libc.src.stdfix.diviulk
)
endif()

View file

@ -971,6 +971,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivulr
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.divir
libc.src.stdfix.divilr
libc.src.stdfix.divik
libc.src.stdfix.divilk
libc.src.stdfix.diviur
libc.src.stdfix.diviulr
libc.src.stdfix.diviuk
libc.src.stdfix.diviulk
)
endif()

View file

@ -1188,6 +1188,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.rdivi
libc.src.stdfix.divir
libc.src.stdfix.divilr
libc.src.stdfix.divik
libc.src.stdfix.divilk
libc.src.stdfix.diviur
libc.src.stdfix.diviulr
libc.src.stdfix.diviuk
libc.src.stdfix.diviulk
)
endif()

View file

@ -1193,6 +1193,14 @@ if(LIBC_COMPILER_HAS_FIXED_POINT)
libc.src.stdfix.idivuk
libc.src.stdfix.idivulk
libc.src.stdfix.rdivi
libc.src.stdfix.divir
libc.src.stdfix.divilr
libc.src.stdfix.divik
libc.src.stdfix.divilk
libc.src.stdfix.diviur
libc.src.stdfix.diviulr
libc.src.stdfix.diviuk
libc.src.stdfix.diviulk
)
endif()

View file

@ -73,7 +73,7 @@ The following functions are included in the ISO/IEC TR 18037:2008 standard.
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| countls | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| | |check| |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| divi\* | | | | | | | | | | | | |
| divi\* | | | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | |check| |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+
| idiv\* | | | |check| | |check| | |check| | |check| | | | |check| | |check| | |check| | |check| |
+---------------+----------------+-------------+---------------+------------+----------------+-------------+----------------+-------------+---------------+------------+----------------+-------------+

View file

@ -565,3 +565,67 @@ functions:
- type: int
- type: int
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: divir
standards:
- stdc_ext
return_type: int
arguments:
- type: int
- type: fract
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: divilr
standards:
- stdc_ext
return_type: long int
arguments:
- type: long int
- type: long fract
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: divik
standards:
- stdc_ext
return_type: int
arguments:
- type: int
- type: accum
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: divilk
standards:
- stdc_ext
return_type: long int
arguments:
- type: long int
- type: long accum
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: diviur
standards:
- stdc_ext
return_type: unsigned int
arguments:
- type: unsigned int
- type: unsigned fract
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: diviulr
standards:
- stdc_ext
return_type: unsigned long int
arguments:
- type: unsigned long int
- type: unsigned long fract
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: diviuk
standards:
- stdc_ext
return_type: unsigned int
arguments:
- type: unsigned int
- type: unsigned accum
guard: LIBC_COMPILER_HAS_FIXED_POINT
- name: diviulk
standards:
- stdc_ext
return_type: unsigned long int
arguments:
- type: unsigned long int
- type: unsigned long accum
guard: LIBC_COMPILER_HAS_FIXED_POINT

View file

@ -23,6 +23,7 @@ add_header_library(
libc.src.__support.CPP.bit
libc.src.__support.CPP.limits
libc.src.__support.math_extras
libc.src.__support.uint128
)
add_header_library(

View file

@ -20,6 +20,7 @@
#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"
#include "src/__support/uint128.h"
#include "fx_rep.h"
@ -333,6 +334,44 @@ template <typename XType> LIBC_INLINE constexpr XType divi(int n, int d) {
}
}
// Divide an integer operand by a fixed-point operand and return the
// mathematically exact result as an IntType rounded towards 0. Assumes
// signedness of IntType matches the signedness of FXType.
template <typename IntType, typename FXType>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<FXType>, IntType>
divifx(IntType n, FXType d) {
using FXBits = FXBits<FXType>;
using FXRep = FXRep<FXType>;
using CompType = typename FXRep::CompType;
static_assert(cpp::is_signed_v<IntType> == (FXRep::SIGN_LEN > 0),
"IntType and FXType must have matching signedness");
// UB if denominator is 0.
LIBC_CRASH_ON_VALUE(d, FXRep::ZERO());
if (LIBC_UNLIKELY(n == 0)) {
return static_cast<IntType>(0);
}
CompType d_comp = static_cast<CompType>(FXBits(d).get_bits());
constexpr int F = FXRep::FRACTION_LEN;
constexpr int INTERMEDIATE_BITS =
sizeof(IntType) * 8 - cpp::is_signed_v<IntType> + F;
using WideType = cpp::conditional_t<
cpp::is_signed_v<IntType>,
cpp::conditional_t<INTERMEDIATE_BITS <= 64, int64_t, Int128>,
cpp::conditional_t<INTERMEDIATE_BITS <= 64, uint64_t, UInt128>>;
WideType scaled_n = static_cast<WideType>(n) << F;
WideType result = scaled_n / static_cast<WideType>(d_comp);
return static_cast<IntType>(result);
}
} // namespace fixed_point
} // namespace LIBC_NAMESPACE_DECL

View file

@ -51,6 +51,7 @@ template <> struct FXRep<short fract> {
LIBC_INLINE static constexpr Type EPS() { return SFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5HR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25HR; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125HR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@ -71,6 +72,7 @@ template <> struct FXRep<unsigned short fract> {
LIBC_INLINE static constexpr Type EPS() { return USFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UHR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UHR; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UHR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@ -91,6 +93,7 @@ template <> struct FXRep<fract> {
LIBC_INLINE static constexpr Type EPS() { return FRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5R; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25R; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125R; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@ -111,6 +114,7 @@ template <> struct FXRep<unsigned fract> {
LIBC_INLINE static constexpr Type EPS() { return UFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UR; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@ -131,6 +135,7 @@ template <> struct FXRep<long fract> {
LIBC_INLINE static constexpr Type EPS() { return LFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5LR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25LR; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125LR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@ -151,6 +156,7 @@ template <> struct FXRep<unsigned long fract> {
LIBC_INLINE static constexpr Type EPS() { return ULFRACT_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5ULR; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25ULR; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125ULR; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@ -171,6 +177,7 @@ template <> struct FXRep<short accum> {
LIBC_INLINE static constexpr Type EPS() { return SACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5HK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25HK; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125HK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@ -191,6 +198,7 @@ template <> struct FXRep<unsigned short accum> {
LIBC_INLINE static constexpr Type EPS() { return USACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UHK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UHK; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UHK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@ -211,6 +219,7 @@ template <> struct FXRep<accum> {
LIBC_INLINE static constexpr Type EPS() { return ACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5K; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25K; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125K; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@ -231,6 +240,7 @@ template <> struct FXRep<unsigned accum> {
LIBC_INLINE static constexpr Type EPS() { return UACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5UK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25UK; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125UK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;
@ -251,6 +261,7 @@ template <> struct FXRep<long accum> {
LIBC_INLINE static constexpr Type EPS() { return LACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5LK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25LK; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125LK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_signed_t<StorageType>;
@ -271,6 +282,7 @@ template <> struct FXRep<unsigned long accum> {
LIBC_INLINE static constexpr Type EPS() { return ULACCUM_EPSILON; }
LIBC_INLINE static constexpr Type ONE_HALF() { return 0.5ULK; }
LIBC_INLINE static constexpr Type ONE_FOURTH() { return 0.25ULK; }
LIBC_INLINE static constexpr Type ONE_EIGHTH() { return 0.125ULK; }
using StorageType = typename internal::Storage<TOTAL_LEN>::Type;
using CompType = cpp::make_unsigned_t<StorageType>;

View file

@ -102,6 +102,20 @@ foreach(suffix IN ITEMS r)
)
endforeach()
foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
add_entrypoint_object(
divi${suffix}
HDRS
divi${suffix}.h
SRCS
divi${suffix}.cpp
COMPILE_OPTIONS
${libc_opt_high_flag}
DEPENDS
libc.src.__support.fixed_point.fx_bits
)
endforeach()
add_entrypoint_object(
uhksqrtus
HDRS

21
libc/src/stdfix/divik.cpp Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation of divik 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 "divik.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, divik, (int n, accum d)) {
return fixed_point::divifx<int, accum>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/divik.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for divik -------------------------*- 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_DIVIK_H
#define LLVM_LIBC_SRC_STDFIX_DIVIK_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
int divik(int n, accum d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVIK_H

View file

@ -0,0 +1,21 @@
//===-- Implementation of divilk 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 "divilk.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long int, divilk, (long int n, long accum d)) {
return fixed_point::divifx<long int, long accum>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/divilk.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for divilk ------------------------*- 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_DIVILK_H
#define LLVM_LIBC_SRC_STDFIX_DIVILK_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
long int divilk(long int n, long accum d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVILK_H

View file

@ -0,0 +1,21 @@
//===-- Implementation of divilr 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 "divilr.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(long int, divilr, (long int n, long fract d)) {
return fixed_point::divifx<long int, long fract>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/divilr.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for divilr ------------------------*- 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_DIVILR_H
#define LLVM_LIBC_SRC_STDFIX_DIVILR_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
long int divilr(long int n, long fract d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVILR_H

21
libc/src/stdfix/divir.cpp Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation of divir 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 "divir.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(int, divir, (int n, fract d)) {
return fixed_point::divifx<int, fract>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/divir.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for divir -------------------------*- 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_DIVIR_H
#define LLVM_LIBC_SRC_STDFIX_DIVIR_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
int divir(int n, fract d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVIR_H

View file

@ -0,0 +1,21 @@
//===-- Implementation of diviuk 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 "diviuk.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned int, diviuk, (unsigned int n, unsigned accum d)) {
return fixed_point::divifx<unsigned int, unsigned accum>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/diviuk.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for diviuk ------------------------*- 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_DIVIUK_H
#define LLVM_LIBC_SRC_STDFIX_DIVIUK_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
unsigned int diviuk(unsigned int n, unsigned accum d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVIUK_H

View file

@ -0,0 +1,22 @@
//===-- Implementation of diviulk 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 "diviulk.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long int, diviulk,
(unsigned long int n, unsigned long accum d)) {
return fixed_point::divifx<unsigned long int, unsigned long accum>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/diviulk.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for diviulk -----------------------*- 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_DIVIULK_H
#define LLVM_LIBC_SRC_STDFIX_DIVIULK_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
unsigned long int diviulk(unsigned long int n, unsigned long accum d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVIULK_H

View file

@ -0,0 +1,22 @@
//===-- Implementation of diviulr 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 "diviulr.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned long int, diviulr,
(unsigned long int n, unsigned long fract d)) {
return fixed_point::divifx<unsigned long int, unsigned long fract>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/diviulr.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for diviulr -----------------------*- 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_DIVIULR_H
#define LLVM_LIBC_SRC_STDFIX_DIVIULR_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
unsigned long int diviulr(unsigned long int n, unsigned long fract d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVIULR_H

View file

@ -0,0 +1,21 @@
//===-- Implementation of diviur 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 "diviur.h"
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
LLVM_LIBC_FUNCTION(unsigned int, diviur, (unsigned int n, unsigned fract d)) {
return fixed_point::divifx<unsigned int, unsigned fract>(n, d);
}
} // namespace LIBC_NAMESPACE_DECL

21
libc/src/stdfix/diviur.h Normal file
View file

@ -0,0 +1,21 @@
//===-- Implementation header for diviur ------------------------*- 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_DIVIUR_H
#define LLVM_LIBC_SRC_STDFIX_DIVIUR_H
#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
unsigned int diviur(unsigned int n, unsigned fract d);
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC_STDFIX_DIVIUR_H

View file

@ -147,6 +147,23 @@ foreach(suffix IN ITEMS r)
)
endforeach()
foreach(suffix IN ITEMS r lr k lk ur ulr uk ulk)
add_libc_test(
divi${suffix}_test
SUITE
libc-stdfix-tests
HDRS
DiviFxTest.h
SRCS
divi${suffix}_test.cpp
DEPENDS
libc.src.stdfix.divi${suffix}
libc.src.__support.fixed_point.fx_rep
libc.src.__support.fixed_point.fx_bits
libc.hdr.signal_macros
)
endforeach()
add_libc_test(
uhksqrtus_test
SUITE

View file

@ -0,0 +1,176 @@
//===-- Utility class to test divifx 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 "hdr/signal_macros.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/fixed_point/fx_bits.h"
#include "src/__support/fixed_point/fx_rep.h"
namespace cpp = LIBC_NAMESPACE::cpp;
template <typename IntType, typename FXType>
class DiviFxTest : public LIBC_NAMESPACE::testing::Test {
using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<FXType>;
static constexpr FXType max = FXRep::MAX();
static constexpr FXType min = FXRep::MIN();
static constexpr FXType zero = FXRep::ZERO();
static constexpr FXType epsilon = FXRep::EPS();
static constexpr FXType one_half = FXRep::ONE_HALF();
static constexpr FXType one_fourth = FXRep::ONE_FOURTH();
static constexpr FXType one_eighth = FXRep::ONE_EIGHTH();
static constexpr bool is_signed = (FXRep::SIGN_LEN > 0);
static constexpr bool has_integral = (FXRep::INTEGRAL_LEN > 0);
public:
typedef IntType (*DiviFxFunc)(IntType, FXType);
void testBasicNumbers(DiviFxFunc func) {
EXPECT_EQ(func(0, one_eighth), static_cast<IntType>(0));
EXPECT_EQ(func(0, one_fourth), static_cast<IntType>(0));
EXPECT_EQ(func(0, one_half), static_cast<IntType>(0));
EXPECT_EQ(func(1, one_eighth), static_cast<IntType>(8));
EXPECT_EQ(func(1, one_fourth), static_cast<IntType>(4));
EXPECT_EQ(func(1, one_half), static_cast<IntType>(2));
EXPECT_EQ(func(2, one_eighth), static_cast<IntType>(16));
EXPECT_EQ(func(2, one_fourth), static_cast<IntType>(8));
EXPECT_EQ(func(2, one_half), static_cast<IntType>(4));
// Verify rounding towards 0.
EXPECT_EQ(func(1, 3 * one_fourth), static_cast<IntType>(1));
EXPECT_EQ(func(2, 3 * one_fourth), static_cast<IntType>(2));
if constexpr (is_signed) {
EXPECT_EQ(func(-1, one_half), static_cast<IntType>(-2));
EXPECT_EQ(func(1, -one_half), static_cast<IntType>(-2));
EXPECT_EQ(func(-1, -one_half), static_cast<IntType>(2));
EXPECT_EQ(func(-2, one_fourth), static_cast<IntType>(-8));
EXPECT_EQ(func(2, -one_fourth), static_cast<IntType>(-8));
// Verify rounding towards 0.
EXPECT_EQ(func(-1, 3 * one_fourth), static_cast<IntType>(-1));
EXPECT_EQ(func(1, -3 * one_fourth), static_cast<IntType>(-1));
EXPECT_EQ(func(-2, 3 * one_fourth), static_cast<IntType>(-2));
EXPECT_EQ(func(2, -3 * one_fourth), static_cast<IntType>(-2));
EXPECT_EQ(func(1, static_cast<FXType>(-1)), static_cast<IntType>(-1));
EXPECT_EQ(func(-1, static_cast<FXType>(-1)), static_cast<IntType>(1));
}
if constexpr (has_integral) {
EXPECT_EQ(func(1, static_cast<FXType>(1)), static_cast<IntType>(1));
if constexpr (is_signed) {
EXPECT_EQ(func(-1, static_cast<FXType>(1)), static_cast<IntType>(-1));
}
// Only run these tests for accum types that can represent these operands.
constexpr FXType max_test_operand = static_cast<FXType>(4);
if constexpr (max >= max_test_operand) {
EXPECT_EQ(func(3, 2.5), static_cast<IntType>(1));
EXPECT_EQ(func(2, 3.5), static_cast<IntType>(0));
EXPECT_EQ(func(3, 1.5), static_cast<IntType>(2));
EXPECT_EQ(func(4, 2.0), static_cast<IntType>(2));
if constexpr (is_signed) {
EXPECT_EQ(func(2, -3.5), static_cast<IntType>(0));
EXPECT_EQ(func(-3, 2.5), static_cast<IntType>(-1));
EXPECT_EQ(func(-3, 1.5), static_cast<IntType>(-2));
EXPECT_EQ(func(-3, -2.5), static_cast<IntType>(1));
}
}
}
}
void testEdgeCases(DiviFxFunc func) {
constexpr IntType int_max = cpp::numeric_limits<IntType>::max();
if constexpr (has_integral) {
EXPECT_EQ(func(int_max, static_cast<FXType>(1)), int_max);
}
if constexpr (is_signed) {
EXPECT_EQ(func(int_max, static_cast<FXType>(-1)), -int_max);
}
// Only valid when integral bits (excluding sign) exceed fraction bits.
// Otherwise 1<<FRACTION_LEN may not fit in IntType.
if constexpr ((FXRep::INTEGRAL_LEN) > FXRep::FRACTION_LEN) {
constexpr IntType epsilon_result = static_cast<IntType>(1)
<< FXRep::FRACTION_LEN;
EXPECT_EQ(func(1, epsilon), epsilon_result);
if constexpr (is_signed) {
EXPECT_EQ(func(1, -epsilon), -epsilon_result);
EXPECT_EQ(func(-1, epsilon), -epsilon_result);
EXPECT_EQ(func(-1, -epsilon), epsilon_result);
}
}
if constexpr (has_integral) {
constexpr IntType largest_positive =
((static_cast<IntType>(1) << FXRep::INTEGRAL_LEN) - 1);
EXPECT_EQ(func(largest_positive, static_cast<FXType>(largest_positive)),
static_cast<IntType>(1));
constexpr IntType largest_power_of_two = static_cast<IntType>(1)
<< (FXRep::INTEGRAL_LEN - 1);
EXPECT_EQ(
func(largest_power_of_two, static_cast<FXType>(largest_power_of_two)),
static_cast<IntType>(1));
}
if constexpr (!has_integral) {
EXPECT_EQ(func(1, max), static_cast<IntType>(1));
if constexpr (is_signed) {
EXPECT_EQ(func(1, min), static_cast<IntType>(-1));
}
}
if constexpr (has_integral) {
EXPECT_EQ(func(1, max), static_cast<IntType>(0));
if constexpr (is_signed) {
EXPECT_EQ(func(1, min), static_cast<IntType>(0));
}
}
}
void testInvalidNumbers(DiviFxFunc func) {
EXPECT_DEATH([func] { func(1, zero); }, WITH_SIGNAL(-1));
if constexpr (has_integral) {
EXPECT_DEATH([func] { func(2, zero); }, WITH_SIGNAL(-1));
}
}
};
#if defined(LIBC_ADD_NULL_CHECKS)
#define LIST_DIVIFX_TESTS(Name, IntType, FXType, func) \
using LlvmLibcDivi##Name##Test = DiviFxTest<IntType, FXType>; \
TEST_F(LlvmLibcDivi##Name##Test, InvalidNumbers) { \
testInvalidNumbers(&func); \
} \
TEST_F(LlvmLibcDivi##Name##Test, BasicNumbers) { testBasicNumbers(&func); } \
TEST_F(LlvmLibcDivi##Name##Test, EdgeCases) { testEdgeCases(&func); } \
static_assert(true, "Require semicolon.")
#else
#define LIST_DIVIFX_TESTS(Name, IntType, FXType, func) \
using LlvmLibcDivi##Name##Test = DiviFxTest<IntType, FXType>; \
TEST_F(LlvmLibcDivi##Name##Test, BasicNumbers) { testBasicNumbers(&func); } \
TEST_F(LlvmLibcDivi##Name##Test, EdgeCases) { testEdgeCases(&func); } \
static_assert(true, "Require semicolon.")
#endif // LIBC_ADD_NULL_CHECKS

View file

@ -0,0 +1,14 @@
//===-- Unittests for divik -----------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/divik.h"
LIST_DIVIFX_TESTS(k, int, accum, LIBC_NAMESPACE::divik);

View file

@ -0,0 +1,14 @@
//===-- Unittests for divilk ----------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/divilk.h"
LIST_DIVIFX_TESTS(lk, long int, long accum, LIBC_NAMESPACE::divilk);

View file

@ -0,0 +1,14 @@
//===-- Unittests for divilr ----------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/divilr.h"
LIST_DIVIFX_TESTS(lr, long int, long fract, LIBC_NAMESPACE::divilr);

View file

@ -0,0 +1,14 @@
//===-- Unittests for divir -----------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/divir.h"
LIST_DIVIFX_TESTS(r, int, fract, LIBC_NAMESPACE::divir);

View file

@ -0,0 +1,14 @@
//===-- Unittests for diviuk ----------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/diviuk.h"
LIST_DIVIFX_TESTS(uk, unsigned int, unsigned accum, LIBC_NAMESPACE::diviuk);

View file

@ -0,0 +1,15 @@
//===-- Unittests for diviulk ---------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/diviulk.h"
LIST_DIVIFX_TESTS(ulk, unsigned long int, unsigned long accum,
LIBC_NAMESPACE::diviulk);

View file

@ -0,0 +1,15 @@
//===-- Unittests for diviulr ---------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/diviulr.h"
LIST_DIVIFX_TESTS(ulr, unsigned long int, unsigned long fract,
LIBC_NAMESPACE::diviulr);

View file

@ -0,0 +1,14 @@
//===-- Unittests for diviur ----------------------------------------------===//
//
// 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 "DiviFxTest.h"
#include "llvm-libc-macros/stdfix-macros.h"
#include "src/stdfix/diviur.h"
LIST_DIVIFX_TESTS(ur, unsigned int, unsigned fract, LIBC_NAMESPACE::diviur);