Add FMT_REDUCE_INT_INSTANTIATIONS flag (#1781)

* Remove <typename UInt> from int_writer

Reduce code bloat by removing multiple instantiation of int_writer based
on the <typename UInt> parameter.

Rationale:
- The only functions that gains a speedup by int size would be
  int_writer::on_dec()'s call to count_digits which uses CLZ. Thus to
  still take advantage of this speedup, we store the size of the int
  so we can use a switch statement to call the correct count_digits.
- All other implementations of count_digits require some sort of looping
  that terminates when the value hits zero regardless of what sized int
  it is.

Caveats:
- There is a performance hit when dealing with and passing around
  64-bit/128-bit values compared to 32-bit values on 32-bit platforms,
  and with 64-bit values on 64-bit systems. But this should not reduce the
  performance that dramatically.
- There is also a performance hit for on_dec() due to the addition of a
  switch case. But, due to it size, this should reduce to a jump table.

Resolves #1778

* Add FMT_USE_SMALLEST_INT flag

When defined and set to zero, will use the largest available integer
container for writing ints. The has the benefit of reducing instances
the of int_writer class which will reduce the binary cost.

* Rename flag to FMT_REDUCE_INT_INSTANTIATIONS

Add comment above FMT_REDUCE_INT_INSTANTIATIONS definition describing
why a developer would use it.

* Move FMT_REDUCE_INT_INSTANTIATIONS to format.h

Co-authored-by: Khalil Estell <kammce@google.com>
This commit is contained in:
Khalil Estell 2020-07-19 13:09:10 -07:00 committed by GitHub
parent c08518a25b
commit d11849bc0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -163,6 +163,14 @@ FMT_END_NAMESPACE
# define FMT_USE_LONG_DOUBLE 1 # define FMT_USE_LONG_DOUBLE 1
#endif #endif
// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of
// int_writer template instances to just one by only using the largest integer
// type. This results in a reduction in binary size but will cause a decrease in
// integer formatting performance.
#if !defined(FMT_REDUCE_INT_INSTANTIATIONS)
# define FMT_REDUCE_INT_INSTANTIATIONS 0
#endif
// __builtin_clz is broken in clang with Microsoft CodeGen: // __builtin_clz is broken in clang with Microsoft CodeGen:
// https://github.com/fmtlib/fmt/issues/519 // https://github.com/fmtlib/fmt/issues/519
#if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER #if (FMT_GCC_VERSION || FMT_HAS_BUILTIN(__builtin_clz)) && !FMT_MSC_VER
@ -738,12 +746,19 @@ FMT_CONSTEXPR bool is_supported_floating_point(T) {
(std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE); (std::is_same<T, long double>::value && FMT_USE_LONG_DOUBLE);
} }
#if FMT_REDUCE_INT_INSTANTIATIONS
// Pick the largest integer container to represent all values of T.
template <typename T>
using uint32_or_64_or_128_t =
conditional_t<sizeof(uint128_t) < sizeof(uint64_t), uint64_t, uint128_t>;
#else
// Smallest of uint32_t, uint64_t, uint128_t that is large enough to // Smallest of uint32_t, uint64_t, uint128_t that is large enough to
// represent all values of T. // represent all values of T.
template <typename T> template <typename T>
using uint32_or_64_or_128_t = conditional_t< using uint32_or_64_or_128_t = conditional_t<
std::numeric_limits<T>::digits <= 32, uint32_t, std::numeric_limits<T>::digits <= 32, uint32_t,
conditional_t<std::numeric_limits<T>::digits <= 64, uint64_t, uint128_t>>; conditional_t<std::numeric_limits<T>::digits <= 64, uint64_t, uint128_t>>;
#endif
// Static data is placed in this class template for the header-only config. // Static data is placed in this class template for the header-only config.
template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data { template <typename T = void> struct FMT_EXTERN_TEMPLATE_API basic_data {