llvm-libc: update to LLVM 22

This commit is contained in:
Alex Rønne Petersen 2026-01-17 05:48:20 +01:00
parent e5ede37983
commit 1576e4181c
No known key found for this signature in database
37 changed files with 1542 additions and 281 deletions

278
lib/libcxx/libc/LICENSE.TXT vendored Normal file
View file

@ -0,0 +1,278 @@
==============================================================================
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
==============================================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.
==============================================================================
Software from third parties included in the LLVM Project:
==============================================================================
The LLVM Project contains third party software which is under different license
terms. All such code will be identified clearly using at least one of two
mechanisms:
1) It will be in a separate directory tree with its own `LICENSE.txt` or
`LICENSE` file at the top containing the specific license and restrictions
which apply to that software, or
2) It will contain specific license and restriction terms at the top of every
file.
==============================================================================
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 2007-2019 University of Illinois at Urbana-Champaign.
All rights reserved.
Developed by:
LLVM Team
University of Illinois at Urbana-Champaign
http://llvm.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLVM Team, University of Illinois at
Urbana-Champaign, nor the names of its contributors may be used to
endorse or promote products derived from this Software without specific
prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.

View file

@ -15,7 +15,9 @@
#include <linux/errno.h>
#include "include/llvm-libc-macros/error-number-macros.h"
#else // __linux__
#elif defined(__APPLE__)
#include <sys/errno.h>
#else // __APPLE__
#include "include/llvm-libc-macros/generic-error-number-macros.h"
#endif

18
lib/libcxx/libc/hdr/stdint_proxy.h vendored Normal file
View file

@ -0,0 +1,18 @@
//===-- stdint.h ----------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_STDINT_PROXY_H
#define LLVM_LIBC_HDR_STDINT_PROXY_H
// This target is to make sure we have correct build order in full build mode,
// that is `libc.include.stdint` is added to the dependency of all targets
// that use <stdint.h> header.
#include <stdint.h>
#endif // LLVM_LIBC_HDR_STDINT_PROXY_H

23
lib/libcxx/libc/hdr/types/wchar_t.h vendored Normal file
View file

@ -0,0 +1,23 @@
//===-- Definition of wchar_t.h -------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_TYPES_WCHAR_T_H
#define LLVM_LIBC_HDR_TYPES_WCHAR_T_H
#ifdef LIBC_FULL_BUILD
#include "include/llvm-libc-types/wchar_t.h"
#else // overlay mode
#include "hdr/wchar_overlay.h"
#endif // LLVM_LIBC_FULL_BUILD
#endif // LLVM_LIBC_HDR_TYPES_WCHAR_T_H

69
lib/libcxx/libc/hdr/wchar_overlay.h vendored Normal file
View file

@ -0,0 +1,69 @@
//===-- Including wchar.h in overlay mode ---------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_WCHAR_OVERLAY_H
#define LLVM_LIBC_HDR_WCHAR_OVERLAY_H
#ifdef LIBC_FULL_BUILD
#error "This header should only be included in overlay mode"
#endif
// Overlay mode
// glibc <wchar.h> header might provide extern inline definitions for few
// functions, causing external alias errors. They are guarded by
// `__USE_EXTERN_INLINES` macro. We temporarily disable `__USE_EXTERN_INLINES`
// macro by defining `__NO_INLINE__` before including <wchar.h>.
// And the same with `__USE_FORTIFY_LEVEL`, which will be temporarily disabled
// with `_FORTIFY_SOURCE`.
#ifdef _FORTIFY_SOURCE
#define LIBC_OLD_FORTIFY_SOURCE _FORTIFY_SOURCE
#undef _FORTIFY_SOURCE
#endif
#ifndef __NO_INLINE__
#define __NO_INLINE__ 1
#define LIBC_SET_NO_INLINE
#endif
#ifdef __USE_EXTERN_INLINES
#define LIBC_OLD_USE_EXTERN_INLINES
#undef __USE_EXTERN_INLINES
#endif
#ifdef __USE_FORTIFY_LEVEL
#define LIBC_OLD_USE_FORTIFY_LEVEL __USE_FORTIFY_LEVEL
#undef __USE_FORTIFY_LEVEL
#define __USE_FORTIFY_LEVEL 0
#endif
#include <wchar.h>
#ifdef LIBC_OLD_FORTIFY_SOURCE
#define _FORTIFY_SOURCE LIBC_OLD_FORTIFY_SOURCE
#undef LIBC_OLD_FORTIFY_SOURCE
#endif
#ifdef LIBC_SET_NO_INLINE
#undef __NO_INLINE__
#undef LIBC_SET_NO_INLINE
#endif
#ifdef LIBC_OLD_USE_FORTIFY_LEVEL
#undef __USE_FORTIFY_LEVEL
#define __USE_FORTIFY_LEVEL LIBC_OLD_USE_FORTIFY_LEVEL
#undef LIBC_OLD_USE_FORTIFY_LEVEL
#endif
#ifdef LIBC_OLD_USE_EXTERN_INLINES
#define __USE_EXTERN_INLINES
#undef LIBC_OLD_USE_EXTERN_INLINES
#endif
#endif // LLVM_LIBC_HDR_WCHAR_OVERLAY_H

View file

@ -0,0 +1,41 @@
//===-- Detection of _Complex _Float128 compiler builtin type -------------===//
//
// 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_MACROS_CFLOAT128_MACROS_H
#define LLVM_LIBC_MACROS_CFLOAT128_MACROS_H
#include "float-macros.h" // LDBL_MANT_DIG
// Currently, the complex variant of C23 `_Float128` type is only defined as a
// built-in type in GCC 7 or later, for C and in GCC 13 or later, for C++. For
// clang, the complex variant of `__float128` is defined instead, and only on
// x86-64 targets for clang 11 or later.
//
// TODO: Update the complex variant of C23 `_Float128` type detection again when
// clang supports it.
#ifdef __clang__
#if (__clang_major__ >= 11) && \
(defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__))
// Use _Complex __float128 type. clang uses __SIZEOF_FLOAT128__ or __FLOAT128__
// macro to notify the availability of __float128 type:
// https://reviews.llvm.org/D15120
#define LIBC_TYPES_HAS_CFLOAT128
#endif
#elif defined(__GNUC__)
#if (defined(__STDC_IEC_60559_COMPLEX__) || defined(__SIZEOF_FLOAT128__)) && \
(__GNUC__ >= 13 || (!defined(__cplusplus)))
#define LIBC_TYPES_HAS_CFLOAT128
#endif
#endif
#if !defined(LIBC_TYPES_HAS_CFLOAT128) && (LDBL_MANT_DIG == 113)
#define LIBC_TYPES_HAS_CFLOAT128
#define LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
#endif
#endif // LLVM_LIBC_MACROS_CFLOAT128_MACROS_H

View file

@ -0,0 +1,20 @@
//===-- Detection of _Complex _Float16 compiler builtin type --------------===//
//
// 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_MACROS_CFLOAT16_MACROS_H
#define LLVM_LIBC_MACROS_CFLOAT16_MACROS_H
#if defined(__FLT16_MANT_DIG__) && \
(!defined(__GNUC__) || __GNUC__ >= 13 || \
(defined(__clang__) && __clang_major__ >= 14)) && \
!defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \
!defined(_WIN32)
#define LIBC_TYPES_HAS_CFLOAT16
#endif
#endif // LLVM_LIBC_MACROS_CFLOAT16_MACROS_H

View file

@ -9,36 +9,19 @@
#ifndef LLVM_LIBC_TYPES_CFLOAT128_H
#define LLVM_LIBC_TYPES_CFLOAT128_H
#include "../llvm-libc-macros/float-macros.h" // LDBL_MANT_DIG
#include "../llvm-libc-macros/cfloat128-macros.h"
// Currently, the complex variant of C23 `_Float128` type is only defined as a
// built-in type in GCC 7 or later, for C and in GCC 13 or later, for C++. For
// clang, the complex variant of `__float128` is defined instead, and only on
// x86-64 targets for clang 11 or later.
//
// TODO: Update the complex variant of C23 `_Float128` type detection again when
// clang supports it.
#ifdef __clang__
#if (__clang_major__ >= 11) && \
(defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__))
// Use _Complex __float128 type. clang uses __SIZEOF_FLOAT128__ or __FLOAT128__
// macro to notify the availability of __float128 type:
// https://reviews.llvm.org/D15120
#define LIBC_TYPES_HAS_CFLOAT128
#ifdef LIBC_TYPES_HAS_CFLOAT128
#ifndef LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
#if defined(__GNUC__) && !defined(__clang__)
// Remove the workaround when https://gcc.gnu.org/PR32187 gets fixed.
typedef __typeof__(_Complex __float128) cfloat128;
#else // ^^^ workaround / no workaround vvv
typedef _Complex __float128 cfloat128;
#endif
#elif defined(__GNUC__)
#if (defined(__STDC_IEC_60559_COMPLEX__) || defined(__SIZEOF_FLOAT128__)) && \
(__GNUC__ >= 13 || (!defined(__cplusplus)))
#define LIBC_TYPES_HAS_CFLOAT128
typedef _Complex _Float128 cfloat128;
#endif
#endif
#if !defined(LIBC_TYPES_HAS_CFLOAT128) && (LDBL_MANT_DIG == 113)
#define LIBC_TYPES_HAS_CFLOAT128
#define LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
#endif // ^^^ no workaround ^^^
#else
typedef _Complex long double cfloat128;
#endif
#endif // LIBC_TYPES_CFLOAT128_IS_COMPLEX_LONG_DOUBLE
#endif // LIBC_TYPES_HAS_CFLOAT128
#endif // LLVM_LIBC_TYPES_CFLOAT128_H

View file

@ -9,13 +9,10 @@
#ifndef LLVM_LIBC_TYPES_CFLOAT16_H
#define LLVM_LIBC_TYPES_CFLOAT16_H
#if defined(__FLT16_MANT_DIG__) && \
(!defined(__GNUC__) || __GNUC__ >= 13 || \
(defined(__clang__) && __clang_major__ >= 14)) && \
!defined(__arm__) && !defined(_M_ARM) && !defined(__riscv) && \
!defined(_WIN32)
#define LIBC_TYPES_HAS_CFLOAT16
#include "../llvm-libc-macros/cfloat16-macros.h"
#ifdef LIBC_TYPES_HAS_CFLOAT16
typedef _Complex _Float16 cfloat16;
#endif
#endif // LIBC_TYPES_HAS_CFLOAT16
#endif // LLVM_LIBC_TYPES_CFLOAT16_H

View file

@ -0,0 +1,19 @@
//===-- Definition of wchar_t types ---------------------------------------===//
//
// 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_TYPES_WCHAR_T_H
#define LLVM_LIBC_TYPES_WCHAR_T_H
// wchar_t is a fundamental type in C++.
#ifndef __cplusplus
typedef __WCHAR_TYPE__ wchar_t;
#endif
#endif // LLVM_LIBC_TYPES_WCHAR_T_H

View file

@ -19,6 +19,11 @@
#define LIBC_ERRNO_MODE LIBC_ERRNO_MODE_SYSTEM_INLINE
#endif // LIBC_ERRNO_MODE
// Use system fenv functions in math implementations.
#ifndef LIBC_MATH_USE_SYSTEM_FENV
#define LIBC_MATH_USE_SYSTEM_FENV
#endif // LIBC_MATH_USE_SYSTEM_FENV
#ifndef LIBC_NAMESPACE
#define LIBC_NAMESPACE __llvm_libc
#endif // LIBC_NAMESPACE

View file

@ -11,14 +11,14 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_BIT_H
#include "hdr/stdint_proxy.h"
#include "src/__support/CPP/limits.h" // numeric_limits
#include "src/__support/CPP/type_traits.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/compiler.h"
#include "src/__support/macros/sanitizer.h"
#include <stdint.h>
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
@ -26,6 +26,16 @@ namespace cpp {
#define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE
#endif
template <unsigned N>
LIBC_INLINE static void inline_copy(const char *from, char *to) {
#if __has_builtin(__builtin_memcpy_inline)
__builtin_memcpy_inline(to, from, N);
#else
for (unsigned i = 0; i < N; ++i)
to[i] = from[i];
#endif // __has_builtin(__builtin_memcpy_inline)
}
// This implementation of bit_cast requires trivially-constructible To, to avoid
// UB in the implementation.
template <typename To, typename From>
@ -37,22 +47,32 @@ LIBC_INLINE constexpr cpp::enable_if_t<
To>
bit_cast(const From &from) {
MSAN_UNPOISON(&from, sizeof(From));
#if __has_builtin(__builtin_bit_cast)
#if __has_builtin(__builtin_bit_cast) || defined(LIBC_COMPILER_IS_MSVC)
return __builtin_bit_cast(To, from);
#else
To to;
To to{};
char *dst = reinterpret_cast<char *>(&to);
const char *src = reinterpret_cast<const char *>(&from);
#if __has_builtin(__builtin_memcpy_inline)
__builtin_memcpy_inline(dst, src, sizeof(To));
#else
for (unsigned i = 0; i < sizeof(To); ++i)
dst[i] = src[i];
#endif // __has_builtin(__builtin_memcpy_inline)
inline_copy<sizeof(From)>(src, dst);
return to;
#endif // __has_builtin(__builtin_bit_cast)
}
// The following simple bit copy from a smaller type to maybe-larger type.
template <typename To, typename From>
LIBC_INLINE constexpr cpp::enable_if_t<
(sizeof(To) >= sizeof(From)) &&
cpp::is_trivially_constructible<To>::value &&
cpp::is_trivially_copyable<To>::value &&
cpp::is_trivially_copyable<From>::value,
void>
bit_copy(const From &from, To &to) {
MSAN_UNPOISON(&from, sizeof(From));
char *dst = reinterpret_cast<char *>(&to);
const char *src = reinterpret_cast<const char *>(&from);
inline_copy<sizeof(From)>(src, dst);
}
template <typename T>
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>,
bool>
@ -105,10 +125,16 @@ countr_zero(T value) {
}
#if __has_builtin(__builtin_ctzs)
ADD_SPECIALIZATION(countr_zero, unsigned short, __builtin_ctzs)
#endif
#endif // __has_builtin(__builtin_ctzs)
#if __has_builtin(__builtin_ctz)
ADD_SPECIALIZATION(countr_zero, unsigned int, __builtin_ctz)
#endif // __has_builtin(__builtin_ctz)
#if __has_builtin(__builtin_ctzl)
ADD_SPECIALIZATION(countr_zero, unsigned long, __builtin_ctzl)
#endif // __has_builtin(__builtin_ctzl)
#if __has_builtin(__builtin_ctzll)
ADD_SPECIALIZATION(countr_zero, unsigned long long, __builtin_ctzll)
#endif // __has_builtin(__builtin_ctzll)
#endif // __has_builtin(__builtin_ctzg)
/// Count number of 0's from the most significant bit to the least
@ -144,10 +170,16 @@ countl_zero(T value) {
}
#if __has_builtin(__builtin_clzs)
ADD_SPECIALIZATION(countl_zero, unsigned short, __builtin_clzs)
#endif
#endif // __has_builtin(__builtin_clzs)
#if __has_builtin(__builtin_clz)
ADD_SPECIALIZATION(countl_zero, unsigned int, __builtin_clz)
#endif // __has_builtin(__builtin_clz)
#if __has_builtin(__builtin_clzl)
ADD_SPECIALIZATION(countl_zero, unsigned long, __builtin_clzl)
#endif // __has_builtin(__builtin_clzl)
#if __has_builtin(__builtin_clzll)
ADD_SPECIALIZATION(countl_zero, unsigned long long, __builtin_clzll)
#endif // __has_builtin(__builtin_clzll)
#endif // __has_builtin(__builtin_clzg)
#undef ADD_SPECIALIZATION
@ -284,11 +316,17 @@ popcount(T value) {
[[nodiscard]] LIBC_INLINE constexpr int popcount<TYPE>(TYPE value) { \
return BUILTIN(value); \
}
#if __has_builtin(__builtin_popcount)
ADD_SPECIALIZATION(unsigned char, __builtin_popcount)
ADD_SPECIALIZATION(unsigned short, __builtin_popcount)
ADD_SPECIALIZATION(unsigned, __builtin_popcount)
#endif // __builtin_popcount
#if __has_builtin(__builtin_popcountl)
ADD_SPECIALIZATION(unsigned long, __builtin_popcountl)
#endif // __builtin_popcountl
#if __has_builtin(__builtin_popcountll)
ADD_SPECIALIZATION(unsigned long long, __builtin_popcountll)
#endif // __builtin_popcountll
#endif // __builtin_popcountg
#undef ADD_SPECIALIZATION

View file

@ -13,12 +13,17 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
// LIBC_TYPES_HAS_CFLOAT16 && LIBC_TYPES_HAS_CFLOAT128
#include "src/__support/macros/properties/compiler.h"
#include "src/__support/macros/properties/complex_types.h"
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
// is_complex
#ifdef LIBC_COMPILER_IS_MSVC
// TODO: Add support for complex types with MSVC.
template <typename T> struct is_complex : false_type {};
#else
template <typename T> struct is_complex {
private:
template <typename Head, typename... Args>
@ -40,6 +45,8 @@ public:
#endif
>();
};
#endif // LIBC_COMPILER_IS_MSVC
template <typename T>
LIBC_INLINE_VAR constexpr bool is_complex_v = is_complex<T>::value;
template <typename T1, typename T2>

View file

@ -15,6 +15,7 @@
#include "src/__support/CPP/type_traits/remove_all_extents.h"
#include "src/__support/CPP/type_traits/true_type.h"
#include "src/__support/CPP/type_traits/type_identity.h"
#include "src/__support/CPP/utility/declval.h"
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
@ -22,7 +23,7 @@ namespace LIBC_NAMESPACE_DECL {
namespace cpp {
// is_destructible
#if __has_builtin(__is_destructible)
#if __has_builtin(__is_destructible) || defined(LIBC_COMPILER_IS_MSVC)
template <typename T>
struct is_destructible : bool_constant<__is_destructible(T)> {};
#else

View file

@ -16,6 +16,8 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
@ -46,6 +48,10 @@ public:
LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; }
};
#endif // LIBC_COMPILER_HAS_FIXED_POINT
#if LIBC_HAS_VECTOR_TYPE
template <typename T, size_t N>
struct is_unsigned<T [[clang::ext_vector_type(N)]]> : bool_constant<false> {};
#endif
template <typename T>
LIBC_INLINE_VAR constexpr bool is_unsigned_v = is_unsigned<T>::value;

View file

@ -5,12 +5,15 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H
#define LLVM_LIBC_SRC___SUPPORT_CPP_UTILITY_INTEGER_SEQUENCE_H
#include "src/__support/CPP/type_traits/is_integral.h"
#include "src/__support/macros/config.h"
#include <stddef.h>
namespace LIBC_NAMESPACE_DECL {
namespace cpp {
@ -34,6 +37,13 @@ template <typename T, int N>
using make_integer_sequence =
typename detail::make_integer_sequence<T, N - 1>::type;
// index sequence
template <size_t... Ints>
using index_sequence = integer_sequence<size_t, Ints...>;
template <int N>
using make_index_sequence =
typename detail::make_integer_sequence<size_t, N - 1>::type;
} // namespace cpp
} // namespace LIBC_NAMESPACE_DECL

View file

@ -15,6 +15,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_FPBITS_H
#include "hdr/stdint_proxy.h"
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/common.h"
@ -26,8 +27,6 @@
#include "src/__support/sign.h" // Sign
#include "src/__support/uint128.h"
#include <stdint.h>
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
@ -790,16 +789,16 @@ struct FPRep : public FPRepImpl<fp_type, FPRep<fp_type>> {
// Returns the FPType corresponding to C++ type T on the host.
template <typename T> LIBC_INLINE static constexpr FPType get_fp_type() {
using UnqualT = cpp::remove_cv_t<T>;
if constexpr (cpp::is_same_v<UnqualT, float> && __FLT_MANT_DIG__ == 24)
if constexpr (cpp::is_same_v<UnqualT, float> && FLT_MANT_DIG == 24)
return FPType::IEEE754_Binary32;
else if constexpr (cpp::is_same_v<UnqualT, double> && __DBL_MANT_DIG__ == 53)
else if constexpr (cpp::is_same_v<UnqualT, double> && DBL_MANT_DIG == 53)
return FPType::IEEE754_Binary64;
else if constexpr (cpp::is_same_v<UnqualT, long double>) {
if constexpr (__LDBL_MANT_DIG__ == 53)
if constexpr (LDBL_MANT_DIG == 53)
return FPType::IEEE754_Binary64;
else if constexpr (__LDBL_MANT_DIG__ == 64)
else if constexpr (LDBL_MANT_DIG == 64)
return FPType::X86_Binary80;
else if constexpr (__LDBL_MANT_DIG__ == 113)
else if constexpr (LDBL_MANT_DIG == 113)
return FPType::IEEE754_Binary128;
}
#if defined(LIBC_TYPES_HAS_FLOAT16)

View file

@ -10,18 +10,21 @@
#define LLVM_LIBC_SRC___SUPPORT_FPUTIL_ROUNDING_MODE_H
#include "hdr/fenv_macros.h"
#include "src/__support/CPP/type_traits.h" // is_constant_evaluated
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
namespace fputil {
namespace generic {
// Quick free-standing test whether fegetround() == FE_UPWARD.
// Using the following observation:
// 1.0f + 2^-25 = 1.0f for FE_TONEAREST, FE_DOWNWARD, FE_TOWARDZERO
// = 0x1.000002f for FE_UPWARD.
LIBC_INLINE bool fenv_is_round_up() {
volatile float x = 0x1.0p-25f;
static volatile float x = 0x1.0p-25f;
return (1.0f + x != 1.0f);
}
@ -30,7 +33,7 @@ LIBC_INLINE bool fenv_is_round_up() {
// -1.0f - 2^-25 = -1.0f for FE_TONEAREST, FE_UPWARD, FE_TOWARDZERO
// = -0x1.000002f for FE_DOWNWARD.
LIBC_INLINE bool fenv_is_round_down() {
volatile float x = 0x1.0p-25f;
static volatile float x = 0x1.0p-25f;
return (-1.0f - x != -1.0f);
}
@ -42,8 +45,8 @@ LIBC_INLINE bool fenv_is_round_down() {
// = 0x1.0ffffep-1f for FE_DOWNWARD, FE_TOWARDZERO
LIBC_INLINE bool fenv_is_round_to_nearest() {
static volatile float x = 0x1.0p-24f;
float y = x;
return (1.5f + y == 1.5f - y);
float y = 1.5f + x;
return (y == 1.5f - x);
}
// Quick free-standing test whether fegetround() == FE_TOWARDZERO.
@ -75,6 +78,49 @@ LIBC_INLINE int quick_get_round() {
return (2.0f + y == 2.0f) ? FE_TONEAREST : FE_UPWARD;
}
} // namespace generic
LIBC_INLINE static constexpr bool fenv_is_round_up() {
if (cpp::is_constant_evaluated()) {
return false;
} else {
return generic::fenv_is_round_up();
}
}
LIBC_INLINE static constexpr bool fenv_is_round_down() {
if (cpp::is_constant_evaluated()) {
return false;
} else {
return generic::fenv_is_round_down();
}
}
LIBC_INLINE static constexpr bool fenv_is_round_to_nearest() {
if (cpp::is_constant_evaluated()) {
return true;
} else {
return generic::fenv_is_round_to_nearest();
}
}
LIBC_INLINE static constexpr bool fenv_is_round_to_zero() {
if (cpp::is_constant_evaluated()) {
return false;
} else {
return generic::fenv_is_round_to_zero();
}
}
// Quick free standing get rounding mode based on the above observations.
LIBC_INLINE static constexpr int quick_get_round() {
if (cpp::is_constant_evaluated()) {
return FE_TONEAREST;
} else {
return generic::quick_get_round();
}
}
} // namespace fputil
} // namespace LIBC_NAMESPACE_DECL

View file

@ -9,6 +9,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
#define LLVM_LIBC_SRC___SUPPORT_BIG_INT_H
#include "hdr/stdint_proxy.h"
#include "src/__support/CPP/array.h"
#include "src/__support/CPP/bit.h" // countl_zero
#include "src/__support/CPP/limits.h"
@ -23,7 +24,6 @@
#include "src/__support/number_pair.h"
#include <stddef.h> // For size_t
#include <stdint.h>
namespace LIBC_NAMESPACE_DECL {
@ -95,10 +95,10 @@ LIBC_INLINE constexpr DoubleWide<word> mul2(word a, word b) {
#endif
else {
using half_word = half_width_t<word>;
const auto shiftl = [](word value) -> word {
constexpr auto shiftl = [](word value) -> word {
return value << cpp::numeric_limits<half_word>::digits;
};
const auto shiftr = [](word value) -> word {
constexpr auto shiftr = [](word value) -> word {
return value >> cpp::numeric_limits<half_word>::digits;
};
// Here we do a one digit multiplication where 'a' and 'b' are of type
@ -111,19 +111,19 @@ LIBC_INLINE constexpr DoubleWide<word> mul2(word a, word b) {
// c result
// We convert 'lo' and 'hi' from 'half_word' to 'word' so multiplication
// doesn't overflow.
const word a_lo = lo(a);
const word b_lo = lo(b);
const word a_hi = hi(a);
const word b_hi = hi(b);
const word step1 = b_lo * a_lo; // no overflow;
const word step2 = b_lo * a_hi; // no overflow;
const word step3 = b_hi * a_lo; // no overflow;
const word step4 = b_hi * a_hi; // no overflow;
word a_lo = lo(a);
word b_lo = lo(b);
word a_hi = hi(a);
word b_hi = hi(b);
word step1 = b_lo * a_lo; // no overflow;
word step2 = b_lo * a_hi; // no overflow;
word step3 = b_hi * a_lo; // no overflow;
word step4 = b_hi * a_hi; // no overflow;
word lo_digit = step1;
word hi_digit = step4;
const word no_carry = 0;
word carry;
word _; // unused carry variable.
word no_carry = 0;
word carry = 0;
[[maybe_unused]] word _ = 0; // unused carry variable.
lo_digit = add_with_carry<word>(lo_digit, shiftl(step2), no_carry, carry);
hi_digit = add_with_carry<word>(hi_digit, shiftr(step2), carry, _);
lo_digit = add_with_carry<word>(lo_digit, shiftl(step3), no_carry, carry);

View file

@ -16,6 +16,7 @@
#include "src/__support/macros/attributes.h"
#include "src/__support/macros/config.h"
#include "src/__support/macros/properties/architectures.h"
#include "src/__support/macros/properties/compiler.h"
#ifndef LLVM_LIBC_FUNCTION_ATTR
#define LLVM_LIBC_FUNCTION_ATTR
@ -41,12 +42,12 @@
// to cleanly export and alias the C++ symbol `LIBC_NAMESPACE::func` with the C
// symbol `func`. So for public packaging on MacOS, we will only export the C
// symbol. Moreover, a C symbol `func` in macOS is mangled as `_func`.
#if defined(LIBC_COPT_PUBLIC_PACKAGING)
#if defined(LIBC_COPT_PUBLIC_PACKAGING) && !defined(LIBC_COMPILER_IS_MSVC)
#ifndef __APPLE__
#define LLVM_LIBC_FUNCTION_IMPL(type, name, arglist) \
LLVM_LIBC_ATTR(name) \
LLVM_LIBC_FUNCTION_ATTR decltype(LIBC_NAMESPACE::name) \
__##name##_impl__ __asm__(#name); \
__##name##_impl__ asm(#name); \
decltype(LIBC_NAMESPACE::name) name [[gnu::alias(#name)]]; \
type __##name##_impl__ arglist
#else // __APPLE__

View file

@ -27,7 +27,7 @@ namespace internal {
// as well as a way to support non-ASCII character encodings.
// Similarly, do not change these functions to use case ranges. e.g.
// bool islower(int ch) {
// bool islower(char ch) {
// switch(ch) {
// case 'a'...'z':
// return true;
@ -37,7 +37,7 @@ namespace internal {
// EBCDIC. Technically we could use some smaller ranges, but that's even harder
// to read.
LIBC_INLINE static constexpr bool islower(int ch) {
LIBC_INLINE static constexpr bool islower(char ch) {
switch (ch) {
case 'a':
case 'b':
@ -71,7 +71,7 @@ LIBC_INLINE static constexpr bool islower(int ch) {
}
}
LIBC_INLINE static constexpr bool isupper(int ch) {
LIBC_INLINE static constexpr bool isupper(char ch) {
switch (ch) {
case 'A':
case 'B':
@ -105,7 +105,7 @@ LIBC_INLINE static constexpr bool isupper(int ch) {
}
}
LIBC_INLINE static constexpr bool isdigit(int ch) {
LIBC_INLINE static constexpr bool isdigit(char ch) {
switch (ch) {
case '0':
case '1':
@ -123,7 +123,7 @@ LIBC_INLINE static constexpr bool isdigit(int ch) {
}
}
LIBC_INLINE static constexpr int tolower(int ch) {
LIBC_INLINE static constexpr char tolower(char ch) {
switch (ch) {
case 'A':
return 'a';
@ -182,7 +182,7 @@ LIBC_INLINE static constexpr int tolower(int ch) {
}
}
LIBC_INLINE static constexpr int toupper(int ch) {
LIBC_INLINE static constexpr char toupper(char ch) {
switch (ch) {
case 'a':
return 'A';
@ -241,7 +241,7 @@ LIBC_INLINE static constexpr int toupper(int ch) {
}
}
LIBC_INLINE static constexpr bool isalpha(int ch) {
LIBC_INLINE static constexpr bool isalpha(char ch) {
switch (ch) {
case 'a':
case 'b':
@ -301,7 +301,7 @@ LIBC_INLINE static constexpr bool isalpha(int ch) {
}
}
LIBC_INLINE static constexpr bool isalnum(int ch) {
LIBC_INLINE static constexpr bool isalnum(char ch) {
switch (ch) {
case 'a':
case 'b':
@ -371,7 +371,7 @@ LIBC_INLINE static constexpr bool isalnum(int ch) {
}
}
LIBC_INLINE static constexpr int b36_char_to_int(int ch) {
LIBC_INLINE static constexpr int b36_char_to_int(char ch) {
switch (ch) {
case '0':
return 0;
@ -476,7 +476,7 @@ LIBC_INLINE static constexpr int b36_char_to_int(int ch) {
}
}
LIBC_INLINE static constexpr int int_to_b36_char(int num) {
LIBC_INLINE static constexpr char int_to_b36_char(int num) {
// Can't actually use LIBC_ASSERT here because it depends on integer_to_string
// which depends on this.
@ -559,7 +559,7 @@ LIBC_INLINE static constexpr int int_to_b36_char(int num) {
}
}
LIBC_INLINE static constexpr bool isspace(int ch) {
LIBC_INLINE static constexpr bool isspace(char ch) {
switch (ch) {
case ' ':
case '\t':
@ -574,10 +574,17 @@ LIBC_INLINE static constexpr bool isspace(int ch) {
}
// not yet encoding independent.
LIBC_INLINE static constexpr bool isgraph(int ch) {
LIBC_INLINE static constexpr bool isgraph(char ch) {
return 0x20 < ch && ch < 0x7f;
}
// An overload which provides a way to compare input with specific character
// values, when input can be of a regular or a wide character type.
LIBC_INLINE static constexpr bool is_char_or_wchar(char ch, char c_value,
[[maybe_unused]] wchar_t) {
return (ch == c_value);
}
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL

View file

@ -9,11 +9,10 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_DETAILED_POWERS_OF_TEN_H
#define LLVM_LIBC_SRC___SUPPORT_DETAILED_POWERS_OF_TEN_H
#include "hdr/stdint_proxy.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include <stdint.h>
namespace LIBC_NAMESPACE_DECL {
namespace internal {

View file

@ -15,11 +15,12 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
#define LLVM_LIBC_SRC___SUPPORT_HIGH_PRECISION_DECIMAL_H
#include "hdr/stdint_proxy.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/ctype_utils.h"
#include "src/__support/macros/config.h"
#include "src/__support/str_to_integer.h"
#include <stdint.h>
#include "src/__support/wctype_utils.h"
namespace LIBC_NAMESPACE_DECL {
namespace internal {
@ -38,6 +39,24 @@ struct LShiftTableEntry {
// TODO: Figure out where to put this.
enum class RoundDirection { Up, Down, Nearest };
// These constants are used in both this file and in the main str_to_float.h.
// TODO: Figure out where to put this.
template <typename CharType> struct constants;
template <> struct constants<char> {
static constexpr char DECIMAL_POINT = '.';
static constexpr char DECIMAL_EXPONENT_MARKER = 'e';
static constexpr char HEX_EXPONENT_MARKER = 'p';
static constexpr char INF_STRING[] = "infinity";
static constexpr char NAN_STRING[] = "nan";
};
template <> struct constants<wchar_t> {
static constexpr wchar_t DECIMAL_POINT = L'.';
static constexpr wchar_t DECIMAL_EXPONENT_MARKER = L'e';
static constexpr wchar_t HEX_EXPONENT_MARKER = L'p';
static constexpr wchar_t INF_STRING[] = L"infinity";
static constexpr wchar_t NAN_STRING[] = L"nan";
};
// This is based on the HPD data structure described as part of the Simple
// Decimal Conversion algorithm by Nigel Tao, described at this link:
// https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html
@ -314,9 +333,9 @@ private:
public:
// num_string is assumed to be a string of numeric characters. It doesn't
// handle leading spaces.
LIBC_INLINE
HighPrecisionDecimal(
const char *__restrict num_string,
template <typename CharType>
LIBC_INLINE HighPrecisionDecimal(
const CharType *__restrict num_string,
const size_t num_len = cpp::numeric_limits<size_t>::max()) {
bool saw_dot = false;
size_t num_cur = 0;
@ -324,25 +343,26 @@ public:
// them all.
uint32_t total_digits = 0;
while (num_cur < num_len &&
(isdigit(num_string[num_cur]) || num_string[num_cur] == '.')) {
if (num_string[num_cur] == '.') {
(isdigit(num_string[num_cur]) ||
num_string[num_cur] == constants<CharType>::DECIMAL_POINT)) {
if (num_string[num_cur] == constants<CharType>::DECIMAL_POINT) {
if (saw_dot) {
break;
}
this->decimal_point = static_cast<int32_t>(total_digits);
saw_dot = true;
} else {
if (num_string[num_cur] == '0' && this->num_digits == 0) {
int digit = b36_char_to_int(num_string[num_cur]);
if (digit == 0 && this->num_digits == 0) {
--this->decimal_point;
++num_cur;
continue;
}
++total_digits;
if (this->num_digits < MAX_NUM_DIGITS) {
this->digits[this->num_digits] = static_cast<uint8_t>(
internal::b36_char_to_int(num_string[num_cur]));
this->digits[this->num_digits] = static_cast<uint8_t>(digit);
++this->num_digits;
} else if (num_string[num_cur] != '0') {
} else if (digit != 0) {
this->truncated = true;
}
}
@ -352,11 +372,10 @@ public:
if (!saw_dot)
this->decimal_point = static_cast<int32_t>(total_digits);
if (num_cur < num_len &&
(num_string[num_cur] == 'e' || num_string[num_cur] == 'E')) {
if (num_cur < num_len && tolower(num_string[num_cur]) ==
constants<CharType>::DECIMAL_EXPONENT_MARKER) {
++num_cur;
if (isdigit(num_string[num_cur]) || num_string[num_cur] == '+' ||
num_string[num_cur] == '-') {
if (isdigit(num_string[num_cur]) || get_sign(num_string + num_cur) != 0) {
auto result =
strtointeger<int32_t>(num_string + num_cur, 10, num_len - num_cur);
if (result.has_error()) {

View file

@ -14,9 +14,11 @@
// The build is configured to just use the public <assert.h> API
// for libc's internal assertions.
#ifndef LIBC_ASSERT
#include <assert.h>
#define LIBC_ASSERT(COND) assert(COND)
#endif // LIBC_ASSERT
#else // Not LIBC_COPT_USE_C_ASSERT

View file

@ -17,6 +17,7 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H
#define LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H
#include "config.h"
#include "properties/architectures.h"
#ifndef __has_attribute
@ -28,7 +29,32 @@
#define LIBC_INLINE_ASM __asm__ __volatile__
#define LIBC_UNUSED __attribute__((unused))
#ifdef LIBC_TARGET_ARCH_IS_GPU
// Uses the platform specific specialization
#define LIBC_THREAD_MODE_PLATFORM 0
// Mutex guards nothing, used in single-threaded implementations
#define LIBC_THREAD_MODE_SINGLE 1
// Vendor provides implementation
#define LIBC_THREAD_MODE_EXTERNAL 2
// libcxx doesn't define LIBC_THREAD_MODE, unless that is passed in the command
// line in the CMake invocation. This defaults to the original implementation
// (before changes in https://github.com/llvm/llvm-project/pull/145358)
#ifndef LIBC_THREAD_MODE
#define LIBC_THREAD_MODE LIBC_THREAD_MODE_PLATFORM
#endif // LIBC_THREAD_MODE
#if LIBC_THREAD_MODE != LIBC_THREAD_MODE_PLATFORM && \
LIBC_THREAD_MODE != LIBC_THREAD_MODE_SINGLE && \
LIBC_THREAD_MODE != LIBC_THREAD_MODE_EXTERNAL
#error LIBC_THREAD_MODE must be one of the following values: \
LIBC_THREAD_MODE_PLATFORM, \
LIBC_THREAD_MODE_SINGLE, \
LIBC_THREAD_MODE_EXTERNAL.
#endif
#if LIBC_THREAD_MODE == LIBC_THREAD_MODE_SINGLE
#define LIBC_THREAD_LOCAL
#else
#define LIBC_THREAD_LOCAL thread_local
@ -48,4 +74,21 @@
#define LIBC_PREFERED_TYPE(TYPE)
#endif
#if __has_attribute(ext_vector_type) && \
LIBC_HAS_FEATURE(ext_vector_type_boolean)
#define LIBC_HAS_VECTOR_TYPE 1
#else
#define LIBC_HAS_VECTOR_TYPE 0
#endif
#if __has_attribute(no_sanitize)
// Disable regular and hardware-supported ASan for functions that may
// intentionally make out-of-bounds access. Disable TSan as well, as it detects
// out-of-bounds accesses to heap memory.
#define LIBC_NO_SANITIZE_OOB_ACCESS \
__attribute__((no_sanitize("address", "hwaddress", "thread")))
#else
#define LIBC_NO_SANITIZE_OOB_ACCESS
#endif
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_ATTRIBUTES_H

View file

@ -13,6 +13,13 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H
#define LLVM_LIBC_SRC___SUPPORT_MACROS_CONFIG_H
#include "src/__support/macros/properties/architectures.h"
#include "src/__support/macros/properties/compiler.h"
#ifdef LIBC_COMPILER_IS_MSVC
#include <intrin.h>
#endif // LIBC_COMPILER_IS_MSVC
// Workaround for compilers that do not support builtin detection.
// FIXME: This is only required for the GPU portion which should be moved.
#ifndef __has_builtin
@ -27,6 +34,22 @@
#define LIBC_HAS_FEATURE(f) 0
#endif
#ifdef LIBC_COMPILER_IS_MSVC
// __builtin_trap replacement
#ifdef LIBC_TARGET_ARCH_IS_X86
#define __builtin_trap __ud2
#else // arm64
#define __builtin_trap() __break(1)
#endif
#define __builtin_expect(value, expectation) (value)
#define __builtin_unreachable() __assume(0)
#define __builtin_prefetch(X, Y, Z)
#endif // LIBC_COMPILER_IS_MSVC
#ifdef __clang__
// Declare a LIBC_NAMESPACE with hidden visibility. `namespace
// LIBC_NAMESPACE_DECL {` should be used around all declarations and definitions

View file

@ -11,9 +11,8 @@
#include "src/__support/macros/config.h"
#include "src/__support/macros/optimization.h"
#include "src/__support/macros/sanitizer.h"
#if defined(LIBC_ADD_NULL_CHECKS) && !defined(LIBC_HAS_SANITIZER)
#if defined(LIBC_ADD_NULL_CHECKS)
#define LIBC_CRASH_ON_NULLPTR(ptr) \
do { \
if (LIBC_UNLIKELY((ptr) == nullptr)) \

View file

@ -34,6 +34,9 @@ LIBC_INLINE constexpr bool expects_bool_condition(T value, T expected) {
#elif defined(LIBC_COMPILER_IS_GCC)
#define LIBC_LOOP_NOUNROLL _Pragma("GCC unroll 0")
#define LIBC_LOOP_UNROLL _Pragma("GCC unroll 2048")
#elif defined(LIBC_COMPILER_IS_MSVC)
#define LIBC_LOOP_NOUNROLL
#define LIBC_LOOP_UNROLL
#else
#error "Unhandled compiler"
#endif

View file

@ -21,7 +21,7 @@
#define LIBC_TARGET_ARCH_IS_GPU
#endif
#if defined(__pnacl__) || defined(__CLR_VER) || defined(LIBC_TARGET_ARCH_IS_GPU)
#if defined(__CLR_VER) || defined(LIBC_TARGET_ARCH_IS_GPU)
#define LIBC_TARGET_ARCH_IS_VM
#endif
@ -41,6 +41,10 @@
#define LIBC_TARGET_ARCH_IS_ARM
#endif
#if defined(__wasm__)
#define LIBC_TARGET_ARCH_IS_WASM
#endif
#if defined(__aarch64__) || defined(__arm64__) || defined(_M_ARM64)
#define LIBC_TARGET_ARCH_IS_AARCH64
#endif

View file

@ -34,10 +34,15 @@
#define LIBC_COMPILER_GCC_VER (__GNUC__ * 100 + __GNUC_MINOR__)
#endif
#if defined(_MSC_VER)
#define LIBC_COMPILER_IS_MSC
#if defined(_MSC_VER) && !defined(__clang__)
#define LIBC_COMPILER_IS_MSVC
// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros
#define LIBC_COMPILER_MSC_VER (_MSC_VER)
#define LIBC_COMPILER_MSVC_VER (_MSC_VER)
#ifdef _M_X64
#define LIBC_COMPILER_IS_MSVC_X64
#else
#define LIBC_COMPILER_IS_MSVC_X86
#endif
#endif
#endif // LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_COMPILER_H

View file

@ -18,6 +18,18 @@
#define LIBC_TARGET_CPU_HAS_FULLFP16
#endif
#if defined(__ARM_FEATURE_SVE)
#define LIBC_TARGET_CPU_HAS_SVE
#endif
#if defined(__ARM_FEATURE_SVE2)
#define LIBC_TARGET_CPU_HAS_SVE2
#endif
#if defined(__ARM_FEATURE_MOPS)
#define LIBC_TARGET_CPU_HAS_MOPS
#endif
#if defined(__SSE2__)
#define LIBC_TARGET_CPU_HAS_SSE2
#define LIBC_TARGET_CPU_HAS_FPU_FLOAT
@ -59,6 +71,10 @@
#endif // LIBC_TARGET_CPU_HAS_ARM_FPU_DOUBLE
#endif // __ARM_FP
#if defined(__ARM_NEON)
#define LIBC_TARGET_CPU_HAS_ARM_NEON
#endif
#if defined(__riscv_flen)
// https://github.com/riscv-non-isa/riscv-c-api-doc/blob/main/src/c-api.adoc
#if defined(__riscv_zfhmin)
@ -81,7 +97,7 @@
#endif
#if defined(__ARM_FEATURE_FMA) || (defined(__AVX2__) && defined(__FMA__)) || \
defined(__NVPTX__) || defined(__AMDGPU__) || defined(__LIBC_RISCV_USE_FMA)
defined(__NVPTX__) || defined(__AMDGPU__) || defined(__riscv_flen)
#define LIBC_TARGET_CPU_HAS_FMA
// Provide a more fine-grained control of FMA instruction for ARM targets.
#if defined(LIBC_TARGET_CPU_HAS_FPU_HALF)

View file

@ -10,7 +10,8 @@
#ifndef LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H
#define LLVM_LIBC_SRC___SUPPORT_MACROS_PROPERTIES_TYPES_H
#include "hdr/float_macros.h" // LDBL_MANT_DIG
#include "hdr/float_macros.h" // LDBL_MANT_DIG
#include "hdr/stdint_proxy.h" // UINT64_MAX, __SIZEOF_INT128__
#include "include/llvm-libc-macros/float16-macros.h" // LIBC_TYPES_HAS_FLOAT16
#include "include/llvm-libc-types/float128.h" // float128
#include "src/__support/macros/config.h" // LIBC_NAMESPACE_DECL
@ -19,8 +20,6 @@
#include "src/__support/macros/properties/cpu_features.h"
#include "src/__support/macros/properties/os.h"
#include <stdint.h> // UINT64_MAX, __SIZEOF_INT128__
// 'long double' properties.
#if (LDBL_MANT_DIG == 53)
#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64

View file

@ -23,16 +23,6 @@
#define LIBC_HAS_MEMORY_SANITIZER
#endif
#if LIBC_HAS_FEATURE(undefined_behavior_sanitizer)
#define LIBC_HAS_UNDEFINED_BEHAVIOR_SANITIZER
#endif
#if defined(LIBC_HAS_ADDRESS_SANITIZER) || \
defined(LIBC_HAS_MEMORY_SANITIZER) || \
defined(LIBC_HAS_UNDEFINED_BEHAVIOR_SANITIZER)
#define LIBC_HAS_SANITIZER
#endif
#ifdef LIBC_HAS_MEMORY_SANITIZER
// Only perform MSAN unpoison in non-constexpr context.
#include <sanitizer/msan_interface.h>

View file

@ -25,7 +25,13 @@ LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
mask_trailing_ones() {
constexpr unsigned T_BITS = CHAR_BIT * sizeof(T);
static_assert(count <= T_BITS && "Invalid bit index");
return count == 0 ? 0 : (T(-1) >> (T_BITS - count));
// MSVC complains about out of range shifts.
if constexpr (count == 0)
return 0;
else if constexpr (count >= T_BITS)
return T(-1);
else
return T(-1) >> (T_BITS - count);
}
// Create a bitmask with the count left-most bits set to 1, and all other bits
@ -55,18 +61,28 @@ mask_leading_zeros() {
// Returns whether 'a + b' overflows, the result is stored in 'res'.
template <typename T>
[[nodiscard]] LIBC_INLINE constexpr bool add_overflow(T a, T b, T &res) {
#if __has_builtin(__builtin_add_overflow)
return __builtin_add_overflow(a, b, &res);
#else
res = a + b;
return (res < a) || (res < b);
#endif // __builtin_add_overflow
}
// Returns whether 'a - b' overflows, the result is stored in 'res'.
template <typename T>
[[nodiscard]] LIBC_INLINE constexpr bool sub_overflow(T a, T b, T &res) {
#if __has_builtin(__builtin_sub_overflow)
return __builtin_sub_overflow(a, b, &res);
#else
res = a - b;
return (res > a);
#endif // __builtin_sub_overflow
}
#define RETURN_IF(TYPE, BUILTIN) \
if constexpr (cpp::is_same_v<T, TYPE>) \
return BUILTIN(a, b, carry_in, carry_out);
return BUILTIN(a, b, carry_in, &carry_out);
// Returns the result of 'a + b' taking into account 'carry_in'.
// The carry out is stored in 'carry_out' it not 'nullptr', dropped otherwise.
@ -74,7 +90,7 @@ template <typename T>
template <typename T>
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
add_with_carry(T a, T b, T carry_in, T &carry_out) {
if constexpr (!cpp::is_constant_evaluated()) {
if (!cpp::is_constant_evaluated()) {
#if __has_builtin(__builtin_addcb)
RETURN_IF(unsigned char, __builtin_addcb)
#elif __has_builtin(__builtin_addcs)
@ -100,7 +116,7 @@ add_with_carry(T a, T b, T carry_in, T &carry_out) {
template <typename T>
[[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_t<cpp::is_unsigned_v<T>, T>
sub_with_borrow(T a, T b, T carry_in, T &carry_out) {
if constexpr (!cpp::is_constant_evaluated()) {
if (!cpp::is_constant_evaluated()) {
#if __has_builtin(__builtin_subcb)
RETURN_IF(unsigned char, __builtin_subcb)
#elif __has_builtin(__builtin_subcs)

View file

@ -16,6 +16,7 @@
#define LLVM_LIBC_SRC___SUPPORT_STR_TO_FLOAT_H
#include "hdr/errno_macros.h" // For ERANGE
#include "hdr/stdint_proxy.h"
#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/CPP/optional.h"
@ -32,8 +33,7 @@
#include "src/__support/str_to_integer.h"
#include "src/__support/str_to_num_result.h"
#include "src/__support/uint128.h"
#include <stdint.h>
#include "src/__support/wctype_utils.h"
namespace LIBC_NAMESPACE_DECL {
namespace internal {
@ -335,9 +335,9 @@ constexpr int32_t NUM_POWERS_OF_TWO =
// the Eisel-Lemire algorithm fails, it's slower but more accurate. It's based
// on the Simple Decimal Conversion algorithm by Nigel Tao, described at this
// link: https://nigeltao.github.io/blog/2020/parse-number-f64-simple.html
template <class T>
template <typename T, typename CharType>
LIBC_INLINE FloatConvertReturn<T> simple_decimal_conversion(
const char *__restrict numStart,
const CharType *__restrict numStart,
const size_t num_len = cpp::numeric_limits<size_t>::max(),
RoundDirection round = RoundDirection::Nearest) {
using FPBits = typename fputil::FPBits<T>;
@ -677,12 +677,11 @@ template <> LIBC_INLINE constexpr int32_t get_lower_bound<double>() {
// Takes a mantissa and base 10 exponent and converts it into its closest
// floating point type T equivalient. First we try the Eisel-Lemire algorithm,
// then if that fails then we fall back to a more accurate algorithm for
// accuracy. The resulting mantissa and exponent are placed in outputMantissa
// and outputExp2.
template <class T>
// accuracy.
template <typename T, typename CharType>
LIBC_INLINE FloatConvertReturn<T> decimal_exp_to_float(
ExpandedFloat<T> init_num, bool truncated, RoundDirection round,
const char *__restrict numStart,
const CharType *__restrict numStart,
const size_t num_len = cpp::numeric_limits<size_t>::max()) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
@ -861,36 +860,42 @@ LIBC_INLINE FloatConvertReturn<T> binary_exp_to_float(ExpandedFloat<T> init_num,
return output;
}
// checks if the next 4 characters of the string pointer are the start of a
// Checks if the first characters of the string pointer are the start of a
// hexadecimal floating point number. Does not advance the string pointer.
LIBC_INLINE bool is_float_hex_start(const char *__restrict src,
const char decimalPoint) {
if (!(src[0] == '0' && tolower(src[1]) == 'x')) {
template <typename CharType>
LIBC_INLINE static bool is_float_hex_start(const CharType *__restrict src) {
if (!is_char_or_wchar(src[0], '0', L'0') ||
!is_char_or_wchar(tolower(src[1]), 'x', L'x')) {
return false;
}
size_t first_digit = 2;
if (src[2] == decimalPoint) {
if (src[2] == constants<CharType>::DECIMAL_POINT) {
++first_digit;
}
return isalnum(src[first_digit]) && b36_char_to_int(src[first_digit]) < 16;
}
// Takes the start of a string representing a decimal float, as well as the
// local decimalPoint. It returns if it suceeded in parsing any digits, and if
// the return value is true then the outputs are pointer to the end of the
// number, and the mantissa and exponent for the closest float T representation.
// If the return value is false, then it is assumed that there is no number
// here.
template <class T>
LIBC_INLINE StrToNumResult<ExpandedFloat<T>>
decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
RoundDirection round) {
// Verifies that first prefix_len characters of str, when lowercased, match the
// specified prefix.
template <typename CharType>
LIBC_INLINE static bool tolower_starts_with(const CharType *str,
size_t prefix_len,
const CharType *prefix) {
for (size_t i = 0; i < prefix_len; ++i) {
if (tolower(str[i]) != prefix[i])
return false;
}
return true;
}
// Attempts parsing a decimal floating point number at the start of the string.
template <typename T, typename CharType>
LIBC_INLINE static StrToNumResult<ExpandedFloat<T>>
decimal_string_to_float(const CharType *__restrict src, RoundDirection round) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
constexpr uint32_t BASE = 10;
constexpr char EXPONENT_MARKER = 'e';
bool truncated = false;
bool seen_digit = false;
bool after_decimal = false;
@ -927,7 +932,7 @@ decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
++index;
continue;
}
if (src[index] == DECIMAL_POINT) {
if (src[index] == constants<CharType>::DECIMAL_POINT) {
if (after_decimal) {
break; // this means that src[index] points to a second decimal point,
// ending the number.
@ -944,13 +949,10 @@ decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
return output;
// TODO: When adding max length argument, handle the case of a trailing
// EXPONENT MARKER, see scanf for more details.
if (tolower(src[index]) == EXPONENT_MARKER) {
bool has_sign = false;
if (src[index + 1] == '+' || src[index + 1] == '-') {
has_sign = true;
}
if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) {
// exponent marker, see scanf for more details.
if (tolower(src[index]) == constants<CharType>::DECIMAL_EXPONENT_MARKER) {
int sign = get_sign(src + index + 1);
if (isdigit(src[index + 1 + static_cast<size_t>(sign != 0)])) {
++index;
auto result = strtointeger<int32_t>(src + index, 10);
if (result.has_error())
@ -986,22 +988,16 @@ decimal_string_to_float(const char *__restrict src, const char DECIMAL_POINT,
return output;
}
// Takes the start of a string representing a hexadecimal float, as well as the
// local decimal point. It returns if it suceeded in parsing any digits, and if
// the return value is true then the outputs are pointer to the end of the
// number, and the mantissa and exponent for the closest float T representation.
// If the return value is false, then it is assumed that there is no number
// here.
template <class T>
LIBC_INLINE StrToNumResult<ExpandedFloat<T>>
hexadecimal_string_to_float(const char *__restrict src,
const char DECIMAL_POINT, RoundDirection round) {
// Attempts parsing a hexadecimal floating point number at the start of the
// string.
template <typename T, typename CharType>
LIBC_INLINE static StrToNumResult<ExpandedFloat<T>>
hexadecimal_string_to_float(const CharType *__restrict src,
RoundDirection round) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
constexpr uint32_t BASE = 16;
constexpr char EXPONENT_MARKER = 'p';
bool truncated = false;
bool seen_digit = false;
bool after_decimal = false;
@ -1039,7 +1035,7 @@ hexadecimal_string_to_float(const char *__restrict src,
++index;
continue;
}
if (src[index] == DECIMAL_POINT) {
if (src[index] == constants<CharType>::DECIMAL_POINT) {
if (after_decimal) {
break; // this means that src[index] points to a second decimal point,
// ending the number.
@ -1058,12 +1054,9 @@ hexadecimal_string_to_float(const char *__restrict src,
// Convert the exponent from having a base of 16 to having a base of 2.
exponent *= 4;
if (tolower(src[index]) == EXPONENT_MARKER) {
bool has_sign = false;
if (src[index + 1] == '+' || src[index + 1] == '-') {
has_sign = true;
}
if (isdigit(src[index + 1 + static_cast<size_t>(has_sign)])) {
if (tolower(src[index]) == constants<CharType>::HEX_EXPONENT_MARKER) {
int sign = get_sign(src + index + 1);
if (isdigit(src[index + 1 + static_cast<size_t>(sign != 0)])) {
++index;
auto result = strtointeger<int32_t>(src + index, 10);
if (result.has_error())
@ -1099,21 +1092,21 @@ hexadecimal_string_to_float(const char *__restrict src,
return output;
}
template <class T>
template <typename T, typename CharType>
LIBC_INLINE typename fputil::FPBits<T>::StorageType
nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) {
nan_mantissa_from_ncharseq(const CharType *str, size_t len) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
StorageType nan_mantissa = 0;
if (ncharseq.data() != nullptr && isdigit(ncharseq[0])) {
if (len > 0 && isdigit(str[0])) {
StrToNumResult<StorageType> strtoint_result =
strtointeger<StorageType>(ncharseq.data(), 0);
strtointeger<StorageType>(str, 0, len);
if (!strtoint_result.has_error())
nan_mantissa = strtoint_result.value;
if (strtoint_result.parsed_len != static_cast<ptrdiff_t>(ncharseq.size()))
if (strtoint_result.parsed_len != static_cast<ptrdiff_t>(len))
nan_mantissa = 0;
}
@ -1124,59 +1117,44 @@ nan_mantissa_from_ncharseq(const cpp::string_view ncharseq) {
// is used as the backend for all of the string to float functions.
// TODO: Add src_len member to match strtointeger.
// TODO: Next, move from char* and length to string_view
template <class T>
LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
template <typename T, typename CharType>
LIBC_INLINE StrToNumResult<T>
strtofloatingpoint(const CharType *__restrict src) {
using FPBits = typename fputil::FPBits<T>;
using StorageType = typename FPBits::StorageType;
FPBits result = FPBits();
bool seen_digit = false;
char sign = '+';
int error = 0;
size_t index = first_non_whitespace(src);
int sign = get_sign(src + index);
bool is_positive = (sign >= 0);
index += (sign != 0);
if (src[index] == '+' || src[index] == '-') {
sign = src[index];
++index;
}
if (sign == '-') {
if (sign < 0) {
result.set_sign(Sign::NEG);
}
static constexpr char DECIMAL_POINT = '.';
static const char *inf_string = "infinity";
static const char *nan_string = "nan";
if (isdigit(src[index]) || src[index] == DECIMAL_POINT) { // regular number
if (isdigit(src[index]) ||
src[index] == constants<CharType>::DECIMAL_POINT) { // regular number
int base = 10;
if (is_float_hex_start(src + index, DECIMAL_POINT)) {
if (is_float_hex_start(src + index)) {
base = 16;
index += 2;
seen_digit = true;
}
RoundDirection round_direction = RoundDirection::Nearest;
switch (fputil::quick_get_round()) {
case FE_TONEAREST:
round_direction = RoundDirection::Nearest;
break;
case FE_UPWARD:
if (sign == '+') {
round_direction = RoundDirection::Up;
} else {
round_direction = RoundDirection::Down;
}
round_direction = is_positive ? RoundDirection::Up : RoundDirection::Down;
break;
case FE_DOWNWARD:
if (sign == '+') {
round_direction = RoundDirection::Down;
} else {
round_direction = RoundDirection::Up;
}
round_direction = is_positive ? RoundDirection::Down : RoundDirection::Up;
break;
case FE_TOWARDZERO:
round_direction = RoundDirection::Down;
@ -1185,58 +1163,53 @@ LIBC_INLINE StrToNumResult<T> strtofloatingpoint(const char *__restrict src) {
StrToNumResult<ExpandedFloat<T>> parse_result({0, 0});
if (base == 16) {
parse_result = hexadecimal_string_to_float<T>(src + index, DECIMAL_POINT,
round_direction);
parse_result =
hexadecimal_string_to_float<T>(src + index, round_direction);
} else { // base is 10
parse_result = decimal_string_to_float<T>(src + index, DECIMAL_POINT,
round_direction);
parse_result = decimal_string_to_float<T>(src + index, round_direction);
}
seen_digit = parse_result.parsed_len != 0;
result.set_mantissa(parse_result.value.mantissa);
result.set_biased_exponent(parse_result.value.exponent);
index += parse_result.parsed_len;
error = parse_result.error;
} else if (tolower(src[index]) == 'n') { // NaN
if (tolower(src[index + 1]) == nan_string[1] &&
tolower(src[index + 2]) == nan_string[2]) {
seen_digit = true;
index += 3;
StorageType nan_mantissa = 0;
// this handles the case of `NaN(n-character-sequence)`, where the
// n-character-sequence is made of 0 or more letters, numbers, or
// underscore characters in any order.
if (src[index] == '(') {
size_t left_paren = index;
} else if (tolower_starts_with(src + index, 3,
constants<CharType>::NAN_STRING)) {
// NAN
seen_digit = true;
index += 3;
StorageType nan_mantissa = 0;
// this handles the case of `NaN(n-character-sequence)`, where the
// n-character-sequence is made of 0 or more letters, numbers, or
// underscore characters in any order.
if (is_char_or_wchar(src[index], '(', L'(')) {
size_t left_paren = index;
++index;
while (isalnum(src[index]) || is_char_or_wchar(src[index], '_', L'_'))
++index;
while (isalnum(src[index]) || src[index] == '_')
++index;
if (src[index] == ')') {
++index;
nan_mantissa = nan_mantissa_from_ncharseq<T>(
cpp::string_view(src + (left_paren + 1), index - left_paren - 2));
} else {
index = left_paren;
}
}
result = FPBits(result.quiet_nan(result.sign(), nan_mantissa));
}
} else if (tolower(src[index]) == 'i') { // INF
if (tolower(src[index + 1]) == inf_string[1] &&
tolower(src[index + 2]) == inf_string[2]) {
seen_digit = true;
result = FPBits(result.inf(result.sign()));
if (tolower(src[index + 3]) == inf_string[3] &&
tolower(src[index + 4]) == inf_string[4] &&
tolower(src[index + 5]) == inf_string[5] &&
tolower(src[index + 6]) == inf_string[6] &&
tolower(src[index + 7]) == inf_string[7]) {
// if the string is "INFINITY" then consume 8 characters.
index += 8;
if (is_char_or_wchar(src[index], ')', L')')) {
++index;
nan_mantissa = nan_mantissa_from_ncharseq<T>(src + (left_paren + 1),
index - left_paren - 2);
} else {
index += 3;
index = left_paren;
}
}
result = FPBits(result.quiet_nan(result.sign(), nan_mantissa));
} else if (tolower_starts_with(src + index, 8,
constants<CharType>::INF_STRING)) {
// INFINITY
seen_digit = true;
result = FPBits(result.inf(result.sign()));
index += 8;
} else if (tolower_starts_with(src + index, 3,
constants<CharType>::INF_STRING)) {
// INF
seen_digit = true;
result = FPBits(result.inf(result.sign()));
index += 3;
}
if (!seen_digit) { // If there is nothing to actually parse, then return 0.
return {T(0), 0, error};
}
@ -1263,7 +1236,7 @@ template <class T> LIBC_INLINE StrToNumResult<T> strtonan(const char *arg) {
++index;
if (arg[index] == '\0')
nan_mantissa = nan_mantissa_from_ncharseq<T>(cpp::string_view(arg, index));
nan_mantissa = nan_mantissa_from_ncharseq<T>(arg, index);
result = FPBits::quiet_nan(Sign::POS, nan_mantissa);
return {result.get_val(), 0, error};

View file

@ -25,36 +25,51 @@
#include "src/__support/macros/config.h"
#include "src/__support/str_to_num_result.h"
#include "src/__support/uint128.h"
#include "src/__support/wctype_utils.h"
namespace LIBC_NAMESPACE_DECL {
namespace internal {
// Returns the idx to the first character in src that is not a whitespace
// character (as determined by isspace())
template <typename CharType>
LIBC_INLINE size_t
first_non_whitespace(const char *__restrict src,
first_non_whitespace(const CharType *__restrict src,
size_t src_len = cpp::numeric_limits<size_t>::max()) {
size_t src_cur = 0;
while (src_cur < src_len && internal::isspace(src[src_cur])) {
++src_cur;
}
for (; src_cur < src_len && internal::isspace(src[src_cur]); ++src_cur)
;
return src_cur;
}
// Returns +1, -1, or 0 if 'src' starts with (respectively)
// plus sign, minus sign, or neither.
template <typename CharType>
LIBC_INLINE static int get_sign(const CharType *__restrict src) {
if (is_char_or_wchar(src[0], '+', L'+'))
return 1;
if (is_char_or_wchar(src[0], '-', L'-'))
return -1;
return 0;
}
// checks if the next 3 characters of the string pointer are the start of a
// hexadecimal number. Does not advance the string pointer.
LIBC_INLINE bool
is_hex_start(const char *__restrict src,
size_t src_len = cpp::numeric_limits<size_t>::max()) {
template <typename CharType>
LIBC_INLINE static bool is_hex_start(const CharType *__restrict src,
size_t src_len) {
if (src_len < 3)
return false;
return *src == '0' && tolower(*(src + 1)) == 'x' && isalnum(*(src + 2)) &&
b36_char_to_int(*(src + 2)) < 16;
return is_char_or_wchar(src[0], '0', L'0') &&
is_char_or_wchar(tolower(src[1]), 'x', L'x') && isalnum(src[2]) &&
b36_char_to_int(src[2]) < 16;
}
// Takes the address of the string pointer and parses the base from the start of
// it.
LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) {
template <typename CharType>
LIBC_INLINE static int infer_base(const CharType *__restrict src,
size_t src_len) {
// A hexadecimal number is defined as "the prefix 0x or 0X followed by a
// sequence of the decimal digits and the letters a (or A) through f (or F)
// with values 10 through 15 respectively." (C standard 6.4.4.1)
@ -63,8 +78,9 @@ LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) {
// An octal number is defined as "the prefix 0 optionally followed by a
// sequence of the digits 0 through 7 only" (C standard 6.4.4.1) and so any
// number that starts with 0, including just 0, is an octal number.
if (src_len > 0 && src[0] == '0')
if (src_len > 0 && is_char_or_wchar(src[0], '0', L'0')) {
return 8;
}
// A decimal number is defined as beginning "with a nonzero digit and
// consist[ing] of a sequence of decimal digits." (C standard 6.4.4.1)
return 10;
@ -77,32 +93,27 @@ LIBC_INLINE int infer_base(const char *__restrict src, size_t src_len) {
// -----------------------------------------------------------------------------
// Takes a pointer to a string and the base to convert to. This function is used
// as the backend for all of the string to int functions.
template <class T>
template <typename T, typename CharType>
LIBC_INLINE StrToNumResult<T>
strtointeger(const char *__restrict src, int base,
strtointeger(const CharType *__restrict src, int base,
const size_t src_len = cpp::numeric_limits<size_t>::max()) {
using ResultType = make_integral_or_big_int_unsigned_t<T>;
ResultType result = 0;
bool is_number = false;
size_t src_cur = 0;
int error_val = 0;
if (src_len == 0)
return {0, 0, 0};
if (base < 0 || base == 1 || base > 36)
return {0, 0, EINVAL};
src_cur = first_non_whitespace(src, src_len);
char result_sign = '+';
if (src[src_cur] == '+' || src[src_cur] == '-') {
result_sign = src[src_cur];
++src_cur;
size_t src_cur = first_non_whitespace(src, src_len);
if (src_cur == src_len) {
return {0, 0, 0};
}
int sign = get_sign(src + src_cur);
bool is_positive = (sign >= 0);
src_cur += (sign != 0);
if (base == 0)
base = infer_base(src + src_cur, src_len - src_cur);
@ -110,8 +121,6 @@ strtointeger(const char *__restrict src, int base,
src_cur = src_cur + 2;
constexpr bool IS_UNSIGNED = cpp::is_unsigned_v<T>;
const bool is_positive = (result_sign == '+');
ResultType constexpr NEGATIVE_MAX =
!IS_UNSIGNED ? static_cast<ResultType>(cpp::numeric_limits<T>::max()) + 1
: cpp::numeric_limits<T>::max();
@ -120,6 +129,9 @@ strtointeger(const char *__restrict src, int base,
ResultType const abs_max_div_by_base =
abs_max / static_cast<ResultType>(base);
bool is_number = false;
int error_val = 0;
ResultType result = 0;
while (src_cur < src_len && isalnum(src[src_cur])) {
int cur_digit = b36_char_to_int(src[src_cur]);
if (cur_digit >= base)

View file

@ -0,0 +1,588 @@
//===-- Collection of utils for implementing wide char 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_WCTYPE_UTILS_H
#define LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H
#include "hdr/types/wchar_t.h"
#include "src/__support/macros/attributes.h" // LIBC_INLINE
#include "src/__support/macros/config.h"
namespace LIBC_NAMESPACE_DECL {
namespace internal {
// -----------------------------------------------------------------------------
// ****************** WARNING ******************
// ****************** DO NOT TRY TO OPTIMIZE THESE FUNCTIONS! ******************
// -----------------------------------------------------------------------------
// This switch/case form is easier for the compiler to understand, and is
// optimized into a form that is almost always the same as or better than
// versions written by hand (see https://godbolt.org/z/qvrebqvvr). Also this
// form makes these functions encoding independent. If you want to rewrite these
// functions, make sure you have benchmarks to show your new solution is faster,
// as well as a way to support non-ASCII character encodings.
// Similarly, do not change these fumarks to show your new solution is faster,
// as well as a way to support non-Anctions to use case ranges. e.g.
// bool islower(wchar_t ch) {
// switch(ch) {
// case L'a'...L'z':
// return true;
// }
// }
// This assumes the character ranges are contiguous, which they aren't in
// EBCDIC. Technically we could use some smaller ranges, but that's even harder
// to read.
LIBC_INLINE static constexpr bool islower(wchar_t wch) {
switch (wch) {
case L'a':
case L'b':
case L'c':
case L'd':
case L'e':
case L'f':
case L'g':
case L'h':
case L'i':
case L'j':
case L'k':
case L'l':
case L'm':
case L'n':
case L'o':
case L'p':
case L'q':
case L'r':
case L's':
case L't':
case L'u':
case L'v':
case L'w':
case L'x':
case L'y':
case L'z':
return true;
default:
return false;
}
}
LIBC_INLINE static constexpr bool isupper(wchar_t wch) {
switch (wch) {
case L'A':
case L'B':
case L'C':
case L'D':
case L'E':
case L'F':
case L'G':
case L'H':
case L'I':
case L'J':
case L'K':
case L'L':
case L'M':
case L'N':
case L'O':
case L'P':
case L'Q':
case L'R':
case L'S':
case L'T':
case L'U':
case L'V':
case L'W':
case L'X':
case L'Y':
case L'Z':
return true;
default:
return false;
}
}
LIBC_INLINE static constexpr bool isdigit(wchar_t wch) {
switch (wch) {
case L'0':
case L'1':
case L'2':
case L'3':
case L'4':
case L'5':
case L'6':
case L'7':
case L'8':
case L'9':
return true;
default:
return false;
}
}
LIBC_INLINE static constexpr wchar_t tolower(wchar_t wch) {
switch (wch) {
case L'A':
return L'a';
case L'B':
return L'b';
case L'C':
return L'c';
case L'D':
return L'd';
case L'E':
return L'e';
case L'F':
return L'f';
case L'G':
return L'g';
case L'H':
return L'h';
case L'I':
return L'i';
case L'J':
return L'j';
case L'K':
return L'k';
case L'L':
return L'l';
case L'M':
return L'm';
case L'N':
return L'n';
case L'O':
return L'o';
case L'P':
return L'p';
case L'Q':
return L'q';
case L'R':
return L'r';
case L'S':
return L's';
case L'T':
return L't';
case L'U':
return L'u';
case L'V':
return L'v';
case L'W':
return L'w';
case L'X':
return L'x';
case L'Y':
return L'y';
case L'Z':
return L'z';
default:
return wch;
}
}
LIBC_INLINE static constexpr wchar_t toupper(wchar_t wch) {
switch (wch) {
case L'a':
return L'A';
case L'b':
return L'B';
case L'c':
return L'C';
case L'd':
return L'D';
case L'e':
return L'E';
case L'f':
return L'F';
case L'g':
return L'G';
case L'h':
return L'H';
case L'i':
return L'I';
case L'j':
return L'J';
case L'k':
return L'K';
case L'l':
return L'L';
case L'm':
return L'M';
case L'n':
return L'N';
case L'o':
return L'O';
case L'p':
return L'P';
case L'q':
return L'Q';
case L'r':
return L'R';
case L's':
return L'S';
case L't':
return L'T';
case L'u':
return L'U';
case L'v':
return L'V';
case L'w':
return L'W';
case L'x':
return L'X';
case L'y':
return L'Y';
case L'z':
return L'Z';
default:
return wch;
}
}
LIBC_INLINE static constexpr bool isalpha(wchar_t wch) {
switch (wch) {
case L'a':
case L'b':
case L'c':
case L'd':
case L'e':
case L'f':
case L'g':
case L'h':
case L'i':
case L'j':
case L'k':
case L'l':
case L'm':
case L'n':
case L'o':
case L'p':
case L'q':
case L'r':
case L's':
case L't':
case L'u':
case L'v':
case L'w':
case L'x':
case L'y':
case L'z':
case L'A':
case L'B':
case L'C':
case L'D':
case L'E':
case L'F':
case L'G':
case L'H':
case L'I':
case L'J':
case L'K':
case L'L':
case L'M':
case L'N':
case L'O':
case L'P':
case L'Q':
case L'R':
case L'S':
case L'T':
case L'U':
case L'V':
case L'W':
case L'X':
case L'Y':
case L'Z':
return true;
default:
return false;
}
}
LIBC_INLINE static constexpr bool isalnum(wchar_t wch) {
switch (wch) {
case L'a':
case L'b':
case L'c':
case L'd':
case L'e':
case L'f':
case L'g':
case L'h':
case L'i':
case L'j':
case L'k':
case L'l':
case L'm':
case L'n':
case L'o':
case L'p':
case L'q':
case L'r':
case L's':
case L't':
case L'u':
case L'v':
case L'w':
case L'x':
case L'y':
case L'z':
case L'A':
case L'B':
case L'C':
case L'D':
case L'E':
case L'F':
case L'G':
case L'H':
case L'I':
case L'J':
case L'K':
case L'L':
case L'M':
case L'N':
case L'O':
case L'P':
case L'Q':
case L'R':
case L'S':
case L'T':
case L'U':
case L'V':
case L'W':
case L'X':
case L'Y':
case L'Z':
case L'0':
case L'1':
case L'2':
case L'3':
case L'4':
case L'5':
case L'6':
case L'7':
case L'8':
case L'9':
return true;
default:
return false;
}
}
LIBC_INLINE static constexpr int b36_char_to_int(wchar_t wch) {
switch (wch) {
case L'0':
return 0;
case L'1':
return 1;
case L'2':
return 2;
case L'3':
return 3;
case L'4':
return 4;
case L'5':
return 5;
case L'6':
return 6;
case L'7':
return 7;
case L'8':
return 8;
case L'9':
return 9;
case L'a':
case L'A':
return 10;
case L'b':
case L'B':
return 11;
case L'c':
case L'C':
return 12;
case L'd':
case L'D':
return 13;
case L'e':
case L'E':
return 14;
case L'f':
case L'F':
return 15;
case L'g':
case L'G':
return 16;
case L'h':
case L'H':
return 17;
case L'i':
case L'I':
return 18;
case L'j':
case L'J':
return 19;
case L'k':
case L'K':
return 20;
case L'l':
case L'L':
return 21;
case L'm':
case L'M':
return 22;
case L'n':
case L'N':
return 23;
case L'o':
case L'O':
return 24;
case L'p':
case L'P':
return 25;
case L'q':
case L'Q':
return 26;
case L'r':
case L'R':
return 27;
case L's':
case L'S':
return 28;
case L't':
case L'T':
return 29;
case L'u':
case L'U':
return 30;
case L'v':
case L'V':
return 31;
case L'w':
case L'W':
return 32;
case L'x':
case L'X':
return 33;
case L'y':
case L'Y':
return 34;
case L'z':
case L'Z':
return 35;
default:
return 0;
}
}
LIBC_INLINE static constexpr wchar_t int_to_b36_wchar(int num) {
// Can't actually use LIBC_ASSERT here because it depends on integer_to_string
// which depends on this.
// LIBC_ASSERT(num < 36);
switch (num) {
case 0:
return L'0';
case 1:
return L'1';
case 2:
return L'2';
case 3:
return L'3';
case 4:
return L'4';
case 5:
return L'5';
case 6:
return L'6';
case 7:
return L'7';
case 8:
return L'8';
case 9:
return L'9';
case 10:
return L'a';
case 11:
return L'b';
case 12:
return L'c';
case 13:
return L'd';
case 14:
return L'e';
case 15:
return L'f';
case 16:
return L'g';
case 17:
return L'h';
case 18:
return L'i';
case 19:
return L'j';
case 20:
return L'k';
case 21:
return L'l';
case 22:
return L'm';
case 23:
return L'n';
case 24:
return L'o';
case 25:
return L'p';
case 26:
return L'q';
case 27:
return L'r';
case 28:
return L's';
case 29:
return L't';
case 30:
return L'u';
case 31:
return L'v';
case 32:
return L'w';
case 33:
return L'x';
case 34:
return L'y';
case 35:
return L'z';
default:
return L'!';
}
}
LIBC_INLINE static constexpr bool isspace(wchar_t wch) {
switch (wch) {
case L' ':
case L'\t':
case L'\n':
case L'\v':
case L'\f':
case L'\r':
return true;
default:
return false;
}
}
// An overload which provides a way to compare input with specific character
// values, when input can be of a regular or a wide character type.
LIBC_INLINE static constexpr bool
is_char_or_wchar(wchar_t ch, [[maybe_unused]] char, wchar_t wc_value) {
return (ch == wc_value);
}
} // namespace internal
} // namespace LIBC_NAMESPACE_DECL
#endif // LLVM_LIBC_SRC___SUPPORT_WCTYPE_UTILS_H