blob: 084e6bf598c7a9c8b7754b8964fe521e6fd384ee [file] [log] [blame]
Zachary Turner733be512016-10-11 19:24:45 +00001//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "llvm/Support/NativeFormatting.h"
11
Zachary Turner7cd07452016-10-17 22:49:24 +000012#include "llvm/ADT/ArrayRef.h"
Zachary Turner733be512016-10-11 19:24:45 +000013#include "llvm/ADT/SmallString.h"
14#include "llvm/ADT/StringExtras.h"
15#include "llvm/Support/Format.h"
16
17using namespace llvm;
18
Zachary Turner7cd07452016-10-17 22:49:24 +000019static bool isHexStyle(IntegerStyle S) {
20 switch (S) {
21 case IntegerStyle::HexLowerNoPrefix:
22 case IntegerStyle::HexLowerPrefix:
23 case IntegerStyle::HexUpperNoPrefix:
24 case IntegerStyle::HexUpperPrefix:
25 return true;
26 default:
27 return false;
28 }
29 LLVM_BUILTIN_UNREACHABLE;
30}
31
32static HexStyle intHexStyleToHexStyle(IntegerStyle S) {
33 assert(isHexStyle(S));
34 switch (S) {
35 case IntegerStyle::HexLowerNoPrefix:
36 return HexStyle::Lower;
37 case IntegerStyle::HexLowerPrefix:
38 return HexStyle::PrefixLower;
39 case IntegerStyle::HexUpperNoPrefix:
40 return HexStyle::Upper;
41 case IntegerStyle::HexUpperPrefix:
42 return HexStyle::PrefixUpper;
43 default:
44 break;
45 }
46 LLVM_BUILTIN_UNREACHABLE;
47}
48
49static void writePadding(raw_ostream &S, Optional<int> FieldWidth,
50 size_t Chars) {
51 if (!FieldWidth.hasValue())
52 return;
53
54 int Pad = *FieldWidth - Chars;
55 if (Pad > 0)
56 S.indent(Pad);
57}
58
Zachary Turner733be512016-10-11 19:24:45 +000059template<typename T, std::size_t N>
60static int format_to_buffer(T Value, char (&Buffer)[N]) {
61 char *EndPtr = std::end(Buffer);
62 char *CurPtr = EndPtr;
63
Zachary Turner7cd07452016-10-17 22:49:24 +000064 do {
Zachary Turner733be512016-10-11 19:24:45 +000065 *--CurPtr = '0' + char(Value % 10);
66 Value /= 10;
Zachary Turner7cd07452016-10-17 22:49:24 +000067 } while (Value);
Zachary Turner733be512016-10-11 19:24:45 +000068 return EndPtr - CurPtr;
69}
70
Zachary Turner7cd07452016-10-17 22:49:24 +000071static void repeat_char(raw_ostream &S, char C, size_t Times) {
72 for (size_t I = 0; I < Times; ++I)
73 S << C;
74}
75
76static void writeWithCommas(raw_ostream &S, ArrayRef<char> Buffer) {
77 assert(!Buffer.empty());
78
79 ArrayRef<char> ThisGroup;
80 int InitialDigits = ((Buffer.size() - 1) % 3) + 1;
81 ThisGroup = Buffer.take_front(InitialDigits);
82 S.write(ThisGroup.data(), ThisGroup.size());
83
84 Buffer = Buffer.drop_front(InitialDigits);
85 assert(Buffer.size() % 3 == 0);
86 while (!Buffer.empty()) {
87 S << ',';
88 ThisGroup = Buffer.take_front(3);
89 S.write(ThisGroup.data(), 3);
90 Buffer = Buffer.drop_front(3);
91 }
92}
93
94template <typename T>
95static void write_unsigned_impl(raw_ostream &S, T N, IntegerStyle Style,
96 Optional<size_t> Precision, Optional<int> Width,
97 bool IsNegative) {
98 static_assert(std::is_unsigned<T>::value, "Value is not unsigned!");
99
100 if (Style == IntegerStyle::Exponent) {
101 write_double(S, static_cast<double>(N), FloatStyle::Exponent, Precision,
102 Width);
103 return;
104 } else if (Style == IntegerStyle::ExponentUpper) {
105 write_double(S, static_cast<double>(N), FloatStyle::ExponentUpper,
106 Precision, Width);
107 return;
108 } else if (isHexStyle(Style)) {
109 write_hex(S, N, intHexStyleToHexStyle(Style), Precision, Width);
Zachary Turner733be512016-10-11 19:24:45 +0000110 return;
111 }
112
Zachary Turner7cd07452016-10-17 22:49:24 +0000113 size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
114 char NumberBuffer[128];
115 std::memset(NumberBuffer, '0', sizeof(NumberBuffer));
116
117 size_t Len = 0;
118 Len = format_to_buffer(N, NumberBuffer);
119
120 bool WriteDecimal =
121 ((Style == IntegerStyle::Fixed || Style == IntegerStyle::Percent) &&
122 Prec > 0);
123
124 size_t LeadingZeros = 0;
125 if ((Style == IntegerStyle::Integer || Style == IntegerStyle::Number) &&
126 Prec > 0) {
127 if (Prec > Len)
128 LeadingZeros = Prec - Len;
129 }
130
131 Len += LeadingZeros;
132
133 // One for the decimal sign, one for each point of precision.
134 size_t DecimalChars = WriteDecimal ? 1 + Prec : 0;
135
136 // One character for the negative sign.
137 size_t Neg = (IsNegative) ? 1 : 0;
138
139 // One comma for each group of 3 digits.
140 size_t Commas = (Style != IntegerStyle::Number) ? 0 : (Len - 1) / 3;
141
142 size_t PercentChars = 0;
143 if (Style == IntegerStyle::Percent) {
144 // For all numbers except 0, we append two additional 0s.
145 PercentChars = (N == 0) ? 1 : 3;
146 }
147
148 writePadding(S, Width, Len + DecimalChars + Neg + Commas + PercentChars);
149
150 if (IsNegative)
151 S << '-';
152 if (Style == IntegerStyle::Number) {
153 writeWithCommas(S, ArrayRef<char>(std::end(NumberBuffer) - Len, Len));
154 } else {
155 S.write(std::end(NumberBuffer) - Len, Len);
156 if (Style == IntegerStyle::Percent && N != 0) {
157 // Rather than multiply by 100, write the characters manually, in case the
158 // multiplication would overflow.
159 S << "00";
160 }
161 }
162
163 if (WriteDecimal) {
164 S << '.';
165 repeat_char(S, '0', Prec);
166 }
167 if (Style == IntegerStyle::Percent)
168 S << '%';
Zachary Turner99eef2d2016-10-17 20:57:45 +0000169}
170
Zachary Turner7cd07452016-10-17 22:49:24 +0000171template <typename T>
172static void write_unsigned(raw_ostream &S, T N, IntegerStyle Style,
173 Optional<size_t> Precision, Optional<int> Width,
174 bool IsNegative = false) {
175 // Output using 32-bit div/mod if possible.
176 if (N == static_cast<uint32_t>(N))
177 write_unsigned_impl(S, static_cast<uint32_t>(N), Style, Precision, Width,
178 IsNegative);
179 else
180 write_unsigned_impl(S, N, Style, Precision, Width, IsNegative);
181}
182
183template <typename T>
184static void write_signed(raw_ostream &S, T N, IntegerStyle Style,
185 Optional<size_t> Precision, Optional<int> Width) {
186 static_assert(std::is_signed<T>::value, "Value is not signed!");
187
188 using UnsignedT = typename std::make_unsigned<T>::type;
189
Zachary Turner99eef2d2016-10-17 20:57:45 +0000190 if (N >= 0) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000191 write_unsigned(S, static_cast<UnsignedT>(N), Style, Precision, Width);
Zachary Turner99eef2d2016-10-17 20:57:45 +0000192 return;
193 }
194
Zachary Turner7cd07452016-10-17 22:49:24 +0000195 UnsignedT UN = -(UnsignedT)N;
196 if (isHexStyle(Style)) {
197 static_assert(sizeof(UnsignedT) == sizeof(T),
198 "Types do not have the same size!");
199 std::memcpy(&UN, &N, sizeof(N));
200 write_hex(S, UN, intHexStyleToHexStyle(Style), Precision, Width);
Zachary Turner9d58e362016-10-17 21:25:41 +0000201 return;
202 }
Zachary Turner7cd07452016-10-17 22:49:24 +0000203 write_unsigned(S, UN, Style, Precision, Width, true);
Zachary Turner733be512016-10-11 19:24:45 +0000204}
205
Zachary Turner7cd07452016-10-17 22:49:24 +0000206void llvm::write_integer(raw_ostream &S, unsigned int N, IntegerStyle Style,
207 Optional<size_t> Precision, Optional<int> Width) {
208 write_unsigned(S, N, Style, Precision, Width);
Zachary Turner733be512016-10-11 19:24:45 +0000209}
210
Zachary Turner7cd07452016-10-17 22:49:24 +0000211void llvm::write_integer(raw_ostream &S, int N, IntegerStyle Style,
212 Optional<size_t> Precision, Optional<int> Width) {
213 write_signed(S, N, Style, Precision, Width);
214}
215
216void llvm::write_integer(raw_ostream &S, unsigned long N, IntegerStyle Style,
217 Optional<size_t> Precision, Optional<int> Width) {
218 write_unsigned(S, N, Style, Precision, Width);
219}
220
221void llvm::write_integer(raw_ostream &S, long N, IntegerStyle Style,
222 Optional<size_t> Precision, Optional<int> Width) {
223 write_signed(S, N, Style, Precision, Width);
224}
225
226void llvm::write_integer(raw_ostream &S, unsigned long long N,
227 IntegerStyle Style, Optional<size_t> Precision,
228 Optional<int> Width) {
229 write_unsigned(S, N, Style, Precision, Width);
230}
231
232void llvm::write_integer(raw_ostream &S, long long N, IntegerStyle Style,
233 Optional<size_t> Precision, Optional<int> Width) {
234 write_signed(S, N, Style, Precision, Width);
235}
236
237void llvm::write_hex(raw_ostream &S, uint64_t N, HexStyle Style,
238 Optional<size_t> Precision, Optional<int> Width) {
239 constexpr size_t kMaxWidth = 128u;
240
241 size_t Prec =
242 std::min(kMaxWidth, Precision.getValueOr(getDefaultPrecision(Style)));
243
Zachary Turner733be512016-10-11 19:24:45 +0000244 unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
Zachary Turner7cd07452016-10-17 22:49:24 +0000245 bool Prefix =
246 (Style == HexStyle::PrefixLower || Style == HexStyle::PrefixUpper);
247 bool Upper = (Style == HexStyle::Upper || Style == HexStyle::PrefixUpper);
Zachary Turner733be512016-10-11 19:24:45 +0000248 unsigned PrefixChars = Prefix ? 2 : 0;
Zachary Turner7cd07452016-10-17 22:49:24 +0000249 unsigned NumChars = std::max(static_cast<unsigned>(Prec),
250 std::max(1u, Nibbles) + PrefixChars);
Zachary Turner733be512016-10-11 19:24:45 +0000251
Zachary Turner7cd07452016-10-17 22:49:24 +0000252 char NumberBuffer[kMaxWidth];
253 ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
254 if (Prefix)
255 NumberBuffer[1] = 'x';
256 char *EndPtr = NumberBuffer + NumChars;
Zachary Turner733be512016-10-11 19:24:45 +0000257 char *CurPtr = EndPtr;
258 while (N) {
259 unsigned char x = static_cast<unsigned char>(N) % 16;
260 *--CurPtr = hexdigit(x, !Upper);
261 N /= 16;
262 }
263
Zachary Turner7cd07452016-10-17 22:49:24 +0000264 writePadding(S, Width, NumChars);
265 S.write(NumberBuffer, NumChars);
Zachary Turner733be512016-10-11 19:24:45 +0000266}
267
Zachary Turner7cd07452016-10-17 22:49:24 +0000268void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
269 Optional<size_t> Precision, Optional<int> Width) {
270 size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
271
272 if (std::isnan(N)) {
273 writePadding(S, Width, 3);
274 S << "nan";
275 return;
276 } else if (std::isinf(N)) {
277 writePadding(S, Width, 3);
278 S << "INF";
279 return;
280 }
281
282 char Letter;
283 if (Style == FloatStyle::Exponent)
284 Letter = 'e';
285 else if (Style == FloatStyle::ExponentUpper)
286 Letter = 'E';
287 else
288 Letter = 'f';
289
Zachary Turner733be512016-10-11 19:24:45 +0000290 SmallString<8> Spec;
291 llvm::raw_svector_ostream Out(Spec);
Zachary Turner7cd07452016-10-17 22:49:24 +0000292 Out << "%." << Prec << Letter;
Zachary Turner733be512016-10-11 19:24:45 +0000293
Zachary Turner7cd07452016-10-17 22:49:24 +0000294 if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
Zachary Turner733be512016-10-11 19:24:45 +0000295#ifdef _WIN32
296// On MSVCRT and compatible, output of %e is incompatible to Posix
297// by default. Number of exponent digits should be at least 2. "%+03d"
298// FIXME: Implement our formatter to here or Support/Format.h!
299#if defined(__MINGW32__)
300 // FIXME: It should be generic to C++11.
301 if (N == 0.0 && std::signbit(N)) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000302 const char *NegativeZero = "-0.000000e+00";
303 writePadding(S, Width, strlen(NegativeZero));
304 S << NegativeZero;
Zachary Turner733be512016-10-11 19:24:45 +0000305 return;
306 }
307#else
308 int fpcl = _fpclass(N);
309
310 // negative zero
311 if (fpcl == _FPCLASS_NZ) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000312 const char *NegativeZero = "-0.000000e+00";
313 writePadding(S, Width, strlen(NegativeZero));
314 S << NegativeZero;
Zachary Turner733be512016-10-11 19:24:45 +0000315 return;
316 }
317#endif
318
Zachary Turner7cd07452016-10-17 22:49:24 +0000319 char buf[32];
Zachary Turner733be512016-10-11 19:24:45 +0000320 unsigned len;
321 len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
322 if (len <= sizeof(buf) - 2) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000323 if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
324 buf[len - 3] == '0') {
Zachary Turner733be512016-10-11 19:24:45 +0000325 int cs = buf[len - 4];
326 if (cs == '+' || cs == '-') {
327 int c1 = buf[len - 2];
328 int c0 = buf[len - 1];
329 if (isdigit(static_cast<unsigned char>(c1)) &&
330 isdigit(static_cast<unsigned char>(c0))) {
331 // Trim leading '0': "...e+012" -> "...e+12\0"
332 buf[len - 3] = c1;
333 buf[len - 2] = c0;
334 buf[--len] = 0;
335 }
336 }
337 }
Zachary Turner7cd07452016-10-17 22:49:24 +0000338 writePadding(S, Width, len);
Zachary Turner733be512016-10-11 19:24:45 +0000339 S << buf;
340 return;
341 }
342#endif
343 }
344
Zachary Turner7cd07452016-10-17 22:49:24 +0000345 if (Style == FloatStyle::Percent)
346 N *= 100.0;
347
348 char Buf[32];
349 unsigned Len;
350 Len = format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
351 if (Style == FloatStyle::Percent)
352 ++Len;
353 writePadding(S, Width, Len);
354 S << Buf;
355 if (Style == FloatStyle::Percent)
356 S << '%';
357}
358
359IntegerStyle llvm::hexStyleToIntHexStyle(HexStyle S) {
360 switch (S) {
361 case HexStyle::Upper:
362 return IntegerStyle::HexUpperNoPrefix;
363 case HexStyle::Lower:
364 return IntegerStyle::HexLowerNoPrefix;
365 case HexStyle::PrefixUpper:
366 return IntegerStyle::HexUpperPrefix;
367 case HexStyle::PrefixLower:
368 return IntegerStyle::HexLowerPrefix;
369 }
370 LLVM_BUILTIN_UNREACHABLE;
371}
372
373size_t llvm::getDefaultPrecision(FloatStyle Style) {
374 switch (Style) {
375 case FloatStyle::Exponent:
376 case FloatStyle::ExponentUpper:
377 return 6; // Number of decimal places.
378 case FloatStyle::Fixed:
379 case FloatStyle::Percent:
380 return 2; // Number of decimal places.
381 }
382 LLVM_BUILTIN_UNREACHABLE;
383}
384
385size_t llvm::getDefaultPrecision(IntegerStyle Style) {
386 switch (Style) {
387 case IntegerStyle::Exponent:
388 case IntegerStyle::ExponentUpper:
389 return 6; // Number of decimal places.
390 case IntegerStyle::Number:
391 case IntegerStyle::Integer:
392 return 0; // Minimum number of digits required.
393 case IntegerStyle::Fixed:
394 return 2; // Number of decimal places.
395 case IntegerStyle::Percent:
396 return 0; // Number of decimal places.
397 case IntegerStyle::HexLowerNoPrefix:
398 case IntegerStyle::HexLowerPrefix:
399 case IntegerStyle::HexUpperNoPrefix:
400 case IntegerStyle::HexUpperPrefix:
401 return getDefaultPrecision(intHexStyleToHexStyle(Style));
402 }
403 LLVM_BUILTIN_UNREACHABLE;
404}
405
406size_t llvm::getDefaultPrecision(HexStyle) {
407 // Number of digits in the resulting string.
408 return 0;
Zachary Turner733be512016-10-11 19:24:45 +0000409}