mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 18:01:07 +01:00
Shrink debug info emitted for CARBON_CHECK message formatting (#7339)
This is based on an idea suggested during review of the original type erasure PR. The type-erased check failure path lowers each check through `CheckFailFormat<Ts...>`, which builds one format adapter per value, down to the out-of-line `CheckFailImpl`, which takes an array of base-class `format_adapter*` pointers. Previously a separate variadic `CheckFailWithAdapters<Adapters...>` template sat in between: it existed only to bind the adapter temporaries to named parameters so that pointers to their base class could be collected into a `std::array` and outlive the call to `CheckFailImpl`. This removes that layer. `CheckFailFormat` now builds the pointer array directly, in the braced-init-list of the `CheckFailImpl` call, using a small `CheckFailFormatAdapterAddr<T>` helper to take the base-class address of each adapter. The adapter temporaries are materialized as named parameters of that helper within the same full-expression as the `CheckFailImpl` call, so they remain alive across the call without a dedicated function for that purpose. The win is in debug info, not code. `CheckFailWithAdapters<Adapters...>` was instantiated once per distinct adapter-type sequence in every translation unit that uses `CARBON_CHECK`, and each instantiation carried its own DWARF records -- type entries, string-table offsets, and range lists. Dropping it removes those records from every such translation unit. The generated machine code is unchanged. Measured impact (fastbuild, the inputs to the inner-loop links): - First-party object files shrink by 173,728 bytes (-0.233%) across the `carbon-busybox` link inputs; 232 of 270 objects get smaller and none grow. The largest reductions are in the check-densest translation units (`type_completion`, `type`, `import_ref`, `function_context`, `constant`, ...). - Per `bloaty`, the reduction is almost entirely DWARF (`.debug_info`, `.debug_str`, `.rela.debug_str_offsets`, `.debug_rnglists`); the loaded code (VM size) is unchanged. Assisted-by: Claude Code --------- Co-authored-by: Geoff Romer <gromer@google.com>
This commit is contained in:
co-authored by
Geoff Romer
parent
77790e44a6
commit
f7e628562f
+21
-27
@@ -31,9 +31,9 @@ CheckCondition(bool condition)
|
||||
// Implements the check failure message printing.
|
||||
//
|
||||
// This is out-of-line and will arrange to stop the program, print any debugging
|
||||
// information and this string. In `!NDEBUG` mode (`dbg` and `fastbuild`), check
|
||||
// failures can be made non-fatal by a build flag, so this is not `[[noreturn]]`
|
||||
// in that case.
|
||||
// information and the failure message. In `!NDEBUG` mode (`dbg` and
|
||||
// `fastbuild`), check failures can be made non-fatal by a build flag, so this
|
||||
// is not `[[noreturn]]` in that case.
|
||||
//
|
||||
// This API uses `const char*` C string arguments rather than `llvm::StringRef`
|
||||
// because we know that these are available as C strings and passing them that
|
||||
@@ -52,8 +52,8 @@ auto CheckFailImpl(
|
||||
llvm::ArrayRef<llvm::support::detail::format_adapter*> extra_adapters)
|
||||
-> void;
|
||||
|
||||
// Allow converting format values; the default behaviour is to just pass them
|
||||
// through.
|
||||
// Allow custom conversion of format values; the default behaviour is to just
|
||||
// pass them through.
|
||||
template <typename T>
|
||||
auto ConvertFormatValue(T&& t) -> T&& {
|
||||
return std::forward<T>(t);
|
||||
@@ -74,28 +74,21 @@ auto ConvertFormatValue(T&& t) -> auto {
|
||||
}
|
||||
}
|
||||
|
||||
// Collects pointers to the given type-erased format adapters and passes them,
|
||||
// with the rest of the check metadata, to the out-of-line `CheckFailImpl`.
|
||||
//
|
||||
// We need a separate function accepting all the adapters as arguments to ensure
|
||||
// those objects stay alive for pointers to their base class to be put into an
|
||||
// array and passed to the type erased implementation.
|
||||
template <typename... Adapters>
|
||||
#ifdef NDEBUG
|
||||
[[noreturn]]
|
||||
#endif
|
||||
auto CheckFailWithAdapters(const char* kind, const char* file, int line,
|
||||
const char* condition_str, const char* extra_format,
|
||||
Adapters&&... adapters) -> void {
|
||||
std::array<llvm::support::detail::format_adapter*, sizeof...(Adapters)>
|
||||
adapter_pointers = {&adapters...};
|
||||
CheckFailImpl(kind, file, line, condition_str, extra_format,
|
||||
adapter_pointers);
|
||||
// Helper to compute a pointer to the base class of a given LLVM
|
||||
// `format_adapter` object. This both handles converting to the base class and
|
||||
// allows taking the address of temporaries within arguments to another function
|
||||
// call.
|
||||
template <typename T>
|
||||
auto CheckFailFormatAdapterAddr(T&& adapter)
|
||||
-> llvm::support::detail::format_adapter* {
|
||||
return &adapter;
|
||||
}
|
||||
|
||||
// Builds one type-erased format adapter per value -- forwarding each value
|
||||
// through the conversion machinery -- and hands them to
|
||||
// `CheckFailWithAdapters`.
|
||||
// through the conversion machinery. The address of the base classes of each of
|
||||
// these are then collected into an init list that can be accessed with an
|
||||
// `ArrayRef`. All of this is then passed to the out-of-line rendering function
|
||||
// `CheckFailImpl`.
|
||||
//
|
||||
// This is templated only on the value types, not on the per-check-site
|
||||
// metadata (file, line, etc., which are passed as ordinary arguments), so the
|
||||
@@ -108,9 +101,10 @@ template <typename... Ts>
|
||||
auto CheckFailFormat(const char* kind, const char* file, int line,
|
||||
const char* condition_str, const char* extra_format,
|
||||
Ts&&... values) -> void {
|
||||
CheckFailWithAdapters(kind, file, line, condition_str, extra_format,
|
||||
llvm::support::detail::build_format_adapter(
|
||||
ConvertFormatValue(std::forward<Ts>(values)))...);
|
||||
CheckFailImpl(
|
||||
kind, file, line, condition_str, extra_format,
|
||||
{CheckFailFormatAdapterAddr(llvm::support::detail::build_format_adapter(
|
||||
ConvertFormatValue(std::forward<Ts>(values))))...});
|
||||
}
|
||||
|
||||
// Prints a check failure, including rendering any user-provided message using
|
||||
|
||||
Reference in New Issue
Block a user