17330f729Sjoerg //===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg
97330f729Sjoerg #include "llvm/Support/NativeFormatting.h"
107330f729Sjoerg #include "llvm/ADT/ArrayRef.h"
117330f729Sjoerg #include "llvm/ADT/SmallString.h"
127330f729Sjoerg #include "llvm/ADT/StringExtras.h"
137330f729Sjoerg #include "llvm/Support/Format.h"
14*82d56013Sjoerg #include "llvm/Support/raw_ostream.h"
157330f729Sjoerg #include <float.h>
167330f729Sjoerg
177330f729Sjoerg using namespace llvm;
187330f729Sjoerg
197330f729Sjoerg template<typename T, std::size_t N>
format_to_buffer(T Value,char (& Buffer)[N])207330f729Sjoerg static int format_to_buffer(T Value, char (&Buffer)[N]) {
217330f729Sjoerg char *EndPtr = std::end(Buffer);
227330f729Sjoerg char *CurPtr = EndPtr;
237330f729Sjoerg
247330f729Sjoerg do {
257330f729Sjoerg *--CurPtr = '0' + char(Value % 10);
267330f729Sjoerg Value /= 10;
277330f729Sjoerg } while (Value);
287330f729Sjoerg return EndPtr - CurPtr;
297330f729Sjoerg }
307330f729Sjoerg
writeWithCommas(raw_ostream & S,ArrayRef<char> Buffer)317330f729Sjoerg static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
327330f729Sjoerg assert(!Buffer.empty());
337330f729Sjoerg
347330f729Sjoerg ArrayRef<char> ThisGroup;
357330f729Sjoerg int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
367330f729Sjoerg ThisGroup = Buffer.take_front(InitialDigits);
377330f729Sjoerg S.write(ThisGroup.data(), ThisGroup.size());
387330f729Sjoerg
397330f729Sjoerg Buffer = Buffer.drop_front(InitialDigits);
407330f729Sjoerg assert(Buffer.size() % 3 == 0);
417330f729Sjoerg while (!Buffer.empty()) {
427330f729Sjoerg S << ',';
437330f729Sjoerg ThisGroup = Buffer.take_front(3);
447330f729Sjoerg S.write(ThisGroup.data(), 3);
457330f729Sjoerg Buffer = Buffer.drop_front(3);
467330f729Sjoerg }
477330f729Sjoerg }
487330f729Sjoerg
497330f729Sjoerg template <typename T>
write_unsigned_impl(raw_ostream & S,T N,size_t MinDigits,IntegerStyle Style,bool IsNegative)507330f729Sjoerg static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
517330f729Sjoerg IntegerStyle Style, bool IsNegative) {
527330f729Sjoerg static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
537330f729Sjoerg
547330f729Sjoerg char NumberBuffer[128];
557330f729Sjoerg std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
567330f729Sjoerg
577330f729Sjoerg size_t Len = 0;
587330f729Sjoerg Len = format_to_buffer(N, NumberBuffer);
597330f729Sjoerg
607330f729Sjoerg if (IsNegative)
617330f729Sjoerg S << '-';
627330f729Sjoerg
637330f729Sjoerg if (Len < MinDigits && Style != IntegerStyle::Number) {
647330f729Sjoerg for (size_t I = Len; I < MinDigits; ++I)
657330f729Sjoerg S << '0';
667330f729Sjoerg }
677330f729Sjoerg
687330f729Sjoerg if (Style == IntegerStyle::Number) {
697330f729Sjoerg writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
707330f729Sjoerg } else {
717330f729Sjoerg S.write(std::end(NumberBuffer) - Len, Len);
727330f729Sjoerg }
737330f729Sjoerg }
747330f729Sjoerg
757330f729Sjoerg template <typename T>
write_unsigned(raw_ostream & S,T N,size_t MinDigits,IntegerStyle Style,bool IsNegative=false)767330f729Sjoerg static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
777330f729Sjoerg IntegerStyle Style, bool IsNegative = false) {
787330f729Sjoerg // Output using 32-bit div/mod if possible.
797330f729Sjoerg if (N == static_cast<uint32_t>(N))
807330f729Sjoerg write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
817330f729Sjoerg IsNegative);
827330f729Sjoerg else
837330f729Sjoerg write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
847330f729Sjoerg }
857330f729Sjoerg
867330f729Sjoerg template <typename T>
write_signed(raw_ostream & S,T N,size_t MinDigits,IntegerStyle Style)877330f729Sjoerg static void write_signed(raw_ostream &S, T N, size_t MinDigits,
887330f729Sjoerg IntegerStyle Style) {
897330f729Sjoerg static_assert(std::is_signed<T>::value, "Value is not signed!");
907330f729Sjoerg
91*82d56013Sjoerg using UnsignedT = std::make_unsigned_t<T>;
927330f729Sjoerg
937330f729Sjoerg if (N >= 0) {
947330f729Sjoerg write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
957330f729Sjoerg return;
967330f729Sjoerg }
977330f729Sjoerg
987330f729Sjoerg UnsignedT UN = -(UnsignedT)N;
997330f729Sjoerg write_unsigned(S, UN, MinDigits, Style, true);
1007330f729Sjoerg }
1017330f729Sjoerg
write_integer(raw_ostream & S,unsigned int N,size_t MinDigits,IntegerStyle Style)1027330f729Sjoerg void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
1037330f729Sjoerg IntegerStyle Style) {
1047330f729Sjoerg write_unsigned(S, N, MinDigits, Style);
1057330f729Sjoerg }
1067330f729Sjoerg
write_integer(raw_ostream & S,int N,size_t MinDigits,IntegerStyle Style)1077330f729Sjoerg void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
1087330f729Sjoerg IntegerStyle Style) {
1097330f729Sjoerg write_signed(S, N, MinDigits, Style);
1107330f729Sjoerg }
1117330f729Sjoerg
write_integer(raw_ostream & S,unsigned long N,size_t MinDigits,IntegerStyle Style)1127330f729Sjoerg void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
1137330f729Sjoerg IntegerStyle Style) {
1147330f729Sjoerg write_unsigned(S, N, MinDigits, Style);
1157330f729Sjoerg }
1167330f729Sjoerg
write_integer(raw_ostream & S,long N,size_t MinDigits,IntegerStyle Style)1177330f729Sjoerg void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
1187330f729Sjoerg IntegerStyle Style) {
1197330f729Sjoerg write_signed(S, N, MinDigits, Style);
1207330f729Sjoerg }
1217330f729Sjoerg
write_integer(raw_ostream & S,unsigned long long N,size_t MinDigits,IntegerStyle Style)1227330f729Sjoerg void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
1237330f729Sjoerg IntegerStyle Style) {
1247330f729Sjoerg write_unsigned(S, N, MinDigits, Style);
1257330f729Sjoerg }
1267330f729Sjoerg
write_integer(raw_ostream & S,long long N,size_t MinDigits,IntegerStyle Style)1277330f729Sjoerg void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
1287330f729Sjoerg IntegerStyle Style) {
1297330f729Sjoerg write_signed(S, N, MinDigits, Style);
1307330f729Sjoerg }
1317330f729Sjoerg
write_hex(raw_ostream & S,uint64_t N,HexPrintStyle Style,Optional<size_t> Width)1327330f729Sjoerg void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
1337330f729Sjoerg Optional<size_t> Width) {
1347330f729Sjoerg const size_t kMaxWidth = 128u;
1357330f729Sjoerg
1367330f729Sjoerg size_t W = std::min(kMaxWidth, Width.getValueOr(0u));
1377330f729Sjoerg
1387330f729Sjoerg unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
1397330f729Sjoerg bool Prefix = (Style == HexPrintStyle::PrefixLower ||
1407330f729Sjoerg Style == HexPrintStyle::PrefixUpper);
1417330f729Sjoerg bool Upper =
1427330f729Sjoerg (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
1437330f729Sjoerg unsigned PrefixChars = Prefix ? 2 : 0;
1447330f729Sjoerg unsigned NumChars =
1457330f729Sjoerg std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
1467330f729Sjoerg
1477330f729Sjoerg char NumberBuffer[kMaxWidth];
1487330f729Sjoerg ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
1497330f729Sjoerg if (Prefix)
1507330f729Sjoerg NumberBuffer[1] = 'x';
1517330f729Sjoerg char *EndPtr = NumberBuffer + NumChars;
1527330f729Sjoerg char *CurPtr = EndPtr;
1537330f729Sjoerg while (N) {
1547330f729Sjoerg unsigned char x = static_cast<unsigned char>(N) % 16;
1557330f729Sjoerg *--CurPtr = hexdigit(x, !Upper);
1567330f729Sjoerg N /= 16;
1577330f729Sjoerg }
1587330f729Sjoerg
1597330f729Sjoerg S.write(NumberBuffer, NumChars);
1607330f729Sjoerg }
1617330f729Sjoerg
write_double(raw_ostream & S,double N,FloatStyle Style,Optional<size_t> Precision)1627330f729Sjoerg void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
1637330f729Sjoerg Optional<size_t> Precision) {
1647330f729Sjoerg size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
1657330f729Sjoerg
1667330f729Sjoerg if (std::isnan(N)) {
1677330f729Sjoerg S << "nan";
1687330f729Sjoerg return;
1697330f729Sjoerg } else if (std::isinf(N)) {
1707330f729Sjoerg S << "INF";
1717330f729Sjoerg return;
1727330f729Sjoerg }
1737330f729Sjoerg
1747330f729Sjoerg char Letter;
1757330f729Sjoerg if (Style == FloatStyle::Exponent)
1767330f729Sjoerg Letter = 'e';
1777330f729Sjoerg else if (Style == FloatStyle::ExponentUpper)
1787330f729Sjoerg Letter = 'E';
1797330f729Sjoerg else
1807330f729Sjoerg Letter = 'f';
1817330f729Sjoerg
1827330f729Sjoerg SmallString<8> Spec;
1837330f729Sjoerg llvm::raw_svector_ostream Out(Spec);
1847330f729Sjoerg Out << "%." << Prec << Letter;
1857330f729Sjoerg
1867330f729Sjoerg if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
1877330f729Sjoerg #ifdef _WIN32
1887330f729Sjoerg // On MSVCRT and compatible, output of %e is incompatible to Posix
1897330f729Sjoerg // by default. Number of exponent digits should be at least 2. "%+03d"
1907330f729Sjoerg // FIXME: Implement our formatter to here or Support/Format.h!
1917330f729Sjoerg #if defined(__MINGW32__)
1927330f729Sjoerg // FIXME: It should be generic to C++11.
1937330f729Sjoerg if (N == 0.0 && std::signbit(N)) {
1947330f729Sjoerg char NegativeZero[] = "-0.000000e+00";
1957330f729Sjoerg if (Style == FloatStyle::ExponentUpper)
1967330f729Sjoerg NegativeZero[strlen(NegativeZero) - 4] = 'E';
1977330f729Sjoerg S << NegativeZero;
1987330f729Sjoerg return;
1997330f729Sjoerg }
2007330f729Sjoerg #else
2017330f729Sjoerg int fpcl = _fpclass(N);
2027330f729Sjoerg
2037330f729Sjoerg // negative zero
2047330f729Sjoerg if (fpcl == _FPCLASS_NZ) {
2057330f729Sjoerg char NegativeZero[] = "-0.000000e+00";
2067330f729Sjoerg if (Style == FloatStyle::ExponentUpper)
2077330f729Sjoerg NegativeZero[strlen(NegativeZero) - 4] = 'E';
2087330f729Sjoerg S << NegativeZero;
2097330f729Sjoerg return;
2107330f729Sjoerg }
2117330f729Sjoerg #endif
2127330f729Sjoerg
2137330f729Sjoerg char buf[32];
2147330f729Sjoerg unsigned len;
2157330f729Sjoerg len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
2167330f729Sjoerg if (len <= sizeof(buf) - 2) {
2177330f729Sjoerg if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
2187330f729Sjoerg buf[len - 3] == '0') {
2197330f729Sjoerg int cs = buf[len - 4];
2207330f729Sjoerg if (cs == '+' || cs == '-') {
2217330f729Sjoerg int c1 = buf[len - 2];
2227330f729Sjoerg int c0 = buf[len - 1];
2237330f729Sjoerg if (isdigit(static_cast<unsigned char>(c1)) &&
2247330f729Sjoerg isdigit(static_cast<unsigned char>(c0))) {
2257330f729Sjoerg // Trim leading '0': "...e+012" -> "...e+12\0"
2267330f729Sjoerg buf[len - 3] = c1;
2277330f729Sjoerg buf[len - 2] = c0;
2287330f729Sjoerg buf[--len] = 0;
2297330f729Sjoerg }
2307330f729Sjoerg }
2317330f729Sjoerg }
2327330f729Sjoerg S << buf;
2337330f729Sjoerg return;
2347330f729Sjoerg }
2357330f729Sjoerg #endif
2367330f729Sjoerg }
2377330f729Sjoerg
2387330f729Sjoerg if (Style == FloatStyle::Percent)
2397330f729Sjoerg N *= 100.0;
2407330f729Sjoerg
2417330f729Sjoerg char Buf[32];
2427330f729Sjoerg format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
2437330f729Sjoerg S << Buf;
2447330f729Sjoerg if (Style == FloatStyle::Percent)
2457330f729Sjoerg S << '%';
2467330f729Sjoerg }
2477330f729Sjoerg
isPrefixedHexStyle(HexPrintStyle S)2487330f729Sjoerg bool llvm::isPrefixedHexStyle(HexPrintStyle S) {
2497330f729Sjoerg return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
2507330f729Sjoerg }
2517330f729Sjoerg
getDefaultPrecision(FloatStyle Style)2527330f729Sjoerg size_t llvm::getDefaultPrecision(FloatStyle Style) {
2537330f729Sjoerg switch (Style) {
2547330f729Sjoerg case FloatStyle::Exponent:
2557330f729Sjoerg case FloatStyle::ExponentUpper:
2567330f729Sjoerg return 6; // Number of decimal places.
2577330f729Sjoerg case FloatStyle::Fixed:
2587330f729Sjoerg case FloatStyle::Percent:
2597330f729Sjoerg return 2; // Number of decimal places.
2607330f729Sjoerg }
2617330f729Sjoerg LLVM_BUILTIN_UNREACHABLE;
2627330f729Sjoerg }
263