diff --git a/libc/config/darwin/arm/entrypoints.txt b/libc/config/darwin/arm/entrypoints.txt new file mode 100644 --- /dev/null +++ b/libc/config/darwin/arm/entrypoints.txt @@ -0,0 +1,196 @@ +set(TARGET_LIBC_ENTRYPOINTS + # ctype.h entrypoints + libc.src.ctype.isalnum + libc.src.ctype.isalpha + libc.src.ctype.isascii + libc.src.ctype.isblank + libc.src.ctype.iscntrl + libc.src.ctype.isdigit + libc.src.ctype.isgraph + libc.src.ctype.islower + libc.src.ctype.isprint + libc.src.ctype.ispunct + libc.src.ctype.isspace + libc.src.ctype.isupper + libc.src.ctype.isxdigit + libc.src.ctype.toascii + libc.src.ctype.tolower + libc.src.ctype.toupper + + # string.h entrypoints + libc.src.string.bcmp + libc.src.string.bzero + libc.src.string.memccpy + libc.src.string.memchr + libc.src.string.memcmp + libc.src.string.memcpy + libc.src.string.memmove + libc.src.string.mempcpy + libc.src.string.memrchr + libc.src.string.memset + libc.src.string.stpcpy + libc.src.string.stpncpy + libc.src.string.strcat + libc.src.string.strchr + libc.src.string.strcmp + libc.src.string.strcpy + libc.src.string.strcspn + libc.src.string.strlen + libc.src.string.strncat + libc.src.string.strncmp + libc.src.string.strncpy + libc.src.string.strnlen + libc.src.string.strpbrk + libc.src.string.strrchr + libc.src.string.strspn + libc.src.string.strstr + libc.src.string.strtok + libc.src.string.strtok_r + + # string.h entrypoints that depend on malloc + libc.src.string.strdup + libc.src.string.strndup + + # inttypes.h entrypoints + libc.src.inttypes.imaxdiv + libc.src.inttypes.strtoimax + libc.src.inttypes.strtoumax + + # stdlib.h entrypoints + libc.src.stdlib.abs + libc.src.stdlib.atoi + libc.src.stdlib.atof + libc.src.stdlib.atol + libc.src.stdlib.atoll + libc.src.stdlib.bsearch + libc.src.stdlib.div + libc.src.stdlib.labs + libc.src.stdlib.ldiv + libc.src.stdlib.llabs + libc.src.stdlib.lldiv + libc.src.stdlib.qsort + libc.src.stdlib.strtod + libc.src.stdlib.strtof + libc.src.stdlib.strtol + libc.src.stdlib.strtold + libc.src.stdlib.strtoll + libc.src.stdlib.strtoul + libc.src.stdlib.strtoull + + # stdlib.h external entrypoints + libc.src.stdlib.malloc + libc.src.stdlib.calloc + libc.src.stdlib.realloc + libc.src.stdlib.free +) + +set(TARGET_LIBM_ENTRYPOINTS + # fenv.h entrypoints + libc.src.fenv.feclearexcept + libc.src.fenv.fedisableexcept + libc.src.fenv.feenableexcept + libc.src.fenv.fegetenv + libc.src.fenv.fegetexcept + libc.src.fenv.fegetexceptflag + libc.src.fenv.fegetround + libc.src.fenv.feholdexcept + libc.src.fenv.fesetenv + libc.src.fenv.fesetexceptflag + libc.src.fenv.fesetround + libc.src.fenv.feraiseexcept + libc.src.fenv.fetestexcept + libc.src.fenv.feupdateenv + + # math.h entrypoints + libc.src.math.copysign + libc.src.math.copysignf + libc.src.math.copysignl + libc.src.math.ceil + libc.src.math.ceilf + libc.src.math.ceill + libc.src.math.cosf + libc.src.math.expf + libc.src.math.exp2f + libc.src.math.expm1f + libc.src.math.fabs + libc.src.math.fabsf + libc.src.math.fabsl + libc.src.math.fdim + libc.src.math.fdimf + libc.src.math.fdiml + libc.src.math.floor + libc.src.math.floorf + libc.src.math.floorl + libc.src.math.fma + libc.src.math.fmaf + libc.src.math.fmax + libc.src.math.fmaxf + libc.src.math.fmaxl + libc.src.math.fmin + libc.src.math.fminf + libc.src.math.fminl + libc.src.math.frexp + libc.src.math.frexpf + libc.src.math.frexpl + libc.src.math.hypot + libc.src.math.hypotf + libc.src.math.ilogb + libc.src.math.ilogbf + libc.src.math.ilogbl + libc.src.math.llrint + libc.src.math.llrintf + libc.src.math.llrintl + libc.src.math.llround + libc.src.math.llroundf + libc.src.math.llroundl + libc.src.math.lrint + libc.src.math.lrintf + libc.src.math.lrintl + libc.src.math.lround + libc.src.math.lroundf + libc.src.math.lroundl + libc.src.math.ldexp + libc.src.math.ldexpf + libc.src.math.ldexpl + libc.src.math.log10f + libc.src.math.log1pf + libc.src.math.log2f + libc.src.math.logf + libc.src.math.logb + libc.src.math.logbf + libc.src.math.logbl + libc.src.math.modf + libc.src.math.modff + libc.src.math.modfl + libc.src.math.nearbyint + libc.src.math.nearbyintf + libc.src.math.nearbyintl + libc.src.math.nextafter + libc.src.math.nextafterf + libc.src.math.nextafterl + libc.src.math.remainderf + libc.src.math.remainder + libc.src.math.remainderl + libc.src.math.remquof + libc.src.math.remquo + libc.src.math.remquol + libc.src.math.rint + libc.src.math.rintf + libc.src.math.rintl + libc.src.math.round + libc.src.math.roundf + libc.src.math.roundl + libc.src.math.sincosf + libc.src.math.sinf + libc.src.math.sqrt + libc.src.math.sqrtf + libc.src.math.sqrtl + libc.src.math.trunc + libc.src.math.truncf + libc.src.math.truncl +) + +set(TARGET_LLVMLIBC_ENTRYPOINTS + ${TARGET_LIBC_ENTRYPOINTS} + ${TARGET_LIBM_ENTRYPOINTS} +) diff --git a/libc/config/darwin/arm/headers.txt b/libc/config/darwin/arm/headers.txt new file mode 100644 --- /dev/null +++ b/libc/config/darwin/arm/headers.txt @@ -0,0 +1,9 @@ +set(TARGET_PUBLIC_HEADERS + libc.include.ctype + libc.include.errno + libc.include.fenv + libc.include.inttypes + libc.include.math + libc.include.stdlib + libc.include.string +) diff --git a/libc/src/__support/FPUtil/FEnvImpl.h b/libc/src/__support/FPUtil/FEnvImpl.h --- a/libc/src/__support/FPUtil/FEnvImpl.h +++ b/libc/src/__support/FPUtil/FEnvImpl.h @@ -12,12 +12,15 @@ #include "src/__support/architectures.h" #if defined(LLVM_LIBC_ARCH_AARCH64) +#if defined(__APPLE__) +#include "aarch64/fenv_darwin_impl.h" +#else #include "aarch64/FEnvImpl.h" +#endif #elif defined(LLVM_LIBC_ARCH_X86) #include "x86_64/FEnvImpl.h" #else #include -#include namespace __llvm_libc { namespace fputil { diff --git a/libc/src/__support/FPUtil/NearestIntegerOperations.h b/libc/src/__support/FPUtil/NearestIntegerOperations.h --- a/libc/src/__support/FPUtil/NearestIntegerOperations.h +++ b/libc/src/__support/FPUtil/NearestIntegerOperations.h @@ -14,10 +14,8 @@ #include "src/__support/CPP/TypeTraits.h" -#include -#if math_errhandling & MATH_ERRNO #include -#endif +#include namespace __llvm_libc { namespace fputil { @@ -245,12 +243,10 @@ constexpr I INTEGER_MAX = -(INTEGER_MIN + 1); FPBits bits(x); auto set_domain_error_and_raise_invalid = []() { -#if math_errhandling & MATH_ERRNO - errno = EDOM; -#endif -#if math_errhandling & MATH_ERREXCEPT - raise_except(FE_INVALID); -#endif + if (math_errhandling & MATH_ERRNO) + errno = EDOM; + if (math_errhandling & MATH_ERREXCEPT) + raise_except(FE_INVALID); }; if (bits.is_inf_or_nan()) { diff --git a/libc/src/__support/FPUtil/aarch64/FEnvImpl.h b/libc/src/__support/FPUtil/aarch64/FEnvImpl.h --- a/libc/src/__support/FPUtil/aarch64/FEnvImpl.h +++ b/libc/src/__support/FPUtil/aarch64/FEnvImpl.h @@ -11,7 +11,7 @@ #include "src/__support/architectures.h" -#if !defined(LLVM_LIBC_ARCH_AARCH64) +#if !defined(LLVM_LIBC_ARCH_AARCH64) || defined(__APPLE__) #error "Invalid include" #endif diff --git a/libc/src/__support/FPUtil/aarch64/fenv_darwin_impl.h b/libc/src/__support/FPUtil/aarch64/fenv_darwin_impl.h new file mode 100644 --- /dev/null +++ b/libc/src/__support/FPUtil/aarch64/fenv_darwin_impl.h @@ -0,0 +1,283 @@ +//===- darwin-aarch64 floating point env manipulation 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SUPPORT_FPUTIL_AARCH64_FENV_DARWIN_IMPL_H +#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_AARCH64_FENV_DARWIN_IMPL_H + +#include "src/__support/architectures.h" + +#if !defined(LLVM_LIBC_ARCH_AARCH64) || !defined(__APPLE__) +#error "Invalid include" +#endif + +#include +#include +#include + +#include "src/__support/FPUtil/FPBits.h" + +namespace __llvm_libc { +namespace fputil { + +struct FEnv { + struct FPState { + uint64_t StatusWord; + uint64_t ControlWord; + }; + + static_assert( + sizeof(fenv_t) == sizeof(FPState), + "Internal floating point state does not match the public fenv_t type."); + + static constexpr uint32_t TONEAREST = 0x0; + static constexpr uint32_t UPWARD = 0x1; + static constexpr uint32_t DOWNWARD = 0x2; + static constexpr uint32_t TOWARDZERO = 0x3; + + // These will be the exception flags we use for exception values normalized + // from both status word and control word. + // We add EX_ prefix to the names since macOS defines OVERFLOW and + // UNDERFLOW macros. + static constexpr uint32_t EX_INVALID = 0x1; + static constexpr uint32_t EX_DIVBYZERO = 0x2; + static constexpr uint32_t EX_OVERFLOW = 0x4; + static constexpr uint32_t EX_UNDERFLOW = 0x8; + static constexpr uint32_t EX_INEXACT = 0x10; + // __APPLE__ ARM64 has an extra flag that is raised when a denormal is flushed + // to zero. + static constexpr uint32_t EX_FLUSHTOZERO = 0x20; + + // Zero-th bit is the first bit. + static constexpr uint32_t ROUNDING_CONTROL_BIT_POSITION = 22; + + // In addition to the 5 floating point exceptions, macOS on arm64 defines + // another floating point exception: FE_FLUSHTOZERO, which is controlled by + // __fpcr_flush_to_zero bit in the FPCR register. This control bit is + // located in a different place from FE_FLUSHTOZERO status bit relative to + // the other exceptions. + static inline 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); + } + + static inline 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); + } + + static inline 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); + } + + static inline 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); + } + + static uint32_t get_control_word() { return __arm_rsr("fpcr"); } + + static void set_control_word(uint32_t fpcr) { __arm_wsr("fpcr", fpcr); } + + static uint32_t get_status_word() { return __arm_rsr("fpsr"); } + + static void set_status_word(uint32_t fpsr) { __arm_wsr("fpsr", fpsr); } +}; + +static inline int enable_except(int excepts) { + uint32_t new_excepts = FEnv::exception_value_from_status(excepts); + uint32_t control_word = FEnv::get_control_word(); + uint32_t old_excepts = FEnv::exception_value_from_control(control_word); + if (new_excepts != old_excepts) { + control_word |= FEnv::exception_value_to_control(new_excepts); + FEnv::set_control_word(control_word); + } + return FEnv::exception_value_to_status(old_excepts); +} + +static inline int disable_except(int excepts) { + uint32_t disabled_excepts = FEnv::exception_value_from_status(excepts); + uint32_t control_word = FEnv::get_control_word(); + uint32_t old_excepts = FEnv::exception_value_from_control(control_word); + control_word &= ~FEnv::exception_value_to_control(disabled_excepts); + FEnv::set_control_word(control_word); + return FEnv::exception_value_to_status(old_excepts); +} + +static inline int get_except() { + uint32_t control_word = FEnv::get_control_word(); + uint32_t enabled_excepts = FEnv::exception_value_from_control(control_word); + return FEnv::exception_value_to_status(enabled_excepts); +} + +static inline int clear_except(int excepts) { + uint32_t status_word = FEnv::get_status_word(); + uint32_t except_value = FEnv::exception_value_from_status(excepts); + status_word &= ~FEnv::exception_value_to_status(except_value); + FEnv::set_status_word(status_word); + return 0; +} + +static inline int test_except(int excepts) { + uint32_t statusWord = FEnv::get_status_word(); + uint32_t ex_value = FEnv::exception_value_from_status(excepts); + return statusWord & FEnv::exception_value_to_status(ex_value); +} + +static inline int set_except(int excepts) { + uint32_t status_word = FEnv::get_status_word(); + uint32_t new_exceptions = FEnv::exception_value_from_status(excepts); + status_word |= FEnv::exception_value_to_status(new_exceptions); + FEnv::set_status_word(status_word); + return 0; +} + +static inline int raise_except(int excepts) { + float zero = 0.0f; + float one = 1.0f; + float large_value = float(FPBits(FPBits::MAX_NORMAL)); + float small_value = float(FPBits(FPBits::MIN_NORMAL)); + auto divfunc = [](float a, float b) { + __asm__ __volatile__("ldr s0, %0\n\t" + "ldr s1, %1\n\t" + "fdiv s0, s0, s1\n\t" + : // No outputs + : "m"(a), "m"(b) + : "s0", "s1" /* s0 and s1 are clobbered */); + }; + + uint32_t to_raise = FEnv::exception_value_from_status(excepts); + int result = 0; + + if (to_raise & FEnv::EX_INVALID) { + divfunc(zero, zero); + uint32_t status_word = FEnv::get_status_word(); + if (!(FEnv::exception_value_from_status(status_word) & FEnv::EX_INVALID)) + result = -1; + } + + if (to_raise & FEnv::EX_DIVBYZERO) { + divfunc(one, zero); + uint32_t status_word = FEnv::get_status_word(); + if (!(FEnv::exception_value_from_status(status_word) & FEnv::EX_DIVBYZERO)) + result = -1; + } + if (to_raise & FEnv::EX_OVERFLOW) { + divfunc(large_value, small_value); + uint32_t status_word = FEnv::get_status_word(); + if (!(FEnv::exception_value_from_status(status_word) & FEnv::EX_OVERFLOW)) + result = -1; + } + if (to_raise & FEnv::EX_UNDERFLOW) { + divfunc(small_value, large_value); + uint32_t status_word = FEnv::get_status_word(); + if (!(FEnv::exception_value_from_status(status_word) & FEnv::EX_UNDERFLOW)) + result = -1; + } + if (to_raise & FEnv::EX_INEXACT) { + float two = 2.0f; + float three = 3.0f; + // 2.0 / 3.0 cannot be represented exactly in any radix 2 floating point + // format. + divfunc(two, three); + uint32_t status_word = FEnv::get_status_word(); + if (!(FEnv::exception_value_from_status(status_word) & FEnv::EX_INEXACT)) + result = -1; + } + if (to_raise & FEnv::EX_FLUSHTOZERO) { + // TODO: raise the flush to zero floating point exception. + result = -1; + } + return result; +} + +static inline int get_round() { + uint32_t rounding_mode = + (FEnv::get_control_word() >> FEnv::ROUNDING_CONTROL_BIT_POSITION) & 0x3; + switch (rounding_mode) { + case FEnv::TONEAREST: + return FE_TONEAREST; + case FEnv::DOWNWARD: + return FE_DOWNWARD; + case FEnv::UPWARD: + return FE_UPWARD; + case FEnv::TOWARDZERO: + return FE_TOWARDZERO; + default: + return -1; // Error value. + } +} + +static inline int set_round(int mode) { + uint16_t bit_value; + switch (mode) { + case FE_TONEAREST: + bit_value = FEnv::TONEAREST; + break; + case FE_DOWNWARD: + bit_value = FEnv::DOWNWARD; + break; + case FE_UPWARD: + bit_value = FEnv::UPWARD; + break; + case FE_TOWARDZERO: + bit_value = FEnv::TOWARDZERO; + break; + default: + return 1; // To indicate failure + } + + uint32_t control_word = FEnv::get_control_word(); + control_word &= ~(0x3 << FEnv::ROUNDING_CONTROL_BIT_POSITION); + control_word |= (bit_value << FEnv::ROUNDING_CONTROL_BIT_POSITION); + FEnv::set_control_word(control_word); + + return 0; +} + +static inline int get_env(fenv_t *envp) { + FEnv::FPState *state = reinterpret_cast(envp); + state->ControlWord = FEnv::get_control_word(); + state->StatusWord = FEnv::get_status_word(); + return 0; +} + +static inline int set_env(const fenv_t *envp) { + if (envp == FE_DFL_ENV) { + // Default status and control words bits are all zeros so we just + // write zeros. + FEnv::set_status_word(0); + FEnv::set_control_word(0); + return 0; + } + const FEnv::FPState *state = reinterpret_cast(envp); + FEnv::set_control_word(state->ControlWord); + FEnv::set_status_word(state->StatusWord); + return 0; +} + +} // namespace fputil +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SUPPORT_FPUTIL_AARCH64_FENV_DARWIN_IMPL_H diff --git a/libc/src/__support/common.h b/libc/src/__support/common.h --- a/libc/src/__support/common.h +++ b/libc/src/__support/common.h @@ -19,7 +19,8 @@ #define LLVM_LIBC_FUNCTION_ATTR #endif -#ifdef LLVM_LIBC_PUBLIC_PACKAGING +// MacOS needs to be excluded because it does not support aliasing. +#if defined(LLVM_LIBC_PUBLIC_PACKAGING) && (!defined(__APPLE__)) #define LLVM_LIBC_FUNCTION(type, name, arglist) \ LLVM_LIBC_FUNCTION_ATTR decltype(__llvm_libc::name) \ __##name##_impl__ __asm__(#name); \ diff --git a/libc/src/__support/str_to_float.h b/libc/src/__support/str_to_float.h --- a/libc/src/__support/str_to_float.h +++ b/libc/src/__support/str_to_float.h @@ -458,8 +458,9 @@ #if defined(LONG_DOUBLE_IS_DOUBLE) template <> class ClingerConsts { public: - static constexpr long double POWERS_OF_TEN_ARRAY[] = - ClingerConsts::POWERS_OF_TEN_ARRAY; + static constexpr long double POWERS_OF_TEN_ARRAY[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, + 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; static constexpr int32_t EXACT_POWERS_OF_TEN = ClingerConsts::EXACT_POWERS_OF_TEN; static constexpr int32_t DIGITS_IN_MANTISSA = diff --git a/libc/test/src/fenv/CMakeLists.txt b/libc/test/src/fenv/CMakeLists.txt --- a/libc/test/src/fenv/CMakeLists.txt +++ b/libc/test/src/fenv/CMakeLists.txt @@ -85,11 +85,13 @@ libc.src.fenv.fegetexcept ) -if (NOT (LLVM_USE_SANITIZER OR (${LIBC_TARGET_OS} STREQUAL "windows"))) +if (NOT (LLVM_USE_SANITIZER OR (${LIBC_TARGET_OS} STREQUAL "windows") + OR (${LIBC_TARGET_OS} STREQUAL "darwin"))) # Sanitizers don't like SIGFPE. So, we will run the # tests which raise SIGFPE only in non-sanitizer builds. - # The tests are also disabled for Windows as they fail currently. - # TODO: Investigate and fix the windows failures and enable them for Windows. + # The tests are also disabled for Windows and MacOS as they fail currently. + # TODO: Investigate and fix the windows failures and enable them for Windows + # and MacOS. add_fp_unittest( enabled_exceptions_test SUITE diff --git a/libc/test/src/math/RoundToIntegerTest.h b/libc/test/src/math/RoundToIntegerTest.h --- a/libc/test/src/math/RoundToIntegerTest.h +++ b/libc/test/src/math/RoundToIntegerTest.h @@ -73,12 +73,12 @@ public: void SetUp() override { -#if math_errhandling & MATH_ERREXCEPT - // We will disable all exceptions so that the test will not - // crash with SIGFPE. We can still use fetestexcept to check - // if the appropriate flag was raised. - __llvm_libc::fputil::disable_except(FE_ALL_EXCEPT); -#endif + if (math_errhandling & MATH_ERREXCEPT) { + // We will disable all exceptions so that the test will not + // crash with SIGFPE. We can still use fetestexcept to check + // if the appropriate flag was raised. + __llvm_libc::fputil::disable_except(FE_ALL_EXCEPT); + } } void do_infinity_and_na_n_test(RoundToIntegerFunc func) { diff --git a/libc/test/src/stdlib/strtold_test.cpp b/libc/test/src/stdlib/strtold_test.cpp --- a/libc/test/src/stdlib/strtold_test.cpp +++ b/libc/test/src/stdlib/strtold_test.cpp @@ -175,12 +175,12 @@ TEST_F(LlvmLibcStrToLDTest, ComplexHexadecimalTests) { run_test("0x1p16383", 9, 0x7ff0000000000000, (__uint128_t(0x7ffe800000) << 40), - (__uint128_t(0x7ffe000000000000) << 64)); + (__uint128_t(0x7ffe000000000000) << 64), ERANGE); run_test("0x123456789abcdef", 17, 0x43723456789abcdf, (__uint128_t(0x403791a2b3) << 40) + __uint128_t(0xc4d5e6f780), (__uint128_t(0x403723456789abcd) << 64) + __uint128_t(0xef00000000000000)); - run_test("0x123456789abcdef0123456789ABCDEF", 33, 0x7ff0000000000000, + run_test("0x123456789abcdef0123456789ABCDEF", 33, 0x47723456789abcdf, (__uint128_t(0x407791a2b3) << 40) + __uint128_t(0xc4d5e6f781), (__uint128_t(0x407723456789abcd) << 64) + __uint128_t(0xef0123456789abce));