llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-llvm-support Author: Alexis Engelke (aengelke) <details> <summary>Changes</summary> Currently, format_object creates a 32B vtable for every instantiation. This is costs space and dynamic relocations. Make format_object non-virtual and adapt the two printing users to use a function_ref instead. --- Full diff: https://github.com/llvm/llvm-project/pull/206319.diff 5 Files Affected: - (modified) clang/tools/libclang/CIndex.cpp (-5) - (modified) clang/tools/libclang/CLog.h (+7-1) - (modified) llvm/include/llvm/Support/Format.h (+31-43) - (modified) llvm/include/llvm/Support/raw_ostream.h (+2-1) - (modified) llvm/lib/Support/raw_ostream.cpp (+4-11) ``````````diff diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index ac2fad38a1348..9bc2f66d7f75f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -10179,11 +10179,6 @@ Logger &cxindex::Logger::operator<<(CXString Str) { return *this; } -Logger &cxindex::Logger::operator<<(const llvm::format_object_base &Fmt) { - LogOS << Fmt; - return *this; -} - static llvm::ManagedStatic<std::mutex> LoggingMutex; cxindex::Logger::~Logger() { diff --git a/clang/tools/libclang/CLog.h b/clang/tools/libclang/CLog.h index 6ce43a01ee8f2..a880fb03b4e87 100644 --- a/clang/tools/libclang/CLog.h +++ b/clang/tools/libclang/CLog.h @@ -16,6 +16,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/Format.h" #include "llvm/Support/raw_ostream.h" #include <string> @@ -82,7 +83,12 @@ class Logger : public RefCountedBase<Logger> { Logger &operator<<(char C) { LogOS << C; return *this; } Logger &operator<<(unsigned char C) { LogOS << C; return *this; } Logger &operator<<(signed char C) { LogOS << C; return *this; } - Logger &operator<<(const llvm::format_object_base &Fmt); + + template <typename... Ts> + Logger &operator<<(const llvm::format_object<Ts...> &Fmt) { + LogOS << Fmt; + return *this; + } }; } diff --git a/llvm/include/llvm/Support/Format.h b/llvm/include/llvm/Support/Format.h index b549341a40e7f..fff1bc5464c57 100644 --- a/llvm/include/llvm/Support/Format.h +++ b/llvm/include/llvm/Support/Format.h @@ -27,6 +27,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/DataTypes.h" +#include "llvm/Support/raw_ostream.h" #include <cassert> #include <cstdio> #include <optional> @@ -35,44 +36,6 @@ namespace llvm { -/// This is a helper class used for handling formatted output. It is the -/// abstract base class of a templated derived class. -class LLVM_ABI format_object_base { -protected: - const char *Fmt; - ~format_object_base() = default; // Disallow polymorphic deletion. - format_object_base(const format_object_base &) = default; - virtual void home(); // Out of line virtual method. - - /// Call snprintf() for this object, on the given buffer and size. - virtual int snprint(char *Buffer, unsigned BufferSize) const = 0; - -public: - format_object_base(const char *fmt) : Fmt(fmt) {} - - /// Format the object into the specified buffer. On success, this returns - /// the length of the formatted string. If the buffer is too small, this - /// returns a length to retry with, which will be larger than BufferSize. - unsigned print(char *Buffer, unsigned BufferSize) const { - assert(BufferSize && "Invalid buffer size!"); - - // Print the string, leaving room for the terminating null. - int N = snprint(Buffer, BufferSize); - - // VC++ and old GlibC return negative on overflow, just double the size. - if (N < 0) - return BufferSize * 2; - - // Other implementations yield number of bytes needed, not including the - // final '\0'. - if (unsigned(N) >= BufferSize) - return N + 1; - - // Otherwise N is the length of output (not including the final '\0'). - return N; - } -}; - /// These are templated helper classes used by the format function that /// capture the object to be formatted and the format string. When actually /// printed, this synthesizes the string into a temporary buffer provided and @@ -89,8 +52,8 @@ template <typename T> using decay_if_c_char_array_t = typename decay_if_c_char_array<T>::type; } // namespace detail -template <typename... Ts> -class format_object final : public format_object_base { +template <typename... Ts> class format_object { + const char *Fmt; std::tuple<detail::decay_if_c_char_array_t<Ts>...> Vals; template <std::size_t... Is> @@ -104,18 +67,43 @@ class format_object final : public format_object_base { } public: - format_object(const char *fmt, const Ts &... vals) - : format_object_base(fmt), Vals(vals...) { + format_object(const char *fmt, const Ts &...vals) : Fmt(fmt), Vals(vals...) { static_assert( (std::is_scalar_v<detail::decay_if_c_char_array_t<Ts>> && ...), "format can't be used with non fundamental / non pointer type"); } - int snprint(char *Buffer, unsigned BufferSize) const override { + int snprint(char *Buffer, unsigned BufferSize) const { return snprint_tuple(Buffer, BufferSize, std::index_sequence_for<Ts...>()); } + + unsigned print(char *Buffer, unsigned BufferSize) const { + assert(BufferSize && "Invalid buffer size!"); + + // Print the string, leaving room for the terminating null. + int N = snprint(Buffer, BufferSize); + + // VC++ and old GlibC return negative on overflow, just double the size. + if (N < 0) + return BufferSize * 2; + + // Other implementations yield number of bytes needed, not including the + // final '\0'. + if (unsigned(N) >= BufferSize) + return N + 1; + + // Otherwise N is the length of output (not including the final '\0'). + return N; + } }; +template <typename... Ts> +raw_ostream &operator<<(raw_ostream &OS, format_object<Ts...> Fmt) { + OS << + [&Fmt](char *Buf, size_t Size) -> size_t { return Fmt.print(Buf, Size); }; + return OS; +} + /// These are helper functions used to produce formatted output. They use /// template type deduction to construct the appropriate instance of the /// format_object class to simplify their construction. diff --git a/llvm/include/llvm/Support/raw_ostream.h b/llvm/include/llvm/Support/raw_ostream.h index 1e66052c849b7..afd45465bcd1c 100644 --- a/llvm/include/llvm/Support/raw_ostream.h +++ b/llvm/include/llvm/Support/raw_ostream.h @@ -13,6 +13,7 @@ #ifndef LLVM_SUPPORT_RAW_OSTREAM_H #define LLVM_SUPPORT_RAW_OSTREAM_H +#include "llvm/ADT/STLFunctionalExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Compiler.h" @@ -305,7 +306,7 @@ class LLVM_ABI raw_ostream { raw_ostream &write(const char *Ptr, size_t Size); // Formatted output, see the format() function in Support/Format.h. - raw_ostream &operator<<(const format_object_base &Fmt); + raw_ostream &operator<<(function_ref<size_t(char *, size_t)> Print); // Formatted output, see the leftJustify() function in Support/Format.h. raw_ostream &operator<<(const FormattedString &); diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp index 9b590dbc2ae27..4c99854dd9bd9 100644 --- a/llvm/lib/Support/raw_ostream.cpp +++ b/llvm/lib/Support/raw_ostream.cpp @@ -295,13 +295,14 @@ void raw_ostream::copy_to_buffer(const char *Ptr, size_t Size) { } // Formatted output. -raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) { +raw_ostream & +raw_ostream::operator<<(function_ref<size_t(char *, size_t)> Print) { // If we have more than a few bytes left in our output buffer, try // formatting directly onto its end. size_t NextBufferSize = 127; size_t BufferBytesLeft = OutBufEnd - OutBufCur; if (BufferBytesLeft > 3) { - size_t BytesUsed = Fmt.print(OutBufCur, BufferBytesLeft); + size_t BytesUsed = Print(OutBufCur, BufferBytesLeft); // Common case is that we have plenty of space. if (BytesUsed <= BufferBytesLeft) { @@ -323,7 +324,7 @@ raw_ostream &raw_ostream::operator<<(const format_object_base &Fmt) { V.resize(NextBufferSize); // Try formatting into the SmallVector. - size_t BytesUsed = Fmt.print(V.data(), NextBufferSize); + size_t BytesUsed = Print(V.data(), NextBufferSize); // If BytesUsed fit into the vector, we win. if (BytesUsed <= NextBufferSize) @@ -540,14 +541,6 @@ raw_ostream &raw_ostream::reverseColor() { void raw_ostream::anchor() {} -//===----------------------------------------------------------------------===// -// Formatted Output -//===----------------------------------------------------------------------===// - -// Out of line virtual method. -void format_object_base::home() { -} - //===----------------------------------------------------------------------===// // raw_fd_ostream //===----------------------------------------------------------------------===// `````````` </details> https://github.com/llvm/llvm-project/pull/206319 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
