From 1576e4181c034ed905ff671bc8e9595ad259da4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Sat, 17 Jan 2026 05:48:20 +0100 Subject: [PATCH] llvm-libc: update to LLVM 22 --- lib/libcxx/libc/LICENSE.TXT | 278 +++++++++ lib/libcxx/libc/hdr/errno_macros.h | 4 +- lib/libcxx/libc/hdr/stdint_proxy.h | 18 + lib/libcxx/libc/hdr/types/wchar_t.h | 23 + lib/libcxx/libc/hdr/wchar_overlay.h | 69 ++ .../llvm-libc-macros/cfloat128-macros.h | 41 ++ .../llvm-libc-macros/cfloat16-macros.h | 20 + .../libc/include/llvm-libc-types/cfloat128.h | 39 +- .../libc/include/llvm-libc-types/cfloat16.h | 11 +- .../libc/include/llvm-libc-types/wchar_t.h | 19 + lib/libcxx/libc/shared/libc_common.h | 5 + lib/libcxx/libc/src/__support/CPP/bit.h | 62 +- .../__support/CPP/type_traits/is_complex.h | 7 + .../CPP/type_traits/is_destructible.h | 3 +- .../__support/CPP/type_traits/is_unsigned.h | 6 + .../__support/CPP/utility/integer_sequence.h | 10 + lib/libcxx/libc/src/__support/FPUtil/FPBits.h | 13 +- .../libc/src/__support/FPUtil/rounding_mode.h | 54 +- lib/libcxx/libc/src/__support/big_int.h | 28 +- lib/libcxx/libc/src/__support/common.h | 5 +- lib/libcxx/libc/src/__support/ctype_utils.h | 31 +- .../src/__support/detailed_powers_of_ten.h | 3 +- .../src/__support/high_precision_decimal.h | 47 +- lib/libcxx/libc/src/__support/libc_assert.h | 2 + .../libc/src/__support/macros/attributes.h | 45 +- lib/libcxx/libc/src/__support/macros/config.h | 23 + .../libc/src/__support/macros/null_check.h | 3 +- .../libc/src/__support/macros/optimization.h | 3 + .../macros/properties/architectures.h | 6 +- .../__support/macros/properties/compiler.h | 11 +- .../macros/properties/cpu_features.h | 18 +- .../src/__support/macros/properties/types.h | 5 +- .../libc/src/__support/macros/sanitizer.h | 10 - lib/libcxx/libc/src/__support/math_extras.h | 24 +- lib/libcxx/libc/src/__support/str_to_float.h | 223 +++---- .../libc/src/__support/str_to_integer.h | 66 +- lib/libcxx/libc/src/__support/wctype_utils.h | 588 ++++++++++++++++++ 37 files changed, 1542 insertions(+), 281 deletions(-) create mode 100644 lib/libcxx/libc/LICENSE.TXT create mode 100644 lib/libcxx/libc/hdr/stdint_proxy.h create mode 100644 lib/libcxx/libc/hdr/types/wchar_t.h create mode 100644 lib/libcxx/libc/hdr/wchar_overlay.h create mode 100644 lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h create mode 100644 lib/libcxx/libc/include/llvm-libc-macros/cfloat16-macros.h create mode 100644 lib/libcxx/libc/include/llvm-libc-types/wchar_t.h create mode 100644 lib/libcxx/libc/src/__support/wctype_utils.h diff --git a/lib/libcxx/libc/LICENSE.TXT b/lib/libcxx/libc/LICENSE.TXT new file mode 100644 index 0000000000..24806ab4c9 --- /dev/null +++ b/lib/libcxx/libc/LICENSE.TXT @@ -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. diff --git a/lib/libcxx/libc/hdr/errno_macros.h b/lib/libcxx/libc/hdr/errno_macros.h index 27ea49977d..e2913f45a8 100644 --- a/lib/libcxx/libc/hdr/errno_macros.h +++ b/lib/libcxx/libc/hdr/errno_macros.h @@ -15,7 +15,9 @@ #include #include "include/llvm-libc-macros/error-number-macros.h" -#else // __linux__ +#elif defined(__APPLE__) +#include +#else // __APPLE__ #include "include/llvm-libc-macros/generic-error-number-macros.h" #endif diff --git a/lib/libcxx/libc/hdr/stdint_proxy.h b/lib/libcxx/libc/hdr/stdint_proxy.h new file mode 100644 index 0000000000..8e815679a4 --- /dev/null +++ b/lib/libcxx/libc/hdr/stdint_proxy.h @@ -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 header. + +#include + +#endif // LLVM_LIBC_HDR_STDINT_PROXY_H diff --git a/lib/libcxx/libc/hdr/types/wchar_t.h b/lib/libcxx/libc/hdr/types/wchar_t.h new file mode 100644 index 0000000000..75e9452391 --- /dev/null +++ b/lib/libcxx/libc/hdr/types/wchar_t.h @@ -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 diff --git a/lib/libcxx/libc/hdr/wchar_overlay.h b/lib/libcxx/libc/hdr/wchar_overlay.h new file mode 100644 index 0000000000..52d3a0cc65 --- /dev/null +++ b/lib/libcxx/libc/hdr/wchar_overlay.h @@ -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 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 . +// 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 + +#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 diff --git a/lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h b/lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h new file mode 100644 index 0000000000..5f28cfa21a --- /dev/null +++ b/lib/libcxx/libc/include/llvm-libc-macros/cfloat128-macros.h @@ -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 diff --git a/lib/libcxx/libc/include/llvm-libc-macros/cfloat16-macros.h b/lib/libcxx/libc/include/llvm-libc-macros/cfloat16-macros.h new file mode 100644 index 0000000000..1f10adf3e3 --- /dev/null +++ b/lib/libcxx/libc/include/llvm-libc-macros/cfloat16-macros.h @@ -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 diff --git a/lib/libcxx/libc/include/llvm-libc-types/cfloat128.h b/lib/libcxx/libc/include/llvm-libc-types/cfloat128.h index 83fad87910..4b1d2543dd 100644 --- a/lib/libcxx/libc/include/llvm-libc-types/cfloat128.h +++ b/lib/libcxx/libc/include/llvm-libc-types/cfloat128.h @@ -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 diff --git a/lib/libcxx/libc/include/llvm-libc-types/cfloat16.h b/lib/libcxx/libc/include/llvm-libc-types/cfloat16.h index 2d4cef7562..644a6469f0 100644 --- a/lib/libcxx/libc/include/llvm-libc-types/cfloat16.h +++ b/lib/libcxx/libc/include/llvm-libc-types/cfloat16.h @@ -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 diff --git a/lib/libcxx/libc/include/llvm-libc-types/wchar_t.h b/lib/libcxx/libc/include/llvm-libc-types/wchar_t.h new file mode 100644 index 0000000000..bf2633a1c2 --- /dev/null +++ b/lib/libcxx/libc/include/llvm-libc-types/wchar_t.h @@ -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 diff --git a/lib/libcxx/libc/shared/libc_common.h b/lib/libcxx/libc/shared/libc_common.h index c4560bbb02..5f7bebdee0 100644 --- a/lib/libcxx/libc/shared/libc_common.h +++ b/lib/libcxx/libc/shared/libc_common.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/CPP/bit.h b/lib/libcxx/libc/src/__support/CPP/bit.h index e491f3e032..88d4362e67 100644 --- a/lib/libcxx/libc/src/__support/CPP/bit.h +++ b/lib/libcxx/libc/src/__support/CPP/bit.h @@ -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 - namespace LIBC_NAMESPACE_DECL { namespace cpp { @@ -26,6 +26,16 @@ namespace cpp { #define LLVM_LIBC_HAS_BUILTIN_MEMCPY_INLINE #endif +template +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 @@ -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(&to); const char *src = reinterpret_cast(&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(src, dst); return to; #endif // __has_builtin(__builtin_bit_cast) } +// The following simple bit copy from a smaller type to maybe-larger type. +template +LIBC_INLINE constexpr cpp::enable_if_t< + (sizeof(To) >= sizeof(From)) && + cpp::is_trivially_constructible::value && + cpp::is_trivially_copyable::value && + cpp::is_trivially_copyable::value, + void> +bit_copy(const From &from, To &to) { + MSAN_UNPOISON(&from, sizeof(From)); + char *dst = reinterpret_cast(&to); + const char *src = reinterpret_cast(&from); + inline_copy(src, dst); +} + template [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_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 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 diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_complex.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_complex.h index 23f05c08cc..5da1a40892 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_complex.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_complex.h @@ -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 struct is_complex : false_type {}; +#else template struct is_complex { private: template @@ -40,6 +45,8 @@ public: #endif >(); }; +#endif // LIBC_COMPILER_IS_MSVC + template LIBC_INLINE_VAR constexpr bool is_complex_v = is_complex::value; template diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_destructible.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_destructible.h index 830f22efaf..dc5e62b32d 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_destructible.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_destructible.h @@ -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 struct is_destructible : bool_constant<__is_destructible(T)> {}; #else diff --git a/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h b/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h index 3ae6337ceb..b4267eedd1 100644 --- a/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h +++ b/lib/libcxx/libc/src/__support/CPP/type_traits/is_unsigned.h @@ -16,6 +16,8 @@ #include "src/__support/macros/attributes.h" #include "src/__support/macros/config.h" +#include + 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 +struct is_unsigned : bool_constant {}; +#endif template LIBC_INLINE_VAR constexpr bool is_unsigned_v = is_unsigned::value; diff --git a/lib/libcxx/libc/src/__support/CPP/utility/integer_sequence.h b/lib/libcxx/libc/src/__support/CPP/utility/integer_sequence.h index 06643d505a..17c3dbfd22 100644 --- a/lib/libcxx/libc/src/__support/CPP/utility/integer_sequence.h +++ b/lib/libcxx/libc/src/__support/CPP/utility/integer_sequence.h @@ -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 + namespace LIBC_NAMESPACE_DECL { namespace cpp { @@ -34,6 +37,13 @@ template using make_integer_sequence = typename detail::make_integer_sequence::type; +// index sequence +template +using index_sequence = integer_sequence; +template +using make_index_sequence = + typename detail::make_integer_sequence::type; + } // namespace cpp } // namespace LIBC_NAMESPACE_DECL diff --git a/lib/libcxx/libc/src/__support/FPUtil/FPBits.h b/lib/libcxx/libc/src/__support/FPUtil/FPBits.h index 9e21136558..ce4925bae1 100644 --- a/lib/libcxx/libc/src/__support/FPUtil/FPBits.h +++ b/lib/libcxx/libc/src/__support/FPUtil/FPBits.h @@ -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 - namespace LIBC_NAMESPACE_DECL { namespace fputil { @@ -790,16 +789,16 @@ struct FPRep : public FPRepImpl> { // Returns the FPType corresponding to C++ type T on the host. template LIBC_INLINE static constexpr FPType get_fp_type() { using UnqualT = cpp::remove_cv_t; - if constexpr (cpp::is_same_v && __FLT_MANT_DIG__ == 24) + if constexpr (cpp::is_same_v && FLT_MANT_DIG == 24) return FPType::IEEE754_Binary32; - else if constexpr (cpp::is_same_v && __DBL_MANT_DIG__ == 53) + else if constexpr (cpp::is_same_v && DBL_MANT_DIG == 53) return FPType::IEEE754_Binary64; else if constexpr (cpp::is_same_v) { - 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) diff --git a/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h b/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h index bc66d09b94..fdc84986a4 100644 --- a/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h +++ b/lib/libcxx/libc/src/__support/FPUtil/rounding_mode.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/big_int.h b/lib/libcxx/libc/src/__support/big_int.h index 85db31d013..bb9cefd67b 100644 --- a/lib/libcxx/libc/src/__support/big_int.h +++ b/lib/libcxx/libc/src/__support/big_int.h @@ -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 // For size_t -#include namespace LIBC_NAMESPACE_DECL { @@ -95,10 +95,10 @@ LIBC_INLINE constexpr DoubleWide mul2(word a, word b) { #endif else { using half_word = half_width_t; - const auto shiftl = [](word value) -> word { + constexpr auto shiftl = [](word value) -> word { return value << cpp::numeric_limits::digits; }; - const auto shiftr = [](word value) -> word { + constexpr auto shiftr = [](word value) -> word { return value >> cpp::numeric_limits::digits; }; // Here we do a one digit multiplication where 'a' and 'b' are of type @@ -111,19 +111,19 @@ LIBC_INLINE constexpr DoubleWide 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(lo_digit, shiftl(step2), no_carry, carry); hi_digit = add_with_carry(hi_digit, shiftr(step2), carry, _); lo_digit = add_with_carry(lo_digit, shiftl(step3), no_carry, carry); diff --git a/lib/libcxx/libc/src/__support/common.h b/lib/libcxx/libc/src/__support/common.h index 15209b7697..a2808147f3 100644 --- a/lib/libcxx/libc/src/__support/common.h +++ b/lib/libcxx/libc/src/__support/common.h @@ -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__ diff --git a/lib/libcxx/libc/src/__support/ctype_utils.h b/lib/libcxx/libc/src/__support/ctype_utils.h index be0f25330a..d60562c02e 100644 --- a/lib/libcxx/libc/src/__support/ctype_utils.h +++ b/lib/libcxx/libc/src/__support/ctype_utils.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/detailed_powers_of_ten.h b/lib/libcxx/libc/src/__support/detailed_powers_of_ten.h index 28741b8a3f..ab6f2beb67 100644 --- a/lib/libcxx/libc/src/__support/detailed_powers_of_ten.h +++ b/lib/libcxx/libc/src/__support/detailed_powers_of_ten.h @@ -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 - namespace LIBC_NAMESPACE_DECL { namespace internal { diff --git a/lib/libcxx/libc/src/__support/high_precision_decimal.h b/lib/libcxx/libc/src/__support/high_precision_decimal.h index cb4b50c315..75f2a7607b 100644 --- a/lib/libcxx/libc/src/__support/high_precision_decimal.h +++ b/lib/libcxx/libc/src/__support/high_precision_decimal.h @@ -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 +#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 struct constants; +template <> struct constants { + 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 { + 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 + LIBC_INLINE HighPrecisionDecimal( + const CharType *__restrict num_string, const size_t num_len = cpp::numeric_limits::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::DECIMAL_POINT)) { + if (num_string[num_cur] == constants::DECIMAL_POINT) { if (saw_dot) { break; } this->decimal_point = static_cast(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( - internal::b36_char_to_int(num_string[num_cur])); + this->digits[this->num_digits] = static_cast(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(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::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(num_string + num_cur, 10, num_len - num_cur); if (result.has_error()) { diff --git a/lib/libcxx/libc/src/__support/libc_assert.h b/lib/libcxx/libc/src/__support/libc_assert.h index ada1795ccb..6e0b5bd3d6 100644 --- a/lib/libcxx/libc/src/__support/libc_assert.h +++ b/lib/libcxx/libc/src/__support/libc_assert.h @@ -14,9 +14,11 @@ // The build is configured to just use the public API // for libc's internal assertions. +#ifndef LIBC_ASSERT #include #define LIBC_ASSERT(COND) assert(COND) +#endif // LIBC_ASSERT #else // Not LIBC_COPT_USE_C_ASSERT diff --git a/lib/libcxx/libc/src/__support/macros/attributes.h b/lib/libcxx/libc/src/__support/macros/attributes.h index c6474673de..d5ff028634 100644 --- a/lib/libcxx/libc/src/__support/macros/attributes.h +++ b/lib/libcxx/libc/src/__support/macros/attributes.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/macros/config.h b/lib/libcxx/libc/src/__support/macros/config.h index 2ab0fba095..b06a890c9c 100644 --- a/lib/libcxx/libc/src/__support/macros/config.h +++ b/lib/libcxx/libc/src/__support/macros/config.h @@ -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 +#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 diff --git a/lib/libcxx/libc/src/__support/macros/null_check.h b/lib/libcxx/libc/src/__support/macros/null_check.h index abf65c56c4..438ba69c0a 100644 --- a/lib/libcxx/libc/src/__support/macros/null_check.h +++ b/lib/libcxx/libc/src/__support/macros/null_check.h @@ -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)) \ diff --git a/lib/libcxx/libc/src/__support/macros/optimization.h b/lib/libcxx/libc/src/__support/macros/optimization.h index 250a9e0607..dbefd20a5c 100644 --- a/lib/libcxx/libc/src/__support/macros/optimization.h +++ b/lib/libcxx/libc/src/__support/macros/optimization.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/macros/properties/architectures.h b/lib/libcxx/libc/src/__support/macros/properties/architectures.h index c88956ff41..21e9bc4288 100644 --- a/lib/libcxx/libc/src/__support/macros/properties/architectures.h +++ b/lib/libcxx/libc/src/__support/macros/properties/architectures.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/macros/properties/compiler.h b/lib/libcxx/libc/src/__support/macros/properties/compiler.h index b9ec0dd1de..592f6c2ba1 100644 --- a/lib/libcxx/libc/src/__support/macros/properties/compiler.h +++ b/lib/libcxx/libc/src/__support/macros/properties/compiler.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h b/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h index cdb2df97b2..1fe20d9b23 100644 --- a/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h +++ b/lib/libcxx/libc/src/__support/macros/properties/cpu_features.h @@ -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) diff --git a/lib/libcxx/libc/src/__support/macros/properties/types.h b/lib/libcxx/libc/src/__support/macros/properties/types.h index aec4a488c3..3259c8a6a1 100644 --- a/lib/libcxx/libc/src/__support/macros/properties/types.h +++ b/lib/libcxx/libc/src/__support/macros/properties/types.h @@ -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 // UINT64_MAX, __SIZEOF_INT128__ - // 'long double' properties. #if (LDBL_MANT_DIG == 53) #define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64 diff --git a/lib/libcxx/libc/src/__support/macros/sanitizer.h b/lib/libcxx/libc/src/__support/macros/sanitizer.h index c20412e0f8..84268a19ab 100644 --- a/lib/libcxx/libc/src/__support/macros/sanitizer.h +++ b/lib/libcxx/libc/src/__support/macros/sanitizer.h @@ -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 diff --git a/lib/libcxx/libc/src/__support/math_extras.h b/lib/libcxx/libc/src/__support/math_extras.h index 47df2a4325..3d0f2703b6 100644 --- a/lib/libcxx/libc/src/__support/math_extras.h +++ b/lib/libcxx/libc/src/__support/math_extras.h @@ -25,7 +25,13 @@ LIBC_INLINE constexpr cpp::enable_if_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 [[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 [[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) \ - 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 template [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_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 [[nodiscard]] LIBC_INLINE constexpr cpp::enable_if_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) diff --git a/lib/libcxx/libc/src/__support/str_to_float.h b/lib/libcxx/libc/src/__support/str_to_float.h index a7dd7ce0ae..873a113780 100644 --- a/lib/libcxx/libc/src/__support/str_to_float.h +++ b/lib/libcxx/libc/src/__support/str_to_float.h @@ -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 +#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 +template LIBC_INLINE FloatConvertReturn simple_decimal_conversion( - const char *__restrict numStart, + const CharType *__restrict numStart, const size_t num_len = cpp::numeric_limits::max(), RoundDirection round = RoundDirection::Nearest) { using FPBits = typename fputil::FPBits; @@ -677,12 +677,11 @@ template <> LIBC_INLINE constexpr int32_t get_lower_bound() { // 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 +// accuracy. +template LIBC_INLINE FloatConvertReturn decimal_exp_to_float( ExpandedFloat init_num, bool truncated, RoundDirection round, - const char *__restrict numStart, + const CharType *__restrict numStart, const size_t num_len = cpp::numeric_limits::max()) { using FPBits = typename fputil::FPBits; using StorageType = typename FPBits::StorageType; @@ -861,36 +860,42 @@ LIBC_INLINE FloatConvertReturn binary_exp_to_float(ExpandedFloat 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 +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::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 -LIBC_INLINE StrToNumResult> -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 +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 +LIBC_INLINE static StrToNumResult> +decimal_string_to_float(const CharType *__restrict src, RoundDirection round) { using FPBits = typename fputil::FPBits; 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::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(has_sign)])) { + // exponent marker, see scanf for more details. + if (tolower(src[index]) == constants::DECIMAL_EXPONENT_MARKER) { + int sign = get_sign(src + index + 1); + if (isdigit(src[index + 1 + static_cast(sign != 0)])) { ++index; auto result = strtointeger(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 -LIBC_INLINE StrToNumResult> -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 +LIBC_INLINE static StrToNumResult> +hexadecimal_string_to_float(const CharType *__restrict src, + RoundDirection round) { using FPBits = typename fputil::FPBits; 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::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(has_sign)])) { + if (tolower(src[index]) == constants::HEX_EXPONENT_MARKER) { + int sign = get_sign(src + index + 1); + if (isdigit(src[index + 1 + static_cast(sign != 0)])) { ++index; auto result = strtointeger(src + index, 10); if (result.has_error()) @@ -1099,21 +1092,21 @@ hexadecimal_string_to_float(const char *__restrict src, return output; } -template +template LIBC_INLINE typename fputil::FPBits::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; using StorageType = typename FPBits::StorageType; StorageType nan_mantissa = 0; - if (ncharseq.data() != nullptr && isdigit(ncharseq[0])) { + if (len > 0 && isdigit(str[0])) { StrToNumResult strtoint_result = - strtointeger(ncharseq.data(), 0); + strtointeger(str, 0, len); if (!strtoint_result.has_error()) nan_mantissa = strtoint_result.value; - if (strtoint_result.parsed_len != static_cast(ncharseq.size())) + if (strtoint_result.parsed_len != static_cast(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 -LIBC_INLINE StrToNumResult strtofloatingpoint(const char *__restrict src) { +template +LIBC_INLINE StrToNumResult +strtofloatingpoint(const CharType *__restrict src) { using FPBits = typename fputil::FPBits; 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::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 strtofloatingpoint(const char *__restrict src) { StrToNumResult> parse_result({0, 0}); if (base == 16) { - parse_result = hexadecimal_string_to_float(src + index, DECIMAL_POINT, - round_direction); + parse_result = + hexadecimal_string_to_float(src + index, round_direction); } else { // base is 10 - parse_result = decimal_string_to_float(src + index, DECIMAL_POINT, - round_direction); + parse_result = decimal_string_to_float(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::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( - 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(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::INF_STRING)) { + // INFINITY + seen_digit = true; + result = FPBits(result.inf(result.sign())); + index += 8; + } else if (tolower_starts_with(src + index, 3, + constants::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 LIBC_INLINE StrToNumResult strtonan(const char *arg) { ++index; if (arg[index] == '\0') - nan_mantissa = nan_mantissa_from_ncharseq(cpp::string_view(arg, index)); + nan_mantissa = nan_mantissa_from_ncharseq(arg, index); result = FPBits::quiet_nan(Sign::POS, nan_mantissa); return {result.get_val(), 0, error}; diff --git a/lib/libcxx/libc/src/__support/str_to_integer.h b/lib/libcxx/libc/src/__support/str_to_integer.h index d332c929f2..2df1ea894e 100644 --- a/lib/libcxx/libc/src/__support/str_to_integer.h +++ b/lib/libcxx/libc/src/__support/str_to_integer.h @@ -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 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::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 +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::max()) { +template +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 +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 +template LIBC_INLINE StrToNumResult -strtointeger(const char *__restrict src, int base, +strtointeger(const CharType *__restrict src, int base, const size_t src_len = cpp::numeric_limits::max()) { using ResultType = make_integral_or_big_int_unsigned_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; - const bool is_positive = (result_sign == '+'); - ResultType constexpr NEGATIVE_MAX = !IS_UNSIGNED ? static_cast(cpp::numeric_limits::max()) + 1 : cpp::numeric_limits::max(); @@ -120,6 +129,9 @@ strtointeger(const char *__restrict src, int base, ResultType const abs_max_div_by_base = abs_max / static_cast(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) diff --git a/lib/libcxx/libc/src/__support/wctype_utils.h b/lib/libcxx/libc/src/__support/wctype_utils.h new file mode 100644 index 0000000000..7f17224104 --- /dev/null +++ b/lib/libcxx/libc/src/__support/wctype_utils.h @@ -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