Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workaround intel bug #3652

Merged
merged 5 commits into from
Sep 21, 2023
Merged
Changes from 2 commits
Commits
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
41 changes: 17 additions & 24 deletions include/fmt/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1740,28 +1740,6 @@ FMT_CONSTEXPR inline fp operator*(fp x, fp y) {
return {multiply(x.f, y.f), x.e + y.e + 64};
}

template <typename T = void> struct basic_data {
// For checking rounding thresholds.
// The kth entry is chosen to be the smallest integer such that the
// upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k.
static constexpr uint32_t fractional_part_rounding_thresholds[8] = {
2576980378U, // ceil(2^31 + 2^32/10^1)
2190433321U, // ceil(2^31 + 2^32/10^2)
2151778616U, // ceil(2^31 + 2^32/10^3)
2147913145U, // ceil(2^31 + 2^32/10^4)
2147526598U, // ceil(2^31 + 2^32/10^5)
2147487943U, // ceil(2^31 + 2^32/10^6)
2147484078U, // ceil(2^31 + 2^32/10^7)
2147483691U // ceil(2^31 + 2^32/10^8)
};
};
// This is a struct rather than an alias to avoid shadowing warnings in gcc.
struct data : basic_data<> {};

#if FMT_CPLUSPLUS < 201703L
template <typename T>
constexpr uint32_t basic_data<T>::fractional_part_rounding_thresholds[];
#endif

template <typename T, bool doublish = num_bits<T>() == num_bits<double>()>
using convert_float_result =
Expand Down Expand Up @@ -3283,6 +3261,21 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision,
template <typename Float>
FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
buffer<char>& buf) -> int {

// For checking rounding thresholds.
// The kth entry is chosen to be the smallest integer such that the
// upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k.
static constexpr uint32_t fractional_part_rounding_thresholds[8] = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need to drop static here:

/Users/runner/work/fmt/fmt/include/fmt/format.h:3268:29: error: definition of a static variable in a constexpr function is a C++2b extension [-Werror,-Wc++2b-extensions]
  static constexpr uint32_t fractional_part_rounding_thresholds[8] = {
                            ^

Also please move to a separate function to avoid parametrization on Float, something like

FMT_CONSTEXPR uint32_t fractional_part_rounding_threshold(int index) {
  constexpr uint32_t thresholds[] = {...};
  return thresholds[index];
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitaut
Will a non-static constexpr array be optimized by the compiler?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

¯_(ツ)_/¯

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitaut

It doesn't get optimized: https://godbolt.org/z/drn31x9zK

Maybe revert this PR?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we should revert this PR but ideas/PRs to optimize it would be welcome.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitaut
Solution for GCC, Clang: https://godbolt.org/z/ezj9GhnYW
But not for MSVC (current code: https://godbolt.org/z/5Pxn3zMfT)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have another idea: 06b2038.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vitaut Solution for GCC, Clang: https://godbolt.org/z/ezj9GhnYW But not for MSVC (current code: https://godbolt.org/z/5Pxn3zMfT)

That looks good. I had something similar but didn't think of the unreachable to quiet the warnings and keep the optimization.

2576980378U, // ceil(2^31 + 2^32/10^1)
2190433321U, // ceil(2^31 + 2^32/10^2)
2151778616U, // ceil(2^31 + 2^32/10^3)
2147913145U, // ceil(2^31 + 2^32/10^4)
2147526598U, // ceil(2^31 + 2^32/10^5)
2147487943U, // ceil(2^31 + 2^32/10^6)
2147484078U, // ceil(2^31 + 2^32/10^7)
2147483691U // ceil(2^31 + 2^32/10^8)
};

// float is passed as double to reduce the number of instantiations.
static_assert(!std::is_same<Float, float>::value, "");
FMT_ASSERT(value >= 0, "value is negative");
Expand Down Expand Up @@ -3485,7 +3478,7 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
if (precision < 9) {
uint32_t fractional_part = static_cast<uint32_t>(prod);
should_round_up = fractional_part >=
data::fractional_part_rounding_thresholds
fractional_part_rounding_thresholds
[8 - number_of_digits_to_print] ||
((fractional_part >> 31) &
((digits & 1) | (second_third_subsegments != 0) |
Expand Down Expand Up @@ -3525,7 +3518,7 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs,
// consisting of a genuine digit from the input.
uint32_t fractional_part = static_cast<uint32_t>(prod);
should_round_up = fractional_part >=
data::fractional_part_rounding_thresholds
fractional_part_rounding_thresholds
[8 - number_of_digits_to_print] ||
((fractional_part >> 31) &
((digits & 1) | (third_subsegment != 0) |
Expand Down
Loading