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 &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
@@ -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 &section,
+                                       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

Reply via email to