(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.
