blob: 4bbd8cb9e07e1f3bcef08fc13d3c4364adadb179 [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
Zachary Turner0d31d9c2016-10-17 23:08:47 +000032static HexPrintStyle intHexStyleToHexStyle(IntegerStyle S) {
Zachary Turner7cd07452016-10-17 22:49:24 +000033 assert(isHexStyle(S));
34 switch (S) {
35 case IntegerStyle::HexLowerNoPrefix:
Zachary Turner0d31d9c2016-10-17 23:08:47 +000036 return HexPrintStyle::Lower;
Zachary Turner7cd07452016-10-17 22:49:24 +000037 case IntegerStyle::HexLowerPrefix:
Zachary Turner0d31d9c2016-10-17 23:08:47 +000038 return HexPrintStyle::PrefixLower;
Zachary Turner7cd07452016-10-17 22:49:24 +000039 case IntegerStyle::HexUpperNoPrefix:
Zachary Turner0d31d9c2016-10-17 23:08:47 +000040 return HexPrintStyle::Upper;
Zachary Turner7cd07452016-10-17 22:49:24 +000041 case IntegerStyle::HexUpperPrefix:
Zachary Turner0d31d9c2016-10-17 23:08:47 +000042 return HexPrintStyle::PrefixUpper;
Zachary Turner7cd07452016-10-17 22:49:24 +000043 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
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000237void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
Zachary Turner7cd07452016-10-17 22:49:24 +0000238 Optional<size_t> Precision, Optional<int> Width) {
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000239 const size_t kMaxWidth = 128u;
Zachary Turner7cd07452016-10-17 22:49:24 +0000240
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 Turner0d31d9c2016-10-17 23:08:47 +0000245 bool Prefix = (Style == HexPrintStyle::PrefixLower ||
246 Style == HexPrintStyle::PrefixUpper);
247 bool Upper =
248 (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
Zachary Turner733be512016-10-11 19:24:45 +0000249 unsigned PrefixChars = Prefix ? 2 : 0;
Zachary Turner7cd07452016-10-17 22:49:24 +0000250 unsigned NumChars = std::max(static_cast<unsigned>(Prec),
251 std::max(1u, Nibbles) + PrefixChars);
Zachary Turner733be512016-10-11 19:24:45 +0000252
Zachary Turner7cd07452016-10-17 22:49:24 +0000253 char NumberBuffer[kMaxWidth];
254 ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
255 if (Prefix)
256 NumberBuffer[1] = 'x';
257 char *EndPtr = NumberBuffer + NumChars;
Zachary Turner733be512016-10-11 19:24:45 +0000258 char *CurPtr = EndPtr;
259 while (N) {
260 unsigned char x = static_cast<unsigned char>(N) % 16;
261 *--CurPtr = hexdigit(x, !Upper);
262 N /= 16;
263 }
264
Zachary Turner7cd07452016-10-17 22:49:24 +0000265 writePadding(S, Width, NumChars);
266 S.write(NumberBuffer, NumChars);
Zachary Turner733be512016-10-11 19:24:45 +0000267}
268
Zachary Turner7cd07452016-10-17 22:49:24 +0000269void llvm::write_double(raw_ostream &S, double N, FloatStyle Style,
270 Optional<size_t> Precision, Optional<int> Width) {
271 size_t Prec = Precision.getValueOr(getDefaultPrecision(Style));
272
273 if (std::isnan(N)) {
274 writePadding(S, Width, 3);
275 S << "nan";
276 return;
277 } else if (std::isinf(N)) {
278 writePadding(S, Width, 3);
279 S << "INF";
280 return;
281 }
282
283 char Letter;
284 if (Style == FloatStyle::Exponent)
285 Letter = 'e';
286 else if (Style == FloatStyle::ExponentUpper)
287 Letter = 'E';
288 else
289 Letter = 'f';
290
Zachary Turner733be512016-10-11 19:24:45 +0000291 SmallString<8> Spec;
292 llvm::raw_svector_ostream Out(Spec);
Zachary Turner7cd07452016-10-17 22:49:24 +0000293 Out << "%." << Prec << Letter;
Zachary Turner733be512016-10-11 19:24:45 +0000294
Zachary Turner7cd07452016-10-17 22:49:24 +0000295 if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
Zachary Turner733be512016-10-11 19:24:45 +0000296#ifdef _WIN32
297// On MSVCRT and compatible, output of %e is incompatible to Posix
298// by default. Number of exponent digits should be at least 2. "%+03d"
299// FIXME: Implement our formatter to here or Support/Format.h!
300#if defined(__MINGW32__)
301 // FIXME: It should be generic to C++11.
302 if (N == 0.0 && std::signbit(N)) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000303 const char *NegativeZero = "-0.000000e+00";
304 writePadding(S, Width, strlen(NegativeZero));
305 S << NegativeZero;
Zachary Turner733be512016-10-11 19:24:45 +0000306 return;
307 }
308#else
309 int fpcl = _fpclass(N);
310
311 // negative zero
312 if (fpcl == _FPCLASS_NZ) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000313 const char *NegativeZero = "-0.000000e+00";
314 writePadding(S, Width, strlen(NegativeZero));
315 S << NegativeZero;
Zachary Turner733be512016-10-11 19:24:45 +0000316 return;
317 }
318#endif
319
Zachary Turner7cd07452016-10-17 22:49:24 +0000320 char buf[32];
Zachary Turner733be512016-10-11 19:24:45 +0000321 unsigned len;
322 len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
323 if (len <= sizeof(buf) - 2) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000324 if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
325 buf[len - 3] == '0') {
Zachary Turner733be512016-10-11 19:24:45 +0000326 int cs = buf[len - 4];
327 if (cs == '+' || cs == '-') {
328 int c1 = buf[len - 2];
329 int c0 = buf[len - 1];
330 if (isdigit(static_cast<unsigned char>(c1)) &&
331 isdigit(static_cast<unsigned char>(c0))) {
332 // Trim leading '0': "...e+012" -> "...e+12\0"
333 buf[len - 3] = c1;
334 buf[len - 2] = c0;
335 buf[--len] = 0;
336 }
337 }
338 }
Zachary Turner7cd07452016-10-17 22:49:24 +0000339 writePadding(S, Width, len);
Zachary Turner733be512016-10-11 19:24:45 +0000340 S << buf;
341 return;
342 }
343#endif
344 }
345
Zachary Turner7cd07452016-10-17 22:49:24 +0000346 if (Style == FloatStyle::Percent)
347 N *= 100.0;
348
349 char Buf[32];
350 unsigned Len;
351 Len = format(Spec.c_str(), N).snprint(Buf, sizeof(Buf));
352 if (Style == FloatStyle::Percent)
353 ++Len;
354 writePadding(S, Width, Len);
355 S << Buf;
356 if (Style == FloatStyle::Percent)
357 S << '%';
358}
359
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000360IntegerStyle llvm::hexStyleToIntHexStyle(HexPrintStyle S) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000361 switch (S) {
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000362 case HexPrintStyle::Upper:
Zachary Turner7cd07452016-10-17 22:49:24 +0000363 return IntegerStyle::HexUpperNoPrefix;
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000364 case HexPrintStyle::Lower:
Zachary Turner7cd07452016-10-17 22:49:24 +0000365 return IntegerStyle::HexLowerNoPrefix;
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000366 case HexPrintStyle::PrefixUpper:
Zachary Turner7cd07452016-10-17 22:49:24 +0000367 return IntegerStyle::HexUpperPrefix;
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000368 case HexPrintStyle::PrefixLower:
Zachary Turner7cd07452016-10-17 22:49:24 +0000369 return IntegerStyle::HexLowerPrefix;
370 }
371 LLVM_BUILTIN_UNREACHABLE;
372}
373
374size_t llvm::getDefaultPrecision(FloatStyle Style) {
375 switch (Style) {
376 case FloatStyle::Exponent:
377 case FloatStyle::ExponentUpper:
378 return 6; // Number of decimal places.
379 case FloatStyle::Fixed:
380 case FloatStyle::Percent:
381 return 2; // Number of decimal places.
382 }
383 LLVM_BUILTIN_UNREACHABLE;
384}
385
386size_t llvm::getDefaultPrecision(IntegerStyle Style) {
387 switch (Style) {
388 case IntegerStyle::Exponent:
389 case IntegerStyle::ExponentUpper:
390 return 6; // Number of decimal places.
391 case IntegerStyle::Number:
392 case IntegerStyle::Integer:
393 return 0; // Minimum number of digits required.
394 case IntegerStyle::Fixed:
395 return 2; // Number of decimal places.
396 case IntegerStyle::Percent:
397 return 0; // Number of decimal places.
398 case IntegerStyle::HexLowerNoPrefix:
399 case IntegerStyle::HexLowerPrefix:
400 case IntegerStyle::HexUpperNoPrefix:
401 case IntegerStyle::HexUpperPrefix:
402 return getDefaultPrecision(intHexStyleToHexStyle(Style));
403 }
404 LLVM_BUILTIN_UNREACHABLE;
405}
406
Zachary Turner0d31d9c2016-10-17 23:08:47 +0000407size_t llvm::getDefaultPrecision(HexPrintStyle) {
Zachary Turner7cd07452016-10-17 22:49:24 +0000408 // Number of digits in the resulting string.
409 return 0;
Zachary Turner733be512016-10-11 19:24:45 +0000410}