Skip to content

[libc] Modular printf option (float only) #147426

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: users/mysterymath/modular-printf/clang
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions libc/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@
"LIBC_CONF_PRINTF_RUNTIME_DISPATCH": {
"value": true,
"doc": "Use dynamic dispatch for the output mechanism to reduce code size."
},
"LIBC_CONF_PRINTF_MODULAR": {
"value": true,
"doc": "Split printf implementation into modules that can be lazily linked in."
}
},
"scanf": {
Expand Down
1 change: 1 addition & 0 deletions libc/docs/configure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,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).
Expand Down
7 changes: 6 additions & 1 deletion libc/src/stdio/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -412,10 +412,15 @@ if(LLVM_LIBC_FULL_BUILD)
)
endif()

set(printf_srcs printf.cpp)
if (LIBC_CONF_PRINTF_MODULAR)
list(APPEND printf_srcs printf_modular.cpp)
endif()
Comment on lines +416 to +418
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it make sense to have __printf_float as a separate entrypoint so that it can be controlled per-platform with the same mechanism as other entrypoints?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm understanding the idea correctly, this would allow platforms to control whether or not named aspects of the various format string function implementations are included in the libc build. This would only work with LIBC_CONF_PRINTF_MODULAR, and it would cause link failures unless programs linked against that libc could be proven not to use those aspects. (Or maybe if they could be proven to use those aspects; that seems more useful. The difference would be whether or not the plain printf definitions would refer to __printf_float, for example.)

Is this roughly what you were thinking? I'm open to this, but it seems to add complexity, and it stretches the notion of entrypoint a bit. Do we do anything like this elsewhere?


add_generic_entrypoint_object(
printf
SRCS
printf.cpp
${printf_srcs}
HDRS
../printf.h
DEPENDS
Expand Down
40 changes: 40 additions & 0 deletions libc/src/stdio/generic/printf_modular.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//===-- Implementation of printf_modular-----------------------------------===//
//
// 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 "src/__support/File/file.h"
#include "src/__support/arg_list.h"
#include "src/__support/macros/config.h"
#include "src/stdio/printf_core/vfprintf_internal.h"

#include "hdr/types/FILE.h"
#include <stdarg.h>

#ifndef LIBC_COPT_STDIO_USE_SYSTEM_FILE
#define PRINTF_STDOUT LIBC_NAMESPACE::stdout
#else // LIBC_COPT_STDIO_USE_SYSTEM_FILE
#define PRINTF_STDOUT ::stdout
#endif // LIBC_COPT_STDIO_USE_SYSTEM_FILE

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);
int ret_val = printf_core::vfprintf_internal_modular(
reinterpret_cast<::FILE *>(PRINTF_STDOUT), format, args);
return ret_val;
}

} // namespace LIBC_NAMESPACE_DECL
1 change: 1 addition & 0 deletions libc/src/stdio/printf.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
7 changes: 6 additions & 1 deletion libc/src/stdio/printf_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -112,10 +115,12 @@ add_header_library(
libc.src.__support.StringUtil.error_to_string
)

add_header_library(
add_object_library(
printf_main
HDRS
printf_main.h
SRCS
float_impl.cpp
DEPENDS
.parser
.converter
Expand Down
13 changes: 13 additions & 0 deletions libc/src/stdio/printf_core/float_dec_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be a separate PR, but can we change all the writer argument to reference instead of pointer?

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>
Expand Down Expand Up @@ -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
Expand Down
12 changes: 12 additions & 0 deletions libc/src/stdio/printf_core/float_dec_converter_limited.h
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,17 @@ 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) {
Expand All @@ -692,6 +703,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
Expand Down
6 changes: 6 additions & 0 deletions libc/src/stdio/printf_core/float_hex_converter.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -254,6 +259,7 @@ LIBC_INLINE int convert_float_hex_exp(Writer<write_mode> *writer,
}
return WRITE_OK;
}
#endif

} // namespace printf_core
} // namespace LIBC_NAMESPACE_DECL
Expand Down
56 changes: 56 additions & 0 deletions libc/src/stdio/printf_core/float_impl.cpp
Original file line number Diff line number Diff line change
@@ -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"
Comment on lines +19 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

given this, do you need to modify converter.h or converter_atlas.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
57 changes: 44 additions & 13 deletions libc/src/stdio/printf_core/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,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
Expand Down Expand Up @@ -299,6 +295,12 @@ template <typename ArgProvider> class Parser {
return section;
}

LIBC_PRINTF_MODULAR_DECL void write_float_arg_val(FormatSection &section,
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
Expand Down Expand Up @@ -474,10 +476,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
Expand Down Expand Up @@ -630,10 +631,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
Expand Down Expand Up @@ -682,6 +680,39 @@ 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 &section,
LengthModifier lm,
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

Expand Down
7 changes: 7 additions & 0 deletions libc/src/stdio/printf_core/printf_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
13 changes: 11 additions & 2 deletions libc/src/stdio/printf_core/printf_main.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ namespace LIBC_NAMESPACE_DECL {
namespace printf_core {

template <WriteMode write_mode>
int printf_main(Writer<write_mode> *writer, const char *__restrict str,
internal::ArgList &args) {
int 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();
Expand All @@ -41,6 +41,15 @@ int printf_main(Writer<write_mode> *writer, const char *__restrict str,
return writer->get_chars_written();
}

template <WriteMode write_mode>
int 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

Expand Down
Loading
Loading