NativeFormatting.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. //===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "llvm/Support/NativeFormatting.h"
  9. #include "llvm/ADT/ArrayRef.h"
  10. #include "llvm/ADT/SmallString.h"
  11. #include "llvm/ADT/StringExtras.h"
  12. #include "llvm/Support/Format.h"
  13. #include "llvm/Support/MathExtras.h"
  14. #include "llvm/Support/raw_ostream.h"
  15. #include <cmath>
  16. #if defined(_WIN32) && !defined(__MINGW32__)
  17. #include <float.h> // For _fpclass in llvm::write_double.
  18. #endif
  19. using namespace llvm;
  20. template<typename T, std::size_t N>
  21. static int format_to_buffer(T Value, char (&Buffer)[N]) {
  22. char *EndPtr = std::end(Buffer);
  23. char *CurPtr = EndPtr;
  24. do {
  25. *--CurPtr = '0' + char(Value % 10);
  26. Value /= 10;
  27. } while (Value);
  28. return EndPtr - CurPtr;
  29. }
  30. static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
  31. assert(!Buffer.empty());
  32. ArrayRef<char> ThisGroup;
  33. int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
  34. ThisGroup = Buffer.take_front(InitialDigits);
  35. S.write(ThisGroup.data(), ThisGroup.size());
  36. Buffer = Buffer.drop_front(InitialDigits);
  37. assert(Buffer.size() % 3 == 0);
  38. while (!Buffer.empty()) {
  39. S << ',';
  40. ThisGroup = Buffer.take_front(3);
  41. S.write(ThisGroup.data(), 3);
  42. Buffer = Buffer.drop_front(3);
  43. }
  44. }
  45. template <typename T>
  46. static void write_unsigned_impl(raw_ostream &S, T N, size_t MinDigits,
  47. IntegerStyle Style, bool IsNegative) {
  48. static_assert(std::is_unsigned_v<T>, "Value is not unsigned!");
  49. char NumberBuffer[128];
  50. std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
  51. size_t Len = 0;
  52. Len = format_to_buffer(N, NumberBuffer);
  53. if (IsNegative)
  54. S << '-';
  55. if (Len < MinDigits && Style != IntegerStyle::Number) {
  56. for (size_t I = Len; I < MinDigits; ++I)
  57. S << '0';
  58. }
  59. if (Style == IntegerStyle::Number) {
  60. writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
  61. } else {
  62. S.write(std::end(NumberBuffer) - Len, Len);
  63. }
  64. }
  65. template <typename T>
  66. static void write_unsigned(raw_ostream &S, T N, size_t MinDigits,
  67. IntegerStyle Style, bool IsNegative = false) {
  68. // Output using 32-bit div/mod if possible.
  69. if (N == static_cast<uint32_t>(N))
  70. write_unsigned_impl(S, static_cast<uint32_t>(N), MinDigits, Style,
  71. IsNegative);
  72. else
  73. write_unsigned_impl(S, N, MinDigits, Style, IsNegative);
  74. }
  75. template <typename T>
  76. static void write_signed(raw_ostream &S, T N, size_t MinDigits,
  77. IntegerStyle Style) {
  78. static_assert(std::is_signed_v<T>, "Value is not signed!");
  79. using UnsignedT = std::make_unsigned_t<T>;
  80. if (N >= 0) {
  81. write_unsigned(S, static_cast<UnsignedT>(N), MinDigits, Style);
  82. return;
  83. }
  84. UnsignedT UN = -(UnsignedT)N;
  85. write_unsigned(S, UN, MinDigits, Style, true);
  86. }
  87. void llvm::write_integer(raw_ostream &S, unsigned int N, size_t MinDigits,
  88. IntegerStyle Style) {
  89. write_unsigned(S, N, MinDigits, Style);
  90. }
  91. void llvm::write_integer(raw_ostream &S, int N, size_t MinDigits,
  92. IntegerStyle Style) {
  93. write_signed(S, N, MinDigits, Style);
  94. }
  95. void llvm::write_integer(raw_ostream &S, unsigned long N, size_t MinDigits,
  96. IntegerStyle Style) {
  97. write_unsigned(S, N, MinDigits, Style);
  98. }
  99. void llvm::write_integer(raw_ostream &S, long N, size_t MinDigits,
  100. IntegerStyle Style) {
  101. write_signed(S, N, MinDigits, Style);
  102. }
  103. void llvm::write_integer(raw_ostream &S, unsigned long long N, size_t MinDigits,
  104. IntegerStyle Style) {
  105. write_unsigned(S, N, MinDigits, Style);
  106. }
  107. void llvm::write_integer(raw_ostream &S, long long N, size_t MinDigits,
  108. IntegerStyle Style) {
  109. write_signed(S, N, MinDigits, Style);
  110. }
  111. void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
  112. std::optional<size_t> Width) {
  113. const size_t kMaxWidth = 128u;
  114. size_t W = std::min(kMaxWidth, Width.value_or(0u));
  115. unsigned Nibbles = (llvm::bit_width(N) + 3) / 4;
  116. bool Prefix = (Style == HexPrintStyle::PrefixLower ||
  117. Style == HexPrintStyle::PrefixUpper);
  118. bool Upper =
  119. (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
  120. unsigned PrefixChars = Prefix ? 2 : 0;
  121. unsigned NumChars =
  122. std::max(static_cast<unsigned>(W), std::max(1u, Nibbles) + PrefixChars);
  123. char NumberBuffer[kMaxWidth];
  124. ::memset(NumberBuffer, '0', std::size(NumberBuffer));
  125. if (Prefix)
  126. NumberBuffer[1] = 'x';
  127. char *EndPtr = NumberBuffer + NumChars;
  128. char *CurPtr = EndPtr;
  129. while (N) {
  130. unsigned char x = static_cast<unsigned char>(N) % 16;
  131. *--CurPtr = hexdigit(x, !Upper);
  132. N /= 16;
  133. }
  134. S.write(NumberBuffer, NumChars);
  135. }
  136. void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
  137. std::optional<size_t> Precision) {
  138. size_t Prec = Precision.value_or(getDefaultPrecision(Style));
  139. if (std::isnan(N)) {
  140. S << "nan";
  141. return;
  142. } else if (std::isinf(N)) {
  143. S << (std::signbit(N) ? "-INF" : "INF");
  144. return;
  145. }
  146. char Letter;
  147. if (Style == FloatStyle::Exponent)
  148. Letter = 'e';
  149. else if (Style == FloatStyle::ExponentUpper)
  150. Letter = 'E';
  151. else
  152. Letter = 'f';
  153. SmallString<8> Spec;
  154. llvm::raw_svector_ostream Out(Spec);
  155. Out << "%." << Prec << Letter;
  156. if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
  157. #ifdef _WIN32
  158. // On MSVCRT and compatible, output of %e is incompatible to Posix
  159. // by default. Number of exponent digits should be at least 2. "%+03d"
  160. // FIXME: Implement our formatter to here or Support/Format.h!
  161. #if defined(__MINGW32__)
  162. // FIXME: It should be generic to C++11.
  163. if (N == 0.0 && std::signbit(N)) {
  164. char NegativeZero[] = "-0.000000e+00";
  165. if (Style == FloatStyle::ExponentUpper)
  166. NegativeZero[strlen(NegativeZero) - 4] = 'E';
  167. S << NegativeZero;
  168. return;
  169. }
  170. #else
  171. int fpcl = _fpclass(N);
  172. // negative zero
  173. if (fpcl == _FPCLASS_NZ) {
  174. char NegativeZero[] = "-0.000000e+00";
  175. if (Style == FloatStyle::ExponentUpper)
  176. NegativeZero[strlen(NegativeZero) - 4] = 'E';
  177. S << NegativeZero;
  178. return;
  179. }
  180. #endif
  181. char buf[32];
  182. unsigned len;
  183. len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
  184. if (len <= sizeof(buf) - 2) {
  185. if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
  186. buf[len - 3] == '0') {
  187. int cs = buf[len - 4];
  188. if (cs == '+' || cs == '-') {
  189. int c1 = buf[len - 2];
  190. int c0 = buf[len - 1];
  191. if (isdigit(static_cast<unsigned char>(c1)) &&
  192. isdigit(static_cast<unsigned char>(c0))) {
  193. // Trim leading '0': "...e+012" -> "...e+12\0"
  194. buf[len - 3] = c1;
  195. buf[len - 2] = c0;
  196. buf[--len] = 0;
  197. }
  198. }
  199. }
  200. S << buf;
  201. return;
  202. }
  203. #endif
  204. }
  205. if (Style == FloatStyle::Percent)
  206. N *= 100.0;
  207. char Buf[32];
  208. format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
  209. S << Buf;
  210. if (Style == FloatStyle::Percent)
  211. S << '%';
  212. }
  213. bool llvm::isPrefixedHexStyle(HexPrintStyle S) {
  214. return (S == HexPrintStyle::PrefixLower || S == HexPrintStyle::PrefixUpper);
  215. }
  216. size_t llvm::getDefaultPrecision(FloatStyle Style) {
  217. switch (Style) {
  218. case FloatStyle::Exponent:
  219. case FloatStyle::ExponentUpper:
  220. return 6; // Number of decimal places.
  221. case FloatStyle::Fixed:
  222. case FloatStyle::Percent:
  223. return 2; // Number of decimal places.
  224. }
  225. llvm_unreachable("Unknown FloatStyle enum");
  226. }