https://github.com/mysterymath updated https://github.com/llvm/llvm-project/pull/147426
>From 1d82299331f9a3d4ff3293ea559fcdb6c4f19d33 Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh <[email protected]> Date: Thu, 19 Dec 2024 11:57:27 -0800 Subject: [PATCH 1/2] [libc] Modular printf option (float only) This adds LIBC_CONF_PRINTF_MODULAR, which causes floating point support (later, others) to be weakly linked into the implementation. __printf_modular becomes the main entry point of the implementaiton, an printf itself wraps __printf_modular. printf it also contains a BFD_RELOC_NONE relocation to bring in the float aspect. See issue #146159 for context. --- libc/config/config.json | 4 ++ libc/docs/configure.rst | 1 + libc/include/CMakeLists.txt | 1 + libc/include/llvm-libc-macros/CMakeLists.txt | 22 ++++++- .../_LIBC_MODULAR_FORMAT_PRINTF-disable.h | 14 +++++ .../_LIBC_MODULAR_FORMAT_PRINTF.h | 15 +++++ libc/include/stdio.yaml | 16 +++++ libc/src/stdio/CMakeLists.txt | 40 +++++++++++-- libc/src/stdio/asprintf.cpp | 5 ++ libc/src/stdio/asprintf.h | 1 + libc/src/stdio/asprintf_modular.cpp | 43 ++++++++++++++ libc/src/stdio/baremetal/CMakeLists.txt | 12 +++- libc/src/stdio/baremetal/printf.cpp | 5 ++ libc/src/stdio/baremetal/printf_modular.cpp | 32 ++++++++++ libc/src/stdio/baremetal/vfprintf.cpp | 5 ++ libc/src/stdio/baremetal/vfprintf_internal.h | 5 +- libc/src/stdio/baremetal/vprintf.cpp | 5 ++ libc/src/stdio/baremetal/vprintf_modular.cpp | 30 ++++++++++ libc/src/stdio/generic/CMakeLists.txt | 4 ++ libc/src/stdio/gpu/CMakeLists.txt | 4 ++ libc/src/stdio/printf.h | 1 + libc/src/stdio/printf_core/CMakeLists.txt | 7 ++- .../stdio/printf_core/float_dec_converter.h | 13 +++++ .../printf_core/float_dec_converter_limited.h | 13 +++++ .../stdio/printf_core/float_hex_converter.h | 6 ++ libc/src/stdio/printf_core/float_impl.cpp | 56 ++++++++++++++++++ libc/src/stdio/printf_core/parser.h | 58 ++++++++++++++----- libc/src/stdio/printf_core/printf_config.h | 7 +++ libc/src/stdio/printf_core/printf_main.h | 16 ++++- .../stdio/printf_core/vasprintf_internal.h | 5 +- .../src/stdio/printf_core/vfprintf_internal.h | 18 ++++-- libc/src/stdio/snprintf.cpp | 5 ++ libc/src/stdio/snprintf.h | 2 + libc/src/stdio/snprintf_modular.cpp | 54 +++++++++++++++++ libc/src/stdio/sprintf.cpp | 5 ++ libc/src/stdio/sprintf.h | 2 + libc/src/stdio/sprintf_modular.cpp | 54 +++++++++++++++++ libc/src/stdio/vasprintf.cpp | 5 ++ libc/src/stdio/vasprintf.h | 2 + libc/src/stdio/vasprintf_modular.cpp | 38 ++++++++++++ libc/src/stdio/vprintf.h | 1 + libc/src/stdio/vsnprintf.cpp | 5 ++ libc/src/stdio/vsnprintf.h | 2 + libc/src/stdio/vsnprintf_modular.cpp | 51 ++++++++++++++++ libc/src/stdio/vsprintf.cpp | 5 ++ libc/src/stdio/vsprintf.h | 2 + libc/src/stdio/vsprintf_modular.cpp | 50 ++++++++++++++++ libc/utils/hdrgen/hdrgen/header.py | 2 +- .../tests/expected_output/test_header.h | 3 +- .../tests/expected_output/test_small.json | 1 + libc/utils/hdrgen/tests/input/merge1.yaml | 1 + 51 files changed, 720 insertions(+), 34 deletions(-) create mode 100644 libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h create mode 100644 libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h create mode 100644 libc/src/stdio/asprintf_modular.cpp create mode 100644 libc/src/stdio/baremetal/printf_modular.cpp create mode 100644 libc/src/stdio/baremetal/vprintf_modular.cpp create mode 100644 libc/src/stdio/printf_core/float_impl.cpp create mode 100644 libc/src/stdio/snprintf_modular.cpp create mode 100644 libc/src/stdio/sprintf_modular.cpp create mode 100644 libc/src/stdio/vasprintf_modular.cpp create mode 100644 libc/src/stdio/vsnprintf_modular.cpp create mode 100644 libc/src/stdio/vsprintf_modular.cpp diff --git a/libc/config/config.json b/libc/config/config.json index 296d2e539c23d..e598be7ee0479 100644 --- a/libc/config/config.json +++ b/libc/config/config.json @@ -56,6 +56,10 @@ "LIBC_CONF_PRINTF_DISABLE_WIDE": { "value": false, "doc": "Disable handling wide characters for printf and friends." + }, + "LIBC_CONF_PRINTF_MODULAR": { + "value": false, + "doc": "Split printf implementation into modules that can be lazily linked in." } }, "scanf": { diff --git a/libc/docs/configure.rst b/libc/docs/configure.rst index 68bacfd74fd33..56a9ef4574db9 100644 --- a/libc/docs/configure.rst +++ b/libc/docs/configure.rst @@ -49,6 +49,7 @@ to learn about the defaults for your platform and target. - ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_DYADIC_FLOAT``: Use dyadic float for faster and smaller but less accurate printf doubles. - ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_FLOAT320``: Use an alternative printf float implementation based on 320-bit floats - ``LIBC_CONF_PRINTF_FLOAT_TO_STR_USE_MEGA_LONG_DOUBLE_TABLE``: Use large table for better printf long double performance. + - ``LIBC_CONF_PRINTF_MODULAR``: Split printf implementation into modules that can be lazily linked in. - ``LIBC_CONF_PRINTF_RUNTIME_DISPATCH``: Use dynamic dispatch for the output mechanism to reduce code size. * **"pthread" options** - ``LIBC_CONF_RAW_MUTEX_DEFAULT_SPIN_COUNT``: Default number of spins before blocking if a mutex is in contention (default to 100). diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt index 1bc9c2ca1a51d..f609693ce5ddc 100644 --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -359,6 +359,7 @@ add_header_macro( ../libc/include/stdio.yaml stdio.h DEPENDS + .llvm-libc-macros._LIBC_MODULAR_FORMAT_PRINTF .llvm-libc-macros.file_seek_macros .llvm-libc-macros.null_macro .llvm-libc-macros.stdio_macros diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt index b16337cccd58b..120277edcb3a7 100644 --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -3,15 +3,19 @@ function(add_macro_header name) cmake_parse_arguments( "MACRO_HEADER" "" # Optional arguments - "HDR" # Single value arguments + "HDR;DEST_HDR" # Single value arguments "DEPENDS" # Multi-value arguments ${ARGN} ) + if (MACRO_HEADER_DEST_HDR) + set(dest_header_arg DEST_HDR ${MACRO_HEADER_DEST_HDR}) + endif() if(TARGET libc.include.llvm-libc-macros.${LIBC_TARGET_OS}.${name}) add_header( ${name} HDR ${MACRO_HEADER_HDR} + ${dest_header_arg} DEPENDS .${LIBC_TARGET_OS}.${name} ${MACRO_HEADER_DEPENDS} @@ -21,6 +25,7 @@ function(add_macro_header name) ${name} HDR ${MACRO_HEADER_HDR} + ${dest_header_arg} DEPENDS ${MACRO_HEADER_DEPENDS} ) @@ -383,3 +388,18 @@ add_macro_header( sysexits-macros.h ) +if (LIBC_CONF_MODULAR_FORMAT) + add_macro_header( + _LIBC_MODULAR_FORMAT_PRINTF + HDR + _LIBC_MODULAR_FORMAT_PRINTF.h + ) +else() + add_macro_header( + _LIBC_MODULAR_FORMAT_PRINTF + HDR + _LIBC_MODULAR_FORMAT_PRINTF-disable.h + DEST_HDR + _LIBC_MODULAR_FORMAT_PRINTF.h + ) +endif() diff --git a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h new file mode 100644 index 0000000000000..e3238161b3808 --- /dev/null +++ b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF-disable.h @@ -0,0 +1,14 @@ +//===-- Definition to disable modular format macro for printf -------------===// +// +// 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_LIBC_MODULAR_FORMAT_PRINTF_H +#define LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H + +#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN) + +#endif // LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H diff --git a/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h new file mode 100644 index 0000000000000..918241ab8f2ec --- /dev/null +++ b/libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h @@ -0,0 +1,15 @@ +//===-- Definition of modular format macro for printf ---------------------===// +// +// 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_LIBC_MODULAR_FORMAT_PRINTF_H +#define LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H + +#define _LIBC_MODULAR_FORMAT_PRINTF(MODULAR_IMPL_FN) \ + __attribute__((modular_format(MODULAR_IMPL_FN, "__printf", "float"))) + +#endif // LLVM_LIBC_MACROS_LIBC_MODULAR_FORMAT_PRINTF_H diff --git a/libc/include/stdio.yaml b/libc/include/stdio.yaml index c50b4ecb0bf08..67eeeaf07bdd1 100644 --- a/libc/include/stdio.yaml +++ b/libc/include/stdio.yaml @@ -31,6 +31,8 @@ functions: - type: char **__restrict - type: const char *__restrict - type: '...' + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__asprintf_modular) - name: clearerr standards: - stdc @@ -276,6 +278,8 @@ functions: arguments: - type: const char *__restrict - type: '...' + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__printf_modular) - name: putc standards: - stdc @@ -347,6 +351,8 @@ functions: - type: size_t - type: const char *__restrict - type: '...' + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__snprintf_modular) - name: sprintf standards: - stdc @@ -355,6 +361,8 @@ functions: - type: char *__restrict - type: const char *__restrict - type: '...' + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__sprintf_modular) - name: sscanf standards: - stdc @@ -378,6 +386,8 @@ functions: - type: char **__restrict - type: const char *__restrict - type: va_list + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__vasprintf_modular) - name: vfprintf standards: - stdc @@ -393,6 +403,8 @@ functions: arguments: - type: const char *__restrict - type: va_list + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__vprintf_modular) - name: vsnprintf standards: - stdc @@ -402,6 +414,8 @@ functions: - type: size_t - type: const char *__restrict - type: va_list + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__vsnprintf_modular) - name: vsprintf standards: - stdc @@ -410,6 +424,8 @@ functions: - type: char *__restrict - type: const char *__restrict - type: va_list + attributes: + - _LIBC_MODULAR_FORMAT_PRINTF(__vsprintf_modular) - name: vsscanf standards: - stdc diff --git a/libc/src/stdio/CMakeLists.txt b/libc/src/stdio/CMakeLists.txt index c75c8b11be2b5..9486a53499792 100644 --- a/libc/src/stdio/CMakeLists.txt +++ b/libc/src/stdio/CMakeLists.txt @@ -116,10 +116,15 @@ add_entrypoint_object( libc.src.stdio.scanf_core.string_reader ) +set(sprintf_srcs sprintf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND sprintf_srcs sprintf_modular.cpp) +endif() + add_entrypoint_object( sprintf SRCS - sprintf.cpp + ${sprintf_srcs} HDRS sprintf.h DEPENDS @@ -131,10 +136,14 @@ add_entrypoint_object( libc.src.__support.CPP.limits ) +set(snprintf_srcs snprintf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND snprintf_srcs snprintf_modular.cpp) +endif() add_entrypoint_object( snprintf SRCS - snprintf.cpp + ${snprintf_srcs} HDRS snprintf.h DEPENDS @@ -146,10 +155,14 @@ add_entrypoint_object( libc.src.__support.CPP.limits ) +set(asprintf_srcs asprintf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND asprintf_srcs asprintf_modular.cpp) +endif() add_entrypoint_object( asprintf SRCS - asprintf.cpp + ${asprintf_srcs} HDRS asprintf.h DEPENDS @@ -160,10 +173,15 @@ add_entrypoint_object( libc.src.__support.CPP.limits ) +set(vsprintf_srcs vsprintf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND vsprintf_srcs vsprintf_modular.cpp) +endif() + add_entrypoint_object( vsprintf SRCS - vsprintf.cpp + ${vsprintf_srcs} HDRS vsprintf.h DEPENDS @@ -175,10 +193,15 @@ add_entrypoint_object( libc.src.__support.CPP.limits ) +set(vsnprintf_srcs vsnprintf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND vsnprintf_srcs vsnprintf_modular.cpp) +endif() + add_entrypoint_object( vsnprintf SRCS - vsnprintf.cpp + ${vsnprintf_srcs} HDRS vsnprintf.h DEPENDS @@ -190,10 +213,15 @@ add_entrypoint_object( libc.src.__support.CPP.limits ) +set(vasprintf_srcs vasprintf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND vasprintf_srcs vasprintf_modular.cpp) +endif() + add_entrypoint_object( vasprintf SRCS - vasprintf.cpp + ${vasprintf_srcs} HDRS vasprintf.h DEPENDS diff --git a/libc/src/stdio/asprintf.cpp b/libc/src/stdio/asprintf.cpp index 0991dfca6a059..f80d2a5eb759d 100644 --- a/libc/src/stdio/asprintf.cpp +++ b/libc/src/stdio/asprintf.cpp @@ -26,7 +26,12 @@ LLVM_LIBC_FUNCTION(int, asprintf, // and pointer semantics, as well as handling // destruction automatically. va_end(vlist); +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + auto ret_val = printf_core::vasprintf_internal<true>(buffer, format, args); +#else auto ret_val = printf_core::vasprintf_internal(buffer, format, args); +#endif if (!ret_val.has_value()) { libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; diff --git a/libc/src/stdio/asprintf.h b/libc/src/stdio/asprintf.h index 168721c4f98b9..26a1f1687aedd 100644 --- a/libc/src/stdio/asprintf.h +++ b/libc/src/stdio/asprintf.h @@ -14,6 +14,7 @@ namespace LIBC_NAMESPACE_DECL { int asprintf(char **__restrict s, const char *__restrict format, ...); +int __asprintf_modular(char **__restrict s, const char *__restrict format, ...); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/asprintf_modular.cpp b/libc/src/stdio/asprintf_modular.cpp new file mode 100644 index 0000000000000..74b62cc0c2501 --- /dev/null +++ b/libc/src/stdio/asprintf_modular.cpp @@ -0,0 +1,43 @@ +//===-- Implementation of asprintf_modular ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/CPP/limits.h" +#include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/asprintf.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_mapper.h" +#include "src/stdio/printf_core/vasprintf_internal.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __asprintf_modular, + (char **__restrict buffer, const char *__restrict format, + ...)) { + va_list vlist; + va_start(vlist, format); + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + va_end(vlist); + auto ret_val = printf_core::vasprintf_internal<true>(buffer, format, args); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); + return -1; + } + if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); + return -1; + } + + return static_cast<int>(ret_val.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/CMakeLists.txt b/libc/src/stdio/baremetal/CMakeLists.txt index a706accecf152..878aca8ca0fc2 100644 --- a/libc/src/stdio/baremetal/CMakeLists.txt +++ b/libc/src/stdio/baremetal/CMakeLists.txt @@ -186,10 +186,14 @@ add_entrypoint_object( libc.include.stdio ) +set(printf_srcs printf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND printf_srcs printf_modular.cpp) +endif() add_entrypoint_object( printf SRCS - printf.cpp + ${printf_srcs} HDRS ../printf.h DEPENDS @@ -274,10 +278,14 @@ add_entrypoint_object( libc.src.__support.arg_list ) +set(vprintf_srcs vprintf.cpp) +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND vprintf_srcs vprintf_modular.cpp) +endif() add_entrypoint_object( vprintf SRCS - vprintf.cpp + ${vprintf_srcs} HDRS ../vprintf.h DEPENDS diff --git a/libc/src/stdio/baremetal/printf.cpp b/libc/src/stdio/baremetal/printf.cpp index 5010810906e24..b43bc1e92528f 100644 --- a/libc/src/stdio/baremetal/printf.cpp +++ b/libc/src/stdio/baremetal/printf.cpp @@ -26,7 +26,12 @@ LLVM_LIBC_FUNCTION(int, printf, (const char *__restrict format, ...)) { // destruction automatically. va_end(vlist); +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + return vfprintf_internal<true>(stdout, format, args); +#else return vfprintf_internal(stdout, format, args); +#endif } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/printf_modular.cpp b/libc/src/stdio/baremetal/printf_modular.cpp new file mode 100644 index 0000000000000..f03060a9c3ff5 --- /dev/null +++ b/libc/src/stdio/baremetal/printf_modular.cpp @@ -0,0 +1,32 @@ +//===-- Implementation of printf_modular for baremetal ----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/printf.h" + +#include "hdr/stdio_macros.h" +#include "src/__support/arg_list.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/vfprintf_internal.h" + +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __printf_modular, (const char *__restrict format, ...)) { + va_list vlist; + va_start(vlist, format); + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + va_end(vlist); + + return vfprintf_internal<true>(stdout, format, args); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vfprintf.cpp b/libc/src/stdio/baremetal/vfprintf.cpp index 2393ca4bcdb3e..c068a10181911 100644 --- a/libc/src/stdio/baremetal/vfprintf.cpp +++ b/libc/src/stdio/baremetal/vfprintf.cpp @@ -25,7 +25,12 @@ LLVM_LIBC_FUNCTION(int, vfprintf, // and pointer semantics, as well as handling // destruction automatically. +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + return vfprintf_internal<true>(stream, format, args); +#else return vfprintf_internal(stream, format, args); +#endif } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vfprintf_internal.h b/libc/src/stdio/baremetal/vfprintf_internal.h index d38a56481bc37..50eaef4a4a3e2 100644 --- a/libc/src/stdio/baremetal/vfprintf_internal.h +++ b/libc/src/stdio/baremetal/vfprintf_internal.h @@ -38,6 +38,7 @@ LIBC_INLINE int write_hook(cpp::string_view str_view, void *cookie) { } // namespace internal +template <bool use_modular = false> LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream, const char *__restrict format, internal::ArgList &args) { @@ -48,7 +49,9 @@ LIBC_INLINE int vfprintf_internal(::FILE *__restrict stream, stream); printf_core::Writer writer(wb); - auto retval = printf_core::printf_main(&writer, format, args); + auto retval = use_modular + ? printf_core::printf_main_modular(&writer, format, args) + : printf_core::printf_main(&writer, format, args); if (!retval.has_value()) { libc_errno = printf_core::internal_error_to_errno(retval.error()); return -1; diff --git a/libc/src/stdio/baremetal/vprintf.cpp b/libc/src/stdio/baremetal/vprintf.cpp index 38f12ab09fa25..e2144b8d8175b 100644 --- a/libc/src/stdio/baremetal/vprintf.cpp +++ b/libc/src/stdio/baremetal/vprintf.cpp @@ -24,7 +24,12 @@ LLVM_LIBC_FUNCTION(int, vprintf, // and pointer semantics, as well as handling // destruction automatically. +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + return vfprintf_internal<true>(stdout, format, args); +#else return vfprintf_internal(stdout, format, args); +#endif } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/baremetal/vprintf_modular.cpp b/libc/src/stdio/baremetal/vprintf_modular.cpp new file mode 100644 index 0000000000000..b14e0fae585bd --- /dev/null +++ b/libc/src/stdio/baremetal/vprintf_modular.cpp @@ -0,0 +1,30 @@ +//===-- Implementation of vprintf_modular -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/vprintf.h" + +#include "hdr/stdio_macros.h" +#include "src/__support/arg_list.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/stdio/baremetal/vfprintf_internal.h" + +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __vprintf_modular, + (const char *__restrict format, va_list vlist)) { + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + + return vfprintf_internal<true>(stdout, format, args); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/generic/CMakeLists.txt b/libc/src/stdio/generic/CMakeLists.txt index 71055edea3d9e..18da01b19d27a 100644 --- a/libc/src/stdio/generic/CMakeLists.txt +++ b/libc/src/stdio/generic/CMakeLists.txt @@ -416,6 +416,10 @@ if(LLVM_LIBC_FULL_BUILD) ) endif() +if (LIBC_CONF_PRINTF_MODULAR AND NOT LIBC_TARGET_OS_IS_BAREMETAL) + message(FATAL_ERROR "modular printf is only supported in baremetal stdio") +endif() + add_generic_entrypoint_object( printf SRCS diff --git a/libc/src/stdio/gpu/CMakeLists.txt b/libc/src/stdio/gpu/CMakeLists.txt index 8412153bf5801..2aea66482997f 100644 --- a/libc/src/stdio/gpu/CMakeLists.txt +++ b/libc/src/stdio/gpu/CMakeLists.txt @@ -1,3 +1,7 @@ +if (LIBC_CONF_PRINTF_MODULAR) + message(FATAL_ERROR "modular printf is only supported in baremetal stdio") +endif() + add_entrypoint_object( stdin SRCS diff --git a/libc/src/stdio/printf.h b/libc/src/stdio/printf.h index 9e47ad8680f9c..81b7d866a6a59 100644 --- a/libc/src/stdio/printf.h +++ b/libc/src/stdio/printf.h @@ -15,6 +15,7 @@ namespace LIBC_NAMESPACE_DECL { int printf(const char *__restrict format, ...); +int __printf_modular(const char *__restrict format, ...); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index ae93cc754299b..1a6b6383bf4d4 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -28,6 +28,9 @@ endif() if(LIBC_CONF_PRINTF_RUNTIME_DISPATCH) list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_RUNTIME_DISPATCH") endif() +if(LIBC_CONF_PRINTF_MODULAR) + list(APPEND printf_config_copts "-DLIBC_COPT_PRINTF_MODULAR") +endif() if(printf_config_copts) list(PREPEND printf_config_copts "COMPILE_OPTIONS") endif() @@ -146,10 +149,12 @@ add_header_library( ${wchar_deps} ) -add_header_library( +add_object_library( printf_main HDRS printf_main.h + SRCS + float_impl.cpp DEPENDS .parser .converter diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h index ed004f9a26a13..1b0a02ed426c1 100644 --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -1122,6 +1122,18 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<write_mode> *writer, } } +template <WriteMode write_mode> +LIBC_PRINTF_MODULAR_DECL int +convert_float_decimal(Writer<write_mode> *writer, const FormatSection &to_conv); +template <WriteMode write_mode> +LIBC_PRINTF_MODULAR_DECL int +convert_float_dec_exp(Writer<write_mode> *writer, const FormatSection &to_conv); +template <WriteMode write_mode> +LIBC_PRINTF_MODULAR_DECL int +convert_float_dec_auto(Writer<write_mode> *writer, + const FormatSection &to_conv); + +#ifdef LIBC_PRINTF_DEFINE_MODULAR // TODO: unify the float converters to remove the duplicated checks for inf/nan. template <WriteMode write_mode> @@ -1189,6 +1201,7 @@ LIBC_INLINE int convert_float_dec_auto(Writer<write_mode> *writer, return convert_inf_nan(writer, to_conv); } +#endif } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/float_dec_converter_limited.h b/libc/src/stdio/printf_core/float_dec_converter_limited.h index 0f85d0a8d26b4..2fc2a180ae2b9 100644 --- a/libc/src/stdio/printf_core/float_dec_converter_limited.h +++ b/libc/src/stdio/printf_core/float_dec_converter_limited.h @@ -676,6 +676,18 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer<write_mode> *writer, return convert_float_typed<T>(writer, to_conv, float_bits, ConversionType::G); } +template <WriteMode write_mode> +LIBC_PRINTF_MODULAR_DECL int +convert_float_decimal(Writer<write_mode> *writer, const FormatSection &to_conv); +template <WriteMode write_mode> +LIBC_PRINTF_MODULAR_DECL int +convert_float_dec_exp(Writer<write_mode> *writer, const FormatSection &to_conv); +template <WriteMode write_mode> +LIBC_PRINTF_MODULAR_DECL int +convert_float_dec_auto(Writer<write_mode> *writer, + const FormatSection &to_conv); + +#ifdef LIBC_PRINTF_DEFINE_MODULAR template <WriteMode write_mode> LIBC_INLINE int convert_float_decimal(Writer<write_mode> *writer, const FormatSection &to_conv) { @@ -693,6 +705,7 @@ LIBC_INLINE int convert_float_dec_auto(Writer<write_mode> *writer, const FormatSection &to_conv) { return convert_float_outer(writer, to_conv, ConversionType::G); } +#endif } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h index 9b57f1d803e74..d2be294dc47ab 100644 --- a/libc/src/stdio/printf_core/float_hex_converter.h +++ b/libc/src/stdio/printf_core/float_hex_converter.h @@ -25,6 +25,11 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { +template <WriteMode write_mode> +LIBC_PRINTF_MODULAR_DECL int +convert_float_hex_exp(Writer<write_mode> *writer, const FormatSection &to_conv); + +#ifdef LIBC_PRINTF_DEFINE_MODULAR template <WriteMode write_mode> LIBC_INLINE int convert_float_hex_exp(Writer<write_mode> *writer, const FormatSection &to_conv) { @@ -253,6 +258,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer<write_mode> *writer, } return WRITE_OK; } +#endif } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/float_impl.cpp b/libc/src/stdio/printf_core/float_impl.cpp new file mode 100644 index 0000000000000..2215ac101f47d --- /dev/null +++ b/libc/src/stdio/printf_core/float_impl.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file instantiates the functionality needed for supporting floating +/// point arguments in modular printf builds. Non-modular printf builds +/// implicitly instantiate these functions. +/// +//===----------------------------------------------------------------------===// + +#ifdef LIBC_COPT_PRINTF_MODULAR +#include "src/__support/arg_list.h" + +#define LIBC_PRINTF_DEFINE_MODULAR +#include "src/stdio/printf_core/float_dec_converter.h" +#include "src/stdio/printf_core/float_hex_converter.h" +#include "src/stdio/printf_core/parser.h" + +namespace LIBC_NAMESPACE_DECL { +namespace printf_core { +template class Parser<internal::ArgList>; +template class Parser<internal::DummyArgList<false>>; +template class Parser<internal::DummyArgList<true>>; +template class Parser<internal::StructArgList<false>>; +template class Parser<internal::StructArgList<true>>; + +#define INSTANTIATE_CONVERT_FN(NAME) \ + template int NAME<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW>( \ + Writer<WriteMode::FILL_BUFF_AND_DROP_OVERFLOW> * writer, \ + const FormatSection &to_conv); \ + template int NAME<WriteMode::FLUSH_TO_STREAM>( \ + Writer<WriteMode::FLUSH_TO_STREAM> * writer, \ + const FormatSection &to_conv); \ + template int NAME<WriteMode::RESIZE_AND_FILL_BUFF>( \ + Writer<WriteMode::RESIZE_AND_FILL_BUFF> * writer, \ + const FormatSection &to_conv); \ + template int NAME<WriteMode::RUNTIME_DISPATCH>( \ + Writer<WriteMode::RUNTIME_DISPATCH> * writer, \ + const FormatSection &to_conv) + +INSTANTIATE_CONVERT_FN(convert_float_decimal); +INSTANTIATE_CONVERT_FN(convert_float_dec_exp); +INSTANTIATE_CONVERT_FN(convert_float_dec_auto); +INSTANTIATE_CONVERT_FN(convert_float_hex_exp); + +} // namespace printf_core +} // namespace LIBC_NAMESPACE_DECL + +// Bring this file into the link if __printf_float is referenced. +extern "C" void __printf_float() {} +#endif diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h index a3b62991bcec9..37a05aed9a131 100644 --- a/libc/src/stdio/printf_core/parser.h +++ b/libc/src/stdio/printf_core/parser.h @@ -249,11 +249,7 @@ template <typename ArgProvider> class Parser { case ('A'): case ('g'): case ('G'): - if (lm != LengthModifier::L) { - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, double, conv_index); - } else { - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long double, conv_index); - } + write_float_arg_val(section, lm, conv_index); break; #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT @@ -312,6 +308,12 @@ template <typename ArgProvider> class Parser { return section; } + LIBC_PRINTF_MODULAR_DECL void write_float_arg_val(FormatSection §ion, + LengthModifier lm, + size_t conv_index); + LIBC_PRINTF_MODULAR_DECL TypeDesc float_type_desc(LengthModifier lm); + LIBC_PRINTF_MODULAR_DECL bool advance_arg_if_float(TypeDesc cur_type_desc); + private: // parse_flags parses the flags inside a format string. It assumes that // str[*local_pos] is inside a format specifier, and parses any flags it @@ -487,10 +489,9 @@ template <typename ArgProvider> class Parser { args_cur.template next_var<uint64_t>(); #ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT // Floating point numbers are stored separately from the other arguments. - else if (cur_type_desc == type_desc_from_type<double>()) - args_cur.template next_var<double>(); - else if (cur_type_desc == type_desc_from_type<long double>()) - args_cur.template next_var<long double>(); + else if (&Parser::advance_arg_if_float && + advance_arg_if_float(cur_type_desc)) + ; #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT // Floating point numbers may be stored separately from the other @@ -652,10 +653,7 @@ template <typename ArgProvider> class Parser { case ('A'): case ('g'): case ('G'): - if (lm != LengthModifier::L) - conv_size = type_desc_from_type<double>(); - else - conv_size = type_desc_from_type<long double>(); + conv_size = float_type_desc(lm); break; #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT @@ -704,6 +702,40 @@ template <typename ArgProvider> class Parser { #endif // LIBC_COPT_PRINTF_DISABLE_INDEX_MODE }; +#ifdef LIBC_PRINTF_DEFINE_MODULAR +template <typename ArgParser> +LIBC_INLINE void +Parser<ArgParser>::write_float_arg_val(FormatSection §ion, + LengthModifier lm, + [[maybe_unused]] size_t conv_index) { + if (lm != LengthModifier::L) { + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, double, conv_index); + } else { + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long double, conv_index); + } +} + +template <typename ArgParser> +LIBC_INLINE TypeDesc Parser<ArgParser>::float_type_desc(LengthModifier lm) { + if (lm != LengthModifier::L) + return type_desc_from_type<double>(); + else + return type_desc_from_type<long double>(); +} + +template <typename ArgParser> +LIBC_INLINE bool +Parser<ArgParser>::advance_arg_if_float(TypeDesc cur_type_desc) { + if (cur_type_desc == type_desc_from_type<double>()) + args_cur.template next_var<double>(); + else if (cur_type_desc == type_desc_from_type<long double>()) + args_cur.template next_var<long double>(); + else + return false; + return true; +} +#endif + } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/printf_config.h b/libc/src/stdio/printf_core/printf_config.h index 8a48abdd170ec..8f6ae8b41bc92 100644 --- a/libc/src/stdio/printf_core/printf_config.h +++ b/libc/src/stdio/printf_core/printf_config.h @@ -48,4 +48,11 @@ // LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS +#ifdef LIBC_COPT_PRINTF_MODULAR +#define LIBC_PRINTF_MODULAR_DECL [[gnu::weak]] +#else +#define LIBC_PRINTF_MODULAR_DECL LIBC_INLINE +#define LIBC_PRINTF_DEFINE_MODULAR +#endif + #endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PRINTF_CONFIG_H diff --git a/libc/src/stdio/printf_core/printf_main.h b/libc/src/stdio/printf_core/printf_main.h index 1c7a7237c097d..874c24464ed52 100644 --- a/libc/src/stdio/printf_core/printf_main.h +++ b/libc/src/stdio/printf_core/printf_main.h @@ -23,9 +23,9 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { template <WriteMode write_mode> -ErrorOr<size_t> printf_main(Writer<write_mode> *writer, - const char *__restrict str, - internal::ArgList &args) { +ErrorOr<size_t> printf_main_modular(Writer<write_mode> *writer, + const char *__restrict str, + internal::ArgList &args) { Parser<internal::ArgList> parser(str, args); int result = 0; for (FormatSection cur_section = parser.get_next_section(); @@ -42,6 +42,16 @@ ErrorOr<size_t> printf_main(Writer<write_mode> *writer, return writer->get_chars_written(); } +template <WriteMode write_mode> +ErrorOr<size_t> printf_main(Writer<write_mode> *writer, + const char *__restrict str, + internal::ArgList &args) { +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); +#endif + return printf_main_modular(writer, str, args); +} + } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/vasprintf_internal.h b/libc/src/stdio/printf_core/vasprintf_internal.h index db6b95d49aaca..1dbf5787717f9 100644 --- a/libc/src/stdio/printf_core/vasprintf_internal.h +++ b/libc/src/stdio/printf_core/vasprintf_internal.h @@ -41,6 +41,7 @@ LIBC_INLINE int resize_overflow_hook(cpp::string_view new_str, constexpr size_t DEFAULT_BUFFER_SIZE = 200; +template <bool use_modular = false> LIBC_INLINE ErrorOr<size_t> vasprintf_internal(char **ret, const char *__restrict format, internal::ArgList args) { @@ -49,7 +50,9 @@ LIBC_INLINE ErrorOr<size_t> vasprintf_internal(char **ret, resize_overflow_hook); printf_core::Writer writer(wb); - auto ret_val = printf_core::printf_main(&writer, format, args); + auto ret_val = use_modular + ? printf_core::printf_main_modular(&writer, format, args) + : printf_core::printf_main(&writer, format, args); if (!ret_val.has_value()) { *ret = nullptr; return ret_val; diff --git a/libc/src/stdio/printf_core/vfprintf_internal.h b/libc/src/stdio/printf_core/vfprintf_internal.h index 321b0693ad339..6ce4ab3d62d4a 100644 --- a/libc/src/stdio/printf_core/vfprintf_internal.h +++ b/libc/src/stdio/printf_core/vfprintf_internal.h @@ -81,16 +81,17 @@ LIBC_INLINE int file_write_hook(cpp::string_view new_str, void *fp) { return WRITE_OK; } -LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE *__restrict stream, - const char *__restrict format, - internal::ArgList &args) { +LIBC_INLINE ErrorOr<size_t> +vfprintf_internal_modular(::FILE *__restrict stream, + const char *__restrict format, + internal::ArgList &args) { constexpr size_t BUFF_SIZE = 1024; char buffer[BUFF_SIZE]; printf_core::FlushingBuffer wb(buffer, BUFF_SIZE, &file_write_hook, reinterpret_cast<void *>(stream)); Writer writer(wb); internal::flockfile(stream); - auto retval = printf_main(&writer, format, args); + auto retval = printf_main_modular(&writer, format, args); if (!retval.has_value()) { internal::funlockfile(stream); return retval; @@ -102,6 +103,15 @@ LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE *__restrict stream, return retval; } +LIBC_INLINE ErrorOr<size_t> vfprintf_internal(::FILE *__restrict stream, + const char *__restrict format, + internal::ArgList &args) { +#ifdef LIBC_COPT_PRINTF_MODULAR + __asm__ __volatile__(".reloc ., BFD_RELOC_NONE, __printf_float"); +#endif + return vfprintf_internal_modular(stream, format, args); +} + } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/snprintf.cpp b/libc/src/stdio/snprintf.cpp index 8364e8d59b278..d8fb1b1ad3577 100644 --- a/libc/src/stdio/snprintf.cpp +++ b/libc/src/stdio/snprintf.cpp @@ -34,7 +34,12 @@ LLVM_LIBC_FUNCTION(int, snprintf, printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0)); printf_core::Writer writer(wb); +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + auto ret_val = printf_core::printf_main_modular(&writer, format, args); +#else auto ret_val = printf_core::printf_main(&writer, format, args); +#endif if (!ret_val.has_value()) { libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; diff --git a/libc/src/stdio/snprintf.h b/libc/src/stdio/snprintf.h index 92a6529704076..9d350d2712803 100644 --- a/libc/src/stdio/snprintf.h +++ b/libc/src/stdio/snprintf.h @@ -16,6 +16,8 @@ namespace LIBC_NAMESPACE_DECL { int snprintf(char *__restrict buffer, size_t buffsz, const char *__restrict format, ...); +int __snprintf_modular(char *__restrict buffer, size_t buffsz, + const char *__restrict format, ...); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/snprintf_modular.cpp b/libc/src/stdio/snprintf_modular.cpp new file mode 100644 index 0000000000000..2e7683d56de75 --- /dev/null +++ b/libc/src/stdio/snprintf_modular.cpp @@ -0,0 +1,54 @@ +//===-- Implementation of snprintf_modular ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/snprintf.h" + +#include "src/__support/CPP/limits.h" +#include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_mapper.h" +#include "src/stdio/printf_core/printf_main.h" +#include "src/stdio/printf_core/writer.h" + +#include <stdarg.h> +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __snprintf_modular, + (char *__restrict buffer, size_t buffsz, + const char *__restrict format, ...)) { + va_list vlist; + va_start(vlist, format); + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + va_end(vlist); + printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0)); + printf_core::Writer writer(wb); + + auto ret_val = printf_core::printf_main_modular(&writer, format, args); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); + return -1; + } + if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. + wb.buff[wb.buff_cur] = '\0'; + + if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); + return -1; + } + + return static_cast<int>(ret_val.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/sprintf.cpp b/libc/src/stdio/sprintf.cpp index d340096bb6d2b..bbb3f64ea7b15 100644 --- a/libc/src/stdio/sprintf.cpp +++ b/libc/src/stdio/sprintf.cpp @@ -35,7 +35,12 @@ LLVM_LIBC_FUNCTION(int, sprintf, cpp::numeric_limits<size_t>::max()); printf_core::Writer writer(wb); +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + auto ret_val = printf_core::printf_main_modular(&writer, format, args); +#else auto ret_val = printf_core::printf_main(&writer, format, args); +#endif if (!ret_val.has_value()) { libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; diff --git a/libc/src/stdio/sprintf.h b/libc/src/stdio/sprintf.h index ef65de399dc6d..4008858aaaa63 100644 --- a/libc/src/stdio/sprintf.h +++ b/libc/src/stdio/sprintf.h @@ -14,6 +14,8 @@ namespace LIBC_NAMESPACE_DECL { int sprintf(char *__restrict buffer, const char *__restrict format, ...); +int __sprintf_modular(char *__restrict buffer, const char *__restrict format, + ...); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/sprintf_modular.cpp b/libc/src/stdio/sprintf_modular.cpp new file mode 100644 index 0000000000000..cfed3fe4a4f4d --- /dev/null +++ b/libc/src/stdio/sprintf_modular.cpp @@ -0,0 +1,54 @@ +//===-- Implementation of sprintf_modular -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/sprintf.h" + +#include "src/__support/CPP/limits.h" +#include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_mapper.h" +#include "src/stdio/printf_core/printf_main.h" +#include "src/stdio/printf_core/writer.h" + +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __sprintf_modular, + (char *__restrict buffer, const char *__restrict format, + ...)) { + va_list vlist; + va_start(vlist, format); + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + va_end(vlist); + + printf_core::DropOverflowBuffer wb(buffer, + cpp::numeric_limits<size_t>::max()); + printf_core::Writer writer(wb); + + auto ret_val = printf_core::printf_main_modular(&writer, format, args); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); + return -1; + } + wb.buff[wb.buff_cur] = '\0'; + + if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); + return -1; + } + + return static_cast<int>(ret_val.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vasprintf.cpp b/libc/src/stdio/vasprintf.cpp index bd77cd8864312..64d959c6edcae 100644 --- a/libc/src/stdio/vasprintf.cpp +++ b/libc/src/stdio/vasprintf.cpp @@ -22,7 +22,12 @@ LLVM_LIBC_FUNCTION(int, vasprintf, internal::ArgList args(vlist); // This holder class allows for easier copying // and pointer semantics, as well as handling // destruction automatically. +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + auto ret_val = printf_core::vasprintf_internal<true>(ret, format, args); +#else auto ret_val = printf_core::vasprintf_internal(ret, format, args); +#endif if (!ret_val.has_value()) { libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; diff --git a/libc/src/stdio/vasprintf.h b/libc/src/stdio/vasprintf.h index 7a98568edbc07..9f6ad87deac81 100644 --- a/libc/src/stdio/vasprintf.h +++ b/libc/src/stdio/vasprintf.h @@ -16,6 +16,8 @@ namespace LIBC_NAMESPACE_DECL { int vasprintf(char **__restrict s, const char *__restrict format, va_list vlist); +int __vasprintf_modular(char **__restrict s, const char *__restrict format, + va_list vlist); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vasprintf_modular.cpp b/libc/src/stdio/vasprintf_modular.cpp new file mode 100644 index 0000000000000..98620bb8a440c --- /dev/null +++ b/libc/src/stdio/vasprintf_modular.cpp @@ -0,0 +1,38 @@ +//===-- Implementation of vasprintf_modular ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/__support/CPP/limits.h" +#include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_mapper.h" +#include "src/stdio/printf_core/vasprintf_internal.h" +#include "src/stdio/vasprintf.h" + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __vasprintf_modular, + (char **__restrict ret, const char *__restrict format, + va_list vlist)) { + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + auto ret_val = printf_core::vasprintf_internal<true>(ret, format, args); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); + return -1; + } + if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); + return -1; + } + return static_cast<int>(ret_val.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vprintf.h b/libc/src/stdio/vprintf.h index 63f0f3ae62d6e..70cf03f69a767 100644 --- a/libc/src/stdio/vprintf.h +++ b/libc/src/stdio/vprintf.h @@ -16,6 +16,7 @@ namespace LIBC_NAMESPACE_DECL { int vprintf(const char *__restrict format, va_list vlist); +int __vprintf_modular(const char *__restrict format, va_list vlist); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsnprintf.cpp b/libc/src/stdio/vsnprintf.cpp index b65343dfefc75..bea980d6b20ec 100644 --- a/libc/src/stdio/vsnprintf.cpp +++ b/libc/src/stdio/vsnprintf.cpp @@ -31,7 +31,12 @@ LLVM_LIBC_FUNCTION(int, vsnprintf, printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0)); printf_core::Writer writer(wb); +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + auto ret_val = printf_core::printf_main_modular(&writer, format, args); +#else auto ret_val = printf_core::printf_main(&writer, format, args); +#endif if (!ret_val.has_value()) { libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; diff --git a/libc/src/stdio/vsnprintf.h b/libc/src/stdio/vsnprintf.h index 27ae763f7746a..0b8af0ac6ff36 100644 --- a/libc/src/stdio/vsnprintf.h +++ b/libc/src/stdio/vsnprintf.h @@ -17,6 +17,8 @@ namespace LIBC_NAMESPACE_DECL { int vsnprintf(char *__restrict buffer, size_t buffsz, const char *__restrict format, va_list vlist); +int __vsnprintf_modular(char *__restrict buffer, size_t buffsz, + const char *__restrict format, va_list vlist); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsnprintf_modular.cpp b/libc/src/stdio/vsnprintf_modular.cpp new file mode 100644 index 0000000000000..7225311601281 --- /dev/null +++ b/libc/src/stdio/vsnprintf_modular.cpp @@ -0,0 +1,51 @@ +//===-- Implementation of vsnprintf_modular ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/vsnprintf.h" + +#include "src/__support/CPP/limits.h" +#include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_mapper.h" +#include "src/stdio/printf_core/printf_main.h" +#include "src/stdio/printf_core/writer.h" + +#include <stdarg.h> +#include <stddef.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __vsnprintf_modular, + (char *__restrict buffer, size_t buffsz, + const char *__restrict format, va_list vlist)) { + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + printf_core::DropOverflowBuffer wb(buffer, (buffsz > 0 ? buffsz - 1 : 0)); + printf_core::Writer writer(wb); + + auto ret_val = printf_core::printf_main_modular(&writer, format, args); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); + return -1; + } + if (buffsz > 0) // if the buffsz is 0 the buffer may be a null pointer. + wb.buff[wb.buff_cur] = '\0'; + + if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); + return -1; + } + + return static_cast<int>(ret_val.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsprintf.cpp b/libc/src/stdio/vsprintf.cpp index 8affb88d2b807..3dae05fbbaadd 100644 --- a/libc/src/stdio/vsprintf.cpp +++ b/libc/src/stdio/vsprintf.cpp @@ -32,7 +32,12 @@ LLVM_LIBC_FUNCTION(int, vsprintf, cpp::numeric_limits<size_t>::max()); printf_core::Writer writer(wb); +#ifdef LIBC_COPT_PRINTF_MODULAR + LIBC_INLINE_ASM(".reloc ., BFD_RELOC_NONE, __printf_float"); + auto ret_val = printf_core::printf_main_modular(&writer, format, args); +#else auto ret_val = printf_core::printf_main(&writer, format, args); +#endif if (!ret_val.has_value()) { libc_errno = printf_core::internal_error_to_errno(ret_val.error()); return -1; diff --git a/libc/src/stdio/vsprintf.h b/libc/src/stdio/vsprintf.h index abb89ba76eae5..54eb6120098a4 100644 --- a/libc/src/stdio/vsprintf.h +++ b/libc/src/stdio/vsprintf.h @@ -16,6 +16,8 @@ namespace LIBC_NAMESPACE_DECL { int vsprintf(char *__restrict buffer, const char *__restrict format, va_list vlist); +int __vsprintf_modular(char *__restrict buffer, const char *__restrict format, + va_list vlist); } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/vsprintf_modular.cpp b/libc/src/stdio/vsprintf_modular.cpp new file mode 100644 index 0000000000000..844d1e3cdd550 --- /dev/null +++ b/libc/src/stdio/vsprintf_modular.cpp @@ -0,0 +1,50 @@ +//===-- Implementation of vsprintf_modular ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/stdio/vsprintf.h" + +#include "src/__support/CPP/limits.h" +#include "src/__support/arg_list.h" +#include "src/__support/libc_errno.h" +#include "src/__support/macros/config.h" +#include "src/stdio/printf_core/core_structs.h" +#include "src/stdio/printf_core/error_mapper.h" +#include "src/stdio/printf_core/printf_main.h" +#include "src/stdio/printf_core/writer.h" + +#include <stdarg.h> + +namespace LIBC_NAMESPACE_DECL { + +LLVM_LIBC_FUNCTION(int, __vsprintf_modular, + (char *__restrict buffer, const char *__restrict format, + va_list vlist)) { + internal::ArgList args(vlist); // This holder class allows for easier copying + // and pointer semantics, as well as handling + // destruction automatically. + + printf_core::DropOverflowBuffer wb(buffer, + cpp::numeric_limits<size_t>::max()); + printf_core::Writer writer(wb); + + auto ret_val = printf_core::printf_main_modular(&writer, format, args); + if (!ret_val.has_value()) { + libc_errno = printf_core::internal_error_to_errno(ret_val.error()); + return -1; + } + wb.buff[wb.buff_cur] = '\0'; + + if (ret_val.value() > static_cast<size_t>(cpp::numeric_limits<int>::max())) { + libc_errno = + printf_core::internal_error_to_errno(-printf_core::OVERFLOW_ERROR); + return -1; + } + return static_cast<int>(ret_val.value()); +} + +} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/utils/hdrgen/hdrgen/header.py b/libc/utils/hdrgen/hdrgen/header.py index b69d22494a7ac..1af741844bd01 100644 --- a/libc/utils/hdrgen/hdrgen/header.py +++ b/libc/utils/hdrgen/hdrgen/header.py @@ -177,7 +177,7 @@ def includes(self): for typ in self.all_types() } | { - PurePosixPath("llvm-libc-macros") / f"{attr}.h" + PurePosixPath("llvm-libc-macros") / f"{attr.split('(')[0]}.h" for attr in self.all_attributes() - COMMON_ATTRIBUTES } ) diff --git a/libc/utils/hdrgen/tests/expected_output/test_header.h b/libc/utils/hdrgen/tests/expected_output/test_header.h index 49112a353f7b6..7704176bbc3d7 100644 --- a/libc/utils/hdrgen/tests/expected_output/test_header.h +++ b/libc/utils/hdrgen/tests/expected_output/test_header.h @@ -13,6 +13,7 @@ #include "llvm-libc-macros/float16-macros.h" #include "llvm-libc-macros/CONST_FUNC_A.h" +#include "llvm-libc-macros/MACRO_ATTR.h" #include "llvm-libc-macros/test_more-macros.h" #include "llvm-libc-macros/test_small-macros.h" #include "llvm-libc-types/float128.h" @@ -32,7 +33,7 @@ enum { __BEGIN_C_DECLS -CONST_FUNC_A void func_a(void) __NOEXCEPT; +CONST_FUNC_A MACRO_ATTR(A) void func_a(void) __NOEXCEPT; #ifdef LIBC_TYPES_HAS_FLOAT128 float128 func_b(void) __NOEXCEPT; diff --git a/libc/utils/hdrgen/tests/expected_output/test_small.json b/libc/utils/hdrgen/tests/expected_output/test_small.json index 8502df23b9a41..e62fce1043ee5 100644 --- a/libc/utils/hdrgen/tests/expected_output/test_small.json +++ b/libc/utils/hdrgen/tests/expected_output/test_small.json @@ -5,6 +5,7 @@ "includes": [ "__llvm-libc-common.h", "llvm-libc-macros/CONST_FUNC_A.h", + "llvm-libc-macros/MACRO_ATTR.h", "llvm-libc-macros/test_more-macros.h", "llvm-libc-macros/test_small-macros.h", "llvm-libc-types/float128.h", diff --git a/libc/utils/hdrgen/tests/input/merge1.yaml b/libc/utils/hdrgen/tests/input/merge1.yaml index 950abd1770320..9abcf7f266710 100644 --- a/libc/utils/hdrgen/tests/input/merge1.yaml +++ b/libc/utils/hdrgen/tests/input/merge1.yaml @@ -17,3 +17,4 @@ functions: - stdc attributes: - CONST_FUNC_A + - MACRO_ATTR(A) >From fdf28d28bc377386835ea91d10ee7e51d79e441f Mon Sep 17 00:00:00 2001 From: Daniel Thornburgh <[email protected]> Date: Wed, 28 Jan 2026 14:47:51 -0800 Subject: [PATCH 2/2] Attr Docs typos --- clang/include/clang/Basic/AttrDocs.td | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td index 812b48058d189..68e8cd1d4ac8b 100644 --- a/clang/include/clang/Basic/AttrDocs.td +++ b/clang/include/clang/Basic/AttrDocs.td @@ -9672,9 +9672,9 @@ not all aspects of the implementation are needed for a given call, the compiler may redirect the call to the identifier given as the first argument to the attribute (the modular implementation function). -The second argument is a implementation name, and the remaining arguments are +The second argument is an implementation name, and the remaining arguments are aspects of the format string for the compiler to report. The implementation -name is an unevaluated identifier be in the C namespace. +name is an unevaluated identifier in the C namespace. The compiler reports that a call requires an aspect by issuing a relocation for the symbol ``<impl_name>_<aspect>`` at the point of the call. This arranges for _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
