[libc] Modular printf option (float only) (#147426)
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.
This commit is contained in:
parent
4e19eee8a6
commit
7efcd6198c
@ -9854,9 +9854,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
|
||||
|
||||
@ -59,6 +59,10 @@
|
||||
"LIBC_COPT_PRINTF_DISABLE_BITINT": {
|
||||
"value": false,
|
||||
"doc": "Disable bitint length modifiers to reduce code size. Specifically the wNUM and wfNUM modifiers."
|
||||
},
|
||||
"LIBC_CONF_PRINTF_MODULAR": {
|
||||
"value": false,
|
||||
"doc": "Split printf implementation into modules that can be lazily linked in."
|
||||
}
|
||||
},
|
||||
"scanf": {
|
||||
|
||||
@ -22,3 +22,4 @@ Navigate to the links below for information on the respective topics:
|
||||
undefined_behavior
|
||||
printf_behavior
|
||||
syscall_wrapper_refactor
|
||||
modular_format
|
||||
|
||||
68
libc/docs/dev/modular_format.rst
Normal file
68
libc/docs/dev/modular_format.rst
Normal file
@ -0,0 +1,68 @@
|
||||
.. _modular_format:
|
||||
|
||||
======================
|
||||
Modular format strings
|
||||
======================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Several C standard library functions (most notably, ``printf`` and ``scanf``),
|
||||
present a large amount of related features to the caller configured via a
|
||||
format string. This benefits code size at the caller, since format strings are
|
||||
typically quite dense, and the equivalent of many individual calls can be
|
||||
performed with only one. Overall this is a benefit, since to a function calls
|
||||
typically outnumber the one definition of that function.
|
||||
|
||||
However, the implementations of various libc features gated behind aspects of
|
||||
those format strings can be large enough that they completely swamp the
|
||||
programs that call them. Floating point and errno conversion in particular can
|
||||
involve large tables which may be wholly dead. However, due to the format
|
||||
string structure, this code is dead in a way previously invisible to the
|
||||
compiler.
|
||||
|
||||
To address this, an clang attribute was introduced: ``modular_format(<impl_fn>,
|
||||
<impl_name>, <aspects>...)``. This adds to the semantics of the existing
|
||||
``format`` attribute (which must also be present, if implicitly.) The first
|
||||
argument is a symbol naming a modular version of the implementation; this
|
||||
version only weakly refers to "aspects" of the implementation that may not be
|
||||
necessary for certain format strings. The second argument is general
|
||||
"implementation name" string, and the remaining arguments are a list of handled
|
||||
aspects of the format string. When the compiler sees that a given call only
|
||||
needs a fixed set of aspects of the implementation, it may redirect the call to
|
||||
the implementation function and emit a series of relocations to symbols named
|
||||
``<impl_name>_<aspect>``. These in turn bring the needed aspects of the call
|
||||
into the link. The default entrypoints fall the modular ones, except they bring
|
||||
in every possible implementation aspect.
|
||||
|
||||
Mechanism
|
||||
=========
|
||||
|
||||
This functionality is currently gated behind ``LIBC_COPT_PRINTF_MODULAR``. When
|
||||
set, the ``printf``-family functions gain modular variants, and the regular
|
||||
variants are modified to call them and emit NONE relocations against all
|
||||
implementation aspects.
|
||||
|
||||
The implementation aspects are defined in headers using the
|
||||
``LIBC_PRINTF_MODULE((<decl>), { <body> })`` macro. If
|
||||
``LIBC_COPT_PRINTF_MODULAR`` is not defined, then this macro makes these
|
||||
``LIBC_INLINE`` definitions as per usual. Otherwise, for normal usage, these
|
||||
become weak declarations, which causes any references to the module to become
|
||||
weak. The implementations are moved to a dedicated impl file for groups of
|
||||
modules. These define the aspect symbol and the module impls by defining
|
||||
``LIBC_PRINTF_DEFINE_MODULES`` before including the header. This causes the to
|
||||
be brought into the link exactly when the aspect symbol is referenced.
|
||||
|
||||
Template functions present a special complication: the implementation must
|
||||
instantiate them for any value that may be used. Since the purpose of the
|
||||
templates is to implement a fixed interface, the possible arguments should
|
||||
always be fixed and finite. Accordingly, libc contains def files to enumerate
|
||||
possible arguments and provide handling for each. Templates are instantiated in
|
||||
the headers whenever ``LIBC_PRINTF_DEFINE_MODULES`` is defined.
|
||||
|
||||
libc and the compiler may understand different sets of aspect names, but their
|
||||
understanding of what an aspect name means must be identical. libc reports the
|
||||
set of aspect names that it needs a verdict on, and the compiler will only
|
||||
provide a verdict for those aspects. If libc asks for a verdict on an aspect
|
||||
unknown to the compiler, the aspect must be summarily considered to be
|
||||
required.
|
||||
@ -360,6 +360,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
|
||||
|
||||
@ -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}
|
||||
)
|
||||
@ -395,3 +400,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()
|
||||
|
||||
@ -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
|
||||
15
libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
Normal file
15
libc/include/llvm-libc-macros/_LIBC_MODULAR_FORMAT_PRINTF.h
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
43
libc/src/stdio/asprintf_modular.cpp
Normal file
43
libc/src/stdio/asprintf_modular.cpp
Normal file
@ -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
|
||||
@ -211,10 +211,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
|
||||
@ -345,10 +349,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
|
||||
|
||||
@ -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
|
||||
|
||||
33
libc/src/stdio/baremetal/printf_modular.cpp
Normal file
33
libc/src/stdio/baremetal/printf_modular.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
//===-- 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
|
||||
@ -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
|
||||
|
||||
@ -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,12 @@ 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 = [&] {
|
||||
if constexpr (use_modular)
|
||||
return printf_core::printf_main_modular(&writer, format, args);
|
||||
else
|
||||
return printf_core::printf_main(&writer, format, args);
|
||||
}();
|
||||
if (!retval.has_value()) {
|
||||
libc_errno = printf_core::internal_error_to_errno(retval.error());
|
||||
return -1;
|
||||
|
||||
@ -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
|
||||
|
||||
30
libc/src/stdio/baremetal/vprintf_modular.cpp
Normal file
30
libc/src/stdio/baremetal/vprintf_modular.cpp
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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()
|
||||
@ -150,10 +153,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
|
||||
|
||||
@ -28,6 +28,37 @@
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace printf_core {
|
||||
|
||||
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
|
||||
LIBC_PRINTF_MODULE((template <WriteMode write_mode>
|
||||
int convert_float(Writer<write_mode> *writer,
|
||||
const FormatSection &to_conv)),
|
||||
{
|
||||
switch (to_conv.conv_name) {
|
||||
case 'f':
|
||||
case 'F':
|
||||
return convert_float_decimal(writer, to_conv);
|
||||
case 'e':
|
||||
case 'E':
|
||||
return convert_float_dec_exp(writer, to_conv);
|
||||
case 'a':
|
||||
case 'A':
|
||||
return convert_float_hex_exp(writer, to_conv);
|
||||
case 'g':
|
||||
case 'G':
|
||||
return convert_float_dec_auto(writer, to_conv);
|
||||
}
|
||||
__builtin_unreachable();
|
||||
})
|
||||
#endif // not LIBC_COPT_PRINTF_DISABLE_FLOAT
|
||||
|
||||
#ifdef LIBC_PRINTF_DEFINE_MODULES
|
||||
#define HANDLE_WRITE_MODE(MODE) \
|
||||
template int convert_float<WriteMode::MODE>( \
|
||||
Writer<WriteMode::MODE> * writer, const FormatSection &to_conv);
|
||||
#include "src/stdio/printf_core/write_modes.def"
|
||||
#undef HANDLE_WRITE_MODE
|
||||
#endif // LIBC_PRINTF_DEFINE_MODULES
|
||||
|
||||
// convert will call a conversion function to convert the FormatSection into
|
||||
// its string representation, and then that will write the result to the
|
||||
// writer.
|
||||
@ -72,16 +103,13 @@ int convert(Writer<write_mode> *writer, const FormatSection &to_conv) {
|
||||
#ifndef LIBC_COPT_PRINTF_DISABLE_FLOAT
|
||||
case 'f':
|
||||
case 'F':
|
||||
return convert_float_decimal(writer, to_conv);
|
||||
case 'e':
|
||||
case 'E':
|
||||
return convert_float_dec_exp(writer, to_conv);
|
||||
case 'a':
|
||||
case 'A':
|
||||
return convert_float_hex_exp(writer, to_conv);
|
||||
case 'g':
|
||||
case 'G':
|
||||
return convert_float_dec_auto(writer, to_conv);
|
||||
return convert_float(writer, to_conv);
|
||||
#endif // LIBC_COPT_PRINTF_DISABLE_FLOAT
|
||||
#ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT
|
||||
case 'r':
|
||||
|
||||
24
libc/src/stdio/printf_core/float_impl.cpp
Normal file
24
libc/src/stdio/printf_core/float_impl.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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
|
||||
|
||||
#define LIBC_PRINTF_DEFINE_MODULES
|
||||
#include "src/stdio/printf_core/converter.h"
|
||||
|
||||
// Bring this file into the link if __printf_float is referenced.
|
||||
extern "C" void __printf_float() {}
|
||||
|
||||
#endif // LIBC_COPT_PRINTF_MODULAR
|
||||
@ -48,4 +48,24 @@
|
||||
|
||||
// LIBC_COPT_PRINTF_NO_NULLPTR_CHECKS
|
||||
|
||||
#ifdef LIBC_COPT_PRINTF_MODULAR
|
||||
#define LIBC_PRINTF_MODULE_DECL __attribute__((weak))
|
||||
#else
|
||||
#define LIBC_PRINTF_MODULE_DECL LIBC_INLINE
|
||||
#endif
|
||||
|
||||
// LIBC_PRINTF_MODULE: Defines/declares a printf module.
|
||||
//
|
||||
// Usage: LIBC_PRINTF_MODULE((<signature>), { <body> })
|
||||
//
|
||||
// Note that the signature is parenthesized, but the body is not.
|
||||
|
||||
#define LIBC_PRINTF_MODULE_UNWRAP(...) __VA_ARGS__
|
||||
#if !defined(LIBC_COPT_PRINTF_MODULAR) || defined(LIBC_PRINTF_DEFINE_MODULES)
|
||||
#define LIBC_PRINTF_MODULE(SIG, ...) LIBC_PRINTF_MODULE_UNWRAP SIG __VA_ARGS__
|
||||
#else
|
||||
#define LIBC_PRINTF_MODULE(SIG, ...) \
|
||||
LIBC_PRINTF_MODULE_UNWRAP SIG LIBC_PRINTF_MODULE_DECL;
|
||||
#endif
|
||||
|
||||
#endif // LLVM_LIBC_SRC_STDIO_PRINTF_CORE_PRINTF_CONFIG_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
|
||||
|
||||
|
||||
@ -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,12 @@ 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 = [&] {
|
||||
if constexpr (use_modular)
|
||||
return printf_core::printf_main_modular(&writer, format, args);
|
||||
else
|
||||
return printf_core::printf_main(&writer, format, args);
|
||||
}();
|
||||
if (!ret_val.has_value()) {
|
||||
*ret = nullptr;
|
||||
return ret_val;
|
||||
|
||||
12
libc/src/stdio/printf_core/write_modes.def
Normal file
12
libc/src/stdio/printf_core/write_modes.def
Normal file
@ -0,0 +1,12 @@
|
||||
//===-- printf write mode definitions ----------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
HANDLE_WRITE_MODE(FILL_BUFF_AND_DROP_OVERFLOW)
|
||||
HANDLE_WRITE_MODE(FLUSH_TO_STREAM)
|
||||
HANDLE_WRITE_MODE(RESIZE_AND_FILL_BUFF)
|
||||
HANDLE_WRITE_MODE(RUNTIME_DISPATCH)
|
||||
@ -21,12 +21,11 @@
|
||||
namespace LIBC_NAMESPACE_DECL {
|
||||
namespace printf_core {
|
||||
|
||||
#define HANDLE_WRITE_MODE(MODE) MODE,
|
||||
enum class WriteMode {
|
||||
FILL_BUFF_AND_DROP_OVERFLOW,
|
||||
FLUSH_TO_STREAM,
|
||||
RESIZE_AND_FILL_BUFF,
|
||||
RUNTIME_DISPATCH,
|
||||
#include "src/stdio/printf_core/write_modes.def"
|
||||
};
|
||||
#undef HANDLE_WRITE_MODE
|
||||
|
||||
// Helper to omit the template argument if we are using runtime dispatch and
|
||||
// avoid multiple copies of the converter functions.
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
54
libc/src/stdio/snprintf_modular.cpp
Normal file
54
libc/src/stdio/snprintf_modular.cpp
Normal file
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
54
libc/src/stdio/sprintf_modular.cpp
Normal file
54
libc/src/stdio/sprintf_modular.cpp
Normal file
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
38
libc/src/stdio/vasprintf_modular.cpp
Normal file
38
libc/src/stdio/vasprintf_modular.cpp
Normal file
@ -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
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
51
libc/src/stdio/vsnprintf_modular.cpp
Normal file
51
libc/src/stdio/vsnprintf_modular.cpp
Normal file
@ -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
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
50
libc/src/stdio/vsprintf_modular.cpp
Normal file
50
libc/src/stdio/vsprintf_modular.cpp
Normal file
@ -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
|
||||
@ -177,7 +177,7 @@ class HeaderFile:
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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",
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#ifdef LIBC_FULL_BUILD
|
||||
|
||||
#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"
|
||||
|
||||
@ -17,3 +17,4 @@ functions:
|
||||
- stdc
|
||||
attributes:
|
||||
- CONST_FUNC_A
|
||||
- MACRO_ATTR(A)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user