Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
383bd60
[IR] llvm.reloc.none intrinsic for no-op symbol references
mysterymath Jul 7, 2025
cd94463
fake.use -> reloc.none
mysterymath Jul 8, 2025
a045626
Take symbol name by metadata arg rather than ptr to GlobalValue
mysterymath Jul 21, 2025
f439cb6
Add a generic reloc_none test
mysterymath Jul 23, 2025
312f688
IR verifier check and test
mysterymath Jul 25, 2025
5d2bb5e
Remove unneeded assertion from AsmPrinter
mysterymath Jul 28, 2025
f67a868
Use llvm-as for test
mysterymath Jul 28, 2025
eac2e30
Rename reloc_none.ll to reloc-none.ll
mysterymath Jul 29, 2025
d4b5316
Lower reloc.none in Global ISel
mysterymath Jul 29, 2025
2d891ba
Remove arg from emitRelocDirective call
mysterymath Jul 29, 2025
984b060
Update tests
mysterymath Jul 29, 2025
ccafe0c
Take symbol name by GlobalValue again to avoid modifying Module
mysterymath Aug 20, 2025
bad31c7
Update big-filter.td
mysterymath Aug 21, 2025
1848a8e
[IR] "modular-format" attribute for functions using format strings
mysterymath Apr 2, 2025
f6e5d88
issing -> issuing
mysterymath Jul 8, 2025
4d10a1d
Emit reloc.none instinsic with metdata string arg
mysterymath Jul 21, 2025
2f49b8c
Correct modular_format to modular-format in docs
mysterymath Jul 22, 2025
d510d67
Describe the semantics of the arguments copied from C format attr
mysterymath Jul 22, 2025
ca8b788
Add a type arg
mysterymath Jul 22, 2025
34aeb64
llvm.reloc.none takes a GlobalValue again
mysterymath Aug 21, 2025
9dff0b3
Add test cases and polish change
mysterymath Aug 26, 2025
7adc2bd
[clang] "modular_format" attribute for functions using format strings
mysterymath Jun 10, 2025
78a37cc
Update docs to account for clang inferring format attribute
mysterymath Jul 15, 2025
f5681b3
Add an example to clang attr doc
mysterymath Jul 16, 2025
aaeb8a9
Emit the new type arg from format attr
mysterymath Jul 22, 2025
3ed12cd
Correct typos
mysterymath Jul 22, 2025
5498b26
[libc] Modular printf option (float only)
mysterymath Dec 19, 2024
662a265
Fix missed SPLIT->MODULAR rename
mysterymath Jul 15, 2025
191b1dd
Add missing file header
mysterymath Jul 15, 2025
05a3088
Use LIBC_INLINE_ASM macro
mysterymath Jul 16, 2025
40cbed7
LIBC_INLINE for modular fn definitions
mysterymath Jul 16, 2025
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
11 changes: 11 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -5240,3 +5240,14 @@ def NonString : InheritableAttr {
let Subjects = SubjectList<[Var, Field]>;
let Documentation = [NonStringDocs];
}

def ModularFormat : InheritableAttr {
let Spellings = [Clang<"modular_format">];
let Args = [
IdentifierArgument<"ModularImplFn">,
StringArgument<"ImplName">,
VariadicStringArgument<"Aspects">
];
let Subjects = SubjectList<[Function]>;
let Documentation = [ModularFormatDocs];
}
34 changes: 34 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -9605,3 +9605,37 @@ silence diagnostics with code like:
__attribute__((nonstring)) char NotAStr[3] = "foo"; // Not diagnosed
}];
}

def ModularFormatDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``modular_format`` attribute can be applied to a function that bears the
``format`` attribute (or standard library functions) to indicate that the
implementation is modular on the format string argument. When the format string
for a given call is constant, the compiler may redirect the call to the symbol
given as the first argument to the attribute (the modular implementation
function).

The second argument is a implementation name, and the remaining arguments are
aspects of the format string for the compiler to report. If the compiler does
not understand an aspect, it must summarily report that the format string has
that aspect.

The compiler reports an aspect by issuing a relocation for the symbol
``<impl_name>_<aspect>``. This arranges for code and data needed to support the
aspect of the implementation to be brought into the link to satisfy weak
references in the modular implemenation function.

For example, say ``printf`` is annotated with
``modular_format(__modular_printf, __printf, float)``. Then, a call to
``printf(var, 42)`` would be untouched. A call to ``printf("%d", 42)`` would
become a call to ``__modular_printf`` with the same arguments, as would
``printf("%f", 42.0)``. The latter would be accompanied with a strong
relocation against the symbol ``__printf_float``, which would bring floating
point support for ``printf`` into the link.

The following aspects are currently supported:

- ``float``: The call has a floating point argument
}];
}
14 changes: 14 additions & 0 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2560,6 +2560,20 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,

if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>())
FuncAttrs.addAttribute("aarch64_pstate_sm_body");

if (auto *ModularFormat = TargetDecl->getAttr<ModularFormatAttr>()) {
// TODO: Error checking
FormatAttr *Format = TargetDecl->getAttr<FormatAttr>();
StringRef Type = Format->getType()->getName();
std::string FormatIdx = std::to_string(Format->getFormatIdx());
std::string FirstArg = std::to_string(Format->getFirstArg());
SmallVector<StringRef> Args = {
Type, FormatIdx, FirstArg,
ModularFormat->getModularImplFn()->getName(),
ModularFormat->getImplName()};
llvm::append_range(Args, ModularFormat->aspects());
FuncAttrs.addAttribute("modular-format", llvm::join(Args, ","));
}
}

// Attach "no-builtins" attributes to:
Expand Down
27 changes: 27 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6751,6 +6751,29 @@ static void handleVTablePointerAuthentication(Sema &S, Decl *D,
CustomDiscriminationValue));
}

static void handleModularFormat(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef ImplName;
if (!S.checkStringLiteralArgumentAttr(AL, 1, ImplName))
return;
SmallVector<StringRef> Aspects;
for (unsigned I = 2, E = AL.getNumArgs(); I != E; ++I) {
StringRef Aspect;
if (!S.checkStringLiteralArgumentAttr(AL, I, Aspect))
return;
Aspects.push_back(Aspect);
}

// Store aspects sorted and without duplicates.
llvm::sort(Aspects);
Aspects.erase(llvm::unique(Aspects), Aspects.end());

// TODO: Type checking on identifier
// TODO: Merge attributes
D->addAttr(::new (S.Context) ModularFormatAttr(
S.Context, AL, AL.getArgAsIdent(0)->getIdentifierInfo(), ImplName,
Aspects.data(), Aspects.size()));
}

//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -7681,6 +7704,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_VTablePointerAuthentication:
handleVTablePointerAuthentication(S, D, AL);
break;

case ParsedAttr::AT_ModularFormat:
handleModularFormat(S, D, AL);
break;
}
}

Expand Down
4 changes: 4 additions & 0 deletions libc/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,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()

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 @@ -114,10 +117,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);
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"

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
Loading
Loading