I "massaged" a bit your original code:
constexpr auto format(T value, auto& format_context)
{
// Invalid generated code
const auto undVal = static_cast<std::underlying_type_t<T>>(value);
return formatter<std::underlying_type_t<T>>::format(undVal, format_context);
}
into this form:
template <typename FormatContext>
constexpr auto format(T value, FormatContext& format_context) const
{
// Invalid generated code
const auto undVal = static_cast<std::underlying_type_t<T>>(value);
return formatter<std::underlying_type_t<T>>::format(undVal, format_context);
}
And it seems to me that the assembly code that is generated with MSVC v19.29 looks similar to what you expect, without the cvttsd2si
instruction.
Compiler Explorer link: https://godbolt.org/z/xKdM9xd8f
Generated assembly:
mov eax, DWORD PTR value$[rsp]
mov DWORD PTR undVal$[rsp], eax
BTW, I agree with David that, if possible, you should upgrade to the most recent version of MSVC. The quality of the MSVC C++ compiler and libraries has historically been monotonically increasing.