207 changes: 168 additions & 39 deletions libc/src/__support/fixed_point/sqrt.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include "include/llvm-libc-macros/stdfix-macros.h"
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/limits.h" // CHAR_BIT
#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY
Expand All @@ -28,16 +29,73 @@ template <typename T> struct SqrtConfig;
template <> struct SqrtConfig<unsigned short fract> {
using Type = unsigned short fract;
static constexpr int EXTRA_STEPS = 0;

// Linear approximation for the initial values, with errors bounded by:
// max(1.5 * 2^-11, eps)
// Generated with Sollya:
// > for i from 4 to 15 do {
// P = fpminimax(sqrt(x), 1, [|8, 8|], [i * 2^-4, (i + 1)*2^-4],
// fixed, absolute);
// print("{", coeff(P, 1), "uhr,", coeff(P, 0), "uhr},");
// };
static constexpr Type FIRST_APPROX[12][2] = {
{0x1.e8p-1uhr, 0x1.0cp-2uhr}, {0x1.bap-1uhr, 0x1.28p-2uhr},
{0x1.94p-1uhr, 0x1.44p-2uhr}, {0x1.74p-1uhr, 0x1.6p-2uhr},
{0x1.6p-1uhr, 0x1.74p-2uhr}, {0x1.4ep-1uhr, 0x1.88p-2uhr},
{0x1.3ep-1uhr, 0x1.9cp-2uhr}, {0x1.32p-1uhr, 0x1.acp-2uhr},
{0x1.22p-1uhr, 0x1.c4p-2uhr}, {0x1.18p-1uhr, 0x1.d4p-2uhr},
{0x1.08p-1uhr, 0x1.fp-2uhr}, {0x1.04p-1uhr, 0x1.f8p-2uhr},
};
};

template <> struct SqrtConfig<unsigned fract> {
using Type = unsigned fract;
static constexpr int EXTRA_STEPS = 1;

// Linear approximation for the initial values, with errors bounded by:
// max(1.5 * 2^-11, eps)
// Generated with Sollya:
// > for i from 4 to 15 do {
// P = fpminimax(sqrt(x), 1, [|16, 16|], [i * 2^-4, (i + 1)*2^-4],
// fixed, absolute);
// print("{", coeff(P, 1), "ur,", coeff(P, 0), "ur},");
// };
static constexpr Type FIRST_APPROX[12][2] = {
{0x1.e378p-1ur, 0x1.0ebp-2ur}, {0x1.b512p-1ur, 0x1.2b94p-2ur},
{0x1.91fp-1ur, 0x1.45dcp-2ur}, {0x1.7622p-1ur, 0x1.5e24p-2ur},
{0x1.5f5ap-1ur, 0x1.74e4p-2ur}, {0x1.4c58p-1ur, 0x1.8a4p-2ur},
{0x1.3c1ep-1ur, 0x1.9e84p-2ur}, {0x1.2e0cp-1ur, 0x1.b1d8p-2ur},
{0x1.21aap-1ur, 0x1.c468p-2ur}, {0x1.16bap-1ur, 0x1.d62cp-2ur},
{0x1.0cfp-1ur, 0x1.e74cp-2ur}, {0x1.0418p-1ur, 0x1.f7ep-2ur},
};
};

template <> struct SqrtConfig<unsigned long fract> {
using Type = unsigned long fract;
static constexpr int EXTRA_STEPS = 2;

// Linear approximation for the initial values, with errors bounded by:
// max(1.5 * 2^-11, eps)
// Generated with Sollya:
// > for i from 4 to 15 do {
// P = fpminimax(sqrt(x), 1, [|32, 32|], [i * 2^-4, (i + 1)*2^-4],
// fixed, absolute);
// print("{", coeff(P, 1), "ulr,", coeff(P, 0), "ulr},");
// };
static constexpr Type FIRST_APPROX[12][2] = {
{0x1.e3779b98p-1ulr, 0x1.0eaff788p-2ulr},
{0x1.b5167872p-1ulr, 0x1.2b908ad4p-2ulr},
{0x1.91f195cap-1ulr, 0x1.45da800cp-2ulr},
{0x1.761ebcb4p-1ulr, 0x1.5e27004cp-2ulr},
{0x1.5f619986p-1ulr, 0x1.74db933cp-2ulr},
{0x1.4c583adep-1ulr, 0x1.8a3fbfccp-2ulr},
{0x1.3c1a591cp-1ulr, 0x1.9e88373cp-2ulr},
{0x1.2e08545ap-1ulr, 0x1.b1dd2534p-2ulr},
{0x1.21b05c0ap-1ulr, 0x1.c45e023p-2ulr},
{0x1.16becd02p-1ulr, 0x1.d624031p-2ulr},
{0x1.0cf49fep-1ulr, 0x1.e743b844p-2ulr},
{0x1.04214e9cp-1ulr, 0x1.f7ce2c3cp-2ulr},
};
};

template <>
Expand All @@ -46,46 +104,38 @@ struct SqrtConfig<unsigned short accum> : SqrtConfig<unsigned fract> {};
template <>
struct SqrtConfig<unsigned accum> : SqrtConfig<unsigned long fract> {};

// TODO: unsigned long accum type is 64-bit, and will need 64-bit fract type.
// Probably we will use DyadicFloat<64> for intermediate computations instead.

// Linear approximation for the initial values, with errors bounded by:
// max(1.5 * 2^-11, eps)
// Generated with Sollya:
// > for i from 4 to 15 do {
// P = fpminimax(sqrt(x), 1, [|8, 8|], [i * 2^-4, (i + 1)*2^-4],
// fixed, absolute);
// print("{", coeff(P, 1), "uhr,", coeff(P, 0), "uhr},");
// };
static constexpr unsigned short fract SQRT_FIRST_APPROX[12][2] = {
{0x1.e8p-1uhr, 0x1.0cp-2uhr}, {0x1.bap-1uhr, 0x1.28p-2uhr},
{0x1.94p-1uhr, 0x1.44p-2uhr}, {0x1.74p-1uhr, 0x1.6p-2uhr},
{0x1.6p-1uhr, 0x1.74p-2uhr}, {0x1.4ep-1uhr, 0x1.88p-2uhr},
{0x1.3ep-1uhr, 0x1.9cp-2uhr}, {0x1.32p-1uhr, 0x1.acp-2uhr},
{0x1.22p-1uhr, 0x1.c4p-2uhr}, {0x1.18p-1uhr, 0x1.d4p-2uhr},
{0x1.08p-1uhr, 0x1.fp-2uhr}, {0x1.04p-1uhr, 0x1.f8p-2uhr},
// Integer square root
template <> struct SqrtConfig<unsigned short> {
using OutType = unsigned short accum;
using FracType = unsigned fract;
// For fast-but-less-accurate version
using FastFracType = unsigned short fract;
using HalfType = unsigned char;
};

} // namespace internal
template <> struct SqrtConfig<unsigned int> {
using OutType = unsigned accum;
using FracType = unsigned long fract;
// For fast-but-less-accurate version
using FastFracType = unsigned fract;
using HalfType = unsigned short;
};

template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, T> sqrt(T x) {
using BitType = typename FXRep<T>::StorageType;
BitType x_bit = cpp::bit_cast<BitType>(x);
// TODO: unsigned long accum type is 64-bit, and will need 64-bit fract type.
// Probably we will use DyadicFloat<64> for intermediate computations instead.

if (LIBC_UNLIKELY(x_bit == 0))
return FXRep<T>::ZERO();
} // namespace internal

int leading_zeros = cpp::countl_zero(x_bit);
constexpr int STORAGE_LENGTH = sizeof(BitType) * CHAR_BIT;
constexpr int EXP_ADJUSTMENT = STORAGE_LENGTH - FXRep<T>::FRACTION_LEN - 1;
// x_exp is the real exponent of the leading bit of x.
int x_exp = EXP_ADJUSTMENT - leading_zeros;
int shift = EXP_ADJUSTMENT - 1 - (x_exp & (~1));
// Normalize.
x_bit <<= shift;
using FracType = typename internal::SqrtConfig<T>::Type;
FracType x_frac = cpp::bit_cast<FracType>(x_bit);
// Core computation for sqrt with normalized inputs (0.25 <= x < 1).
template <typename Config>
LIBC_INLINE constexpr typename Config::Type
sqrt_core(typename Config::Type x_frac) {
using FracType = typename Config::Type;
using FXRep = FXRep<FracType>;
using StorageType = typename FXRep::StorageType;
// Exact case:
if (x_frac == FXRep::ONE_FOURTH())
return FXRep::ONE_HALF();

// Use use Newton method to approximate sqrt(a):
// x_{n + 1} = 1/2 (x_n + a / x_n)
Expand All @@ -96,9 +146,10 @@ LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, T> sqrt(T x) {
// are between 0b0100 and 0b1111. Hence the lookup table only needs 12
// entries, and we can get the index by subtracting the leading 4 bits of
// x_frac by 4 = 0b0100.
int index = (x_bit >> (STORAGE_LENGTH - 4)) - 4;
FracType a = static_cast<FracType>(internal::SQRT_FIRST_APPROX[index][0]);
FracType b = static_cast<FracType>(internal::SQRT_FIRST_APPROX[index][1]);
StorageType x_bit = cpp::bit_cast<StorageType>(x_frac);
int index = (static_cast<int>(x_bit >> (FXRep::TOTAL_LEN - 4))) - 4;
FracType a = Config::FIRST_APPROX[index][0];
FracType b = Config::FIRST_APPROX[index][1];

// Initial approximation step.
// Estimated error bounds: | r - sqrt(x_frac) | < max(1.5 * 2^-11, eps).
Expand All @@ -112,16 +163,94 @@ LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, T> sqrt(T x) {
// Blanchard, J. D. and Chamberland, M., "Newton's Method Without Division",
// The American Mathematical Monthly (2023).
// https://chamberland.math.grinnell.edu/papers/newton.pdf
for (int i = 0; i < internal::SqrtConfig<T>::EXTRA_STEPS; ++i)
for (int i = 0; i < Config::EXTRA_STEPS; ++i)
r = (r >> 1) + (x_frac >> 1) / r;

return r;
}

template <typename T>
LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_fixed_point_v<T>, T> sqrt(T x) {
using BitType = typename FXRep<T>::StorageType;
BitType x_bit = cpp::bit_cast<BitType>(x);

if (LIBC_UNLIKELY(x_bit == 0))
return FXRep<T>::ZERO();

int leading_zeros = cpp::countl_zero(x_bit);
constexpr int STORAGE_LENGTH = sizeof(BitType) * CHAR_BIT;
constexpr int EXP_ADJUSTMENT = STORAGE_LENGTH - FXRep<T>::FRACTION_LEN - 1;
// x_exp is the real exponent of the leading bit of x.
int x_exp = EXP_ADJUSTMENT - leading_zeros;
int shift = EXP_ADJUSTMENT - 1 - (x_exp & (~1));
// Normalize.
x_bit <<= shift;
using FracType = typename internal::SqrtConfig<T>::Type;
FracType x_frac = cpp::bit_cast<FracType>(x_bit);

// Compute sqrt(x_frac) using Newton-method.
FracType r = sqrt_core<internal::SqrtConfig<T>>(x_frac);

// Re-scaling
r >>= EXP_ADJUSTMENT - (x_exp >> 1);

// Return result.
return cpp::bit_cast<T>(r);
}

// Integer square root - Accurate version:
// Absolute errors < 2^(-fraction length).
template <typename T>
LIBC_INLINE constexpr typename internal::SqrtConfig<T>::OutType isqrt(T x) {
using OutType = typename internal::SqrtConfig<T>::OutType;
using FracType = typename internal::SqrtConfig<T>::FracType;

if (x == 0)
return FXRep<OutType>::ZERO();

// Normalize the leading bits to the first two bits.
// Shift and then Bit cast x to x_frac gives us:
// x = 2^(FRACTION_LEN + 1 - shift) * x_frac;
int leading_zeros = cpp::countl_zero(x);
int shift = ((leading_zeros >> 1) << 1);
x <<= shift;
// Convert to frac type and compute square root.
FracType x_frac = cpp::bit_cast<FracType>(x);
FracType r = sqrt_core<internal::SqrtConfig<FracType>>(x_frac);
// To rescale back to the OutType (Accum)
r >>= (shift >> 1);

return cpp::bit_cast<OutType>(r);
}

// Integer square root - Fast but less accurate version:
// Relative errors < 2^(-fraction length).
template <typename T>
LIBC_INLINE constexpr typename internal::SqrtConfig<T>::OutType
isqrt_fast(T x) {
using OutType = typename internal::SqrtConfig<T>::OutType;
using FracType = typename internal::SqrtConfig<T>::FastFracType;
using StorageType = typename FXRep<FracType>::StorageType;

if (x == 0)
return FXRep<OutType>::ZERO();

// Normalize the leading bits to the first two bits.
// Shift and then Bit cast x to x_frac gives us:
// x = 2^(FRACTION_LEN + 1 - shift) * x_frac;
int leading_zeros = cpp::countl_zero(x);
int shift = (leading_zeros & (~1));
x <<= shift;
// Convert to frac type and compute square root.
FracType x_frac = cpp::bit_cast<FracType>(
static_cast<StorageType>(x >> FXRep<FracType>::FRACTION_LEN));
OutType r =
static_cast<OutType>(sqrt_core<internal::SqrtConfig<FracType>>(x_frac));
// To rescale back to the OutType (Accum)
r <<= (FXRep<OutType>::INTEGRAL_LEN - (shift >> 1));
return cpp::bit_cast<OutType>(r);
}

} // namespace LIBC_NAMESPACE::fixed_point

#endif // LIBC_COMPILER_HAS_FIXED_POINT
Expand Down
27 changes: 24 additions & 3 deletions libc/src/stdfix/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ foreach(suffix IN ITEMS hr r lr hk k lk)
abs${suffix}.cpp
COMPILE_OPTIONS
-O3
-ffixed-point
DEPENDS
libc.src.__support.fixed_point.fx_bits
)
Expand All @@ -26,7 +25,6 @@ foreach(suffix IN ITEMS uhr ur ulr uhk uk)
sqrt${suffix}.cpp
COMPILE_OPTIONS
-O3
-ffixed-point
DEPENDS
libc.src.__support.fixed_point.sqrt
)
Expand All @@ -41,8 +39,31 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
round${suffix}.cpp
COMPILE_OPTIONS
-O3
-ffixed-point
DEPENDS
libc.src.__support.fixed_point.fx_bits
)
endforeach()

add_entrypoint_object(
uhksqrtus
HDRS
uhksqrtus.h
SRCS
uhksqrtus.cpp
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.fixed_point.sqrt
)

add_entrypoint_object(
uksqrtui
HDRS
uksqrtui.h
SRCS
uksqrtui.cpp
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.__support.fixed_point.sqrt
)
23 changes: 23 additions & 0 deletions libc/src/stdfix/uhksqrtus.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===-- Implementation of uhksqrtus 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 "uhksqrtus.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/sqrt.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned short accum, uhksqrtus, (unsigned short x)) {
#ifdef LIBC_FAST_MATH
return fixed_point::isqrt_fast(x);
#else
return fixed_point::isqrt(x);
#endif
}

} // namespace LIBC_NAMESPACE
20 changes: 20 additions & 0 deletions libc/src/stdfix/uhksqrtus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for uhksqrtus ---------------------*- 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_UHKSQRTUS_H
#define LLVM_LIBC_SRC_STDFIX_UHKSQRTUS_H

#include "include/llvm-libc-macros/stdfix-macros.h"

namespace LIBC_NAMESPACE {

unsigned short accum uhksqrtus(unsigned short x);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDFIX_UHKSQRTUS_H
23 changes: 23 additions & 0 deletions libc/src/stdfix/uksqrtui.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===-- Implementation of uksqrtui 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 "uksqrtui.h"
#include "src/__support/common.h"
#include "src/__support/fixed_point/sqrt.h"

namespace LIBC_NAMESPACE {

LLVM_LIBC_FUNCTION(unsigned accum, uksqrtui, (unsigned int x)) {
#ifdef LIBC_FAST_MATH
return fixed_point::isqrt_fast(x);
#else
return fixed_point::isqrt(x);
#endif
}

} // namespace LIBC_NAMESPACE
20 changes: 20 additions & 0 deletions libc/src/stdfix/uksqrtui.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for uksqrtui ----------------------*- 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_UKSQRTUI_H
#define LLVM_LIBC_SRC_STDFIX_UKSQRTUI_H

#include "include/llvm-libc-macros/stdfix-macros.h"

namespace LIBC_NAMESPACE {

unsigned accum uksqrtui(unsigned int x);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_STDFIX_UKSQRTUI_H
41 changes: 38 additions & 3 deletions libc/test/src/stdfix/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ foreach(suffix IN ITEMS hr r lr hk k lk)
abs${suffix}_test.cpp
COMPILE_OPTIONS
-O3
-ffixed-point
DEPENDS
libc.src.stdfix.abs${suffix}
libc.src.__support.fixed_point.fx_bits
Expand All @@ -33,7 +32,6 @@ foreach(suffix IN ITEMS uhr ur ulr uhk uk)
sqrt${suffix}_test.cpp
COMPILE_OPTIONS
-O3
-ffixed-point
DEPENDS
libc.src.stdfix.sqrt${suffix}
libc.src.__support.CPP.bit
Expand All @@ -55,9 +53,46 @@ foreach(suffix IN ITEMS hr r lr hk k lk uhr ur ulr uhk uk ulk)
round${suffix}_test.cpp
COMPILE_OPTIONS
-O3
-ffixed-point
DEPENDS
libc.src.stdfix.round${suffix}
libc.src.__support.fixed_point.fx_bits
)
endforeach()

add_libc_test(
uhksqrtus_test
SUITE
libc-stdfix-tests
HDRS
ISqrtTest.h
SRCS
uhksqrtus_test.cpp
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.stdfix.uhksqrtus
libc.src.__support.CPP.bit
libc.src.__support.fixed_point.fx_rep
libc.src.__support.fixed_point.sqrt
libc.src.__support.FPUtil.basic_operations
libc.src.__support.FPUtil.sqrt
)

add_libc_test(
uksqrtui_test
SUITE
libc-stdfix-tests
HDRS
ISqrtTest.h
SRCS
uksqrtui_test.cpp
COMPILE_OPTIONS
-O3
DEPENDS
libc.src.stdfix.uksqrtui
libc.src.__support.CPP.bit
libc.src.__support.fixed_point.fx_rep
libc.src.__support.fixed_point.sqrt
libc.src.__support.FPUtil.basic_operations
libc.src.__support.FPUtil.sqrt
)
63 changes: 63 additions & 0 deletions libc/test/src/stdfix/ISqrtTest.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//===-- Utility class to test integer sqrt ----------------------*- 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/FPMatcher.h"
#include "test/UnitTest/Test.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/FPUtil/BasicOperations.h"
#include "src/__support/FPUtil/sqrt.h"
#include "src/__support/fixed_point/fx_rep.h"
#include "src/__support/fixed_point/sqrt.h"

template <typename T> class ISqrtTest : public LIBC_NAMESPACE::testing::Test {

using OutType =
typename LIBC_NAMESPACE::fixed_point::internal::SqrtConfig<T>::OutType;
using FXRep = LIBC_NAMESPACE::fixed_point::FXRep<OutType>;
static constexpr OutType zero = FXRep::ZERO();
static constexpr OutType one = static_cast<OutType>(1);
static constexpr OutType eps = FXRep::EPS();

public:
typedef OutType (*SqrtFunc)(T);

void testSpecialNumbers(SqrtFunc func) {
EXPECT_EQ(zero, func(T(0)));

EXPECT_EQ(one, func(T(1)));
EXPECT_EQ(static_cast<OutType>(2.0), func(T(4)));
EXPECT_EQ(static_cast<OutType>(4.0), func(T(16)));
EXPECT_EQ(static_cast<OutType>(16.0), func(T(256)));

constexpr int COUNT = 255;
constexpr double ERR = 3.0 * static_cast<double>(eps);
double x_d = 0.0;
T x = 0;
for (int i = 0; i < COUNT; ++i) {
x_d += 1.0;
++x;
double y_d = static_cast<double>(func(x));
double result = LIBC_NAMESPACE::fputil::sqrt(x_d);
double errors = LIBC_NAMESPACE::fputil::abs((y_d / result) - 1.0);
if (errors > ERR) {
// Print out the failure input and output.
EXPECT_EQ(x, T(0));
EXPECT_EQ(func(x), zero);
}
ASSERT_TRUE(errors <= ERR);
}
}
};

#define LIST_ISQRT_TESTS(Name, T, func) \
using LlvmLibcISqrt##Name##Test = ISqrtTest<T>; \
TEST_F(LlvmLibcISqrt##Name##Test, SpecialNumbers) { \
testSpecialNumbers(&func); \
} \
static_assert(true, "Require semicolon.")
20 changes: 20 additions & 0 deletions libc/test/src/stdfix/uhksqrtus_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Unittests for uhksqrtus -------------------------------------------===//
//
// 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 "ISqrtTest.h"

#include "src/__support/fixed_point/sqrt.h"
#include "src/stdfix/uhksqrtus.h"

unsigned short accum uhksqrtus_fast(unsigned short x) {
return LIBC_NAMESPACE::fixed_point::isqrt_fast(x);
}

LIST_ISQRT_TESTS(US, unsigned short, LIBC_NAMESPACE::uhksqrtus);

LIST_ISQRT_TESTS(USFast, unsigned short, uhksqrtus_fast);
20 changes: 20 additions & 0 deletions libc/test/src/stdfix/uksqrtui_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Unittests for uksqrtui --------------------------------------------===//
//
// 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 "ISqrtTest.h"

#include "src/__support/fixed_point/sqrt.h"
#include "src/stdfix/uksqrtui.h"

unsigned accum uksqrtui_fast(unsigned int x) {
return LIBC_NAMESPACE::fixed_point::isqrt_fast(x);
}

LIST_ISQRT_TESTS(UI, unsigned int, LIBC_NAMESPACE::uksqrtui);

LIST_ISQRT_TESTS(UIFast, unsigned int, uksqrtui_fast);