1 //===- 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 
12 #include "llvm/ADT/ArrayRef.h"
13 #include "llvm/ADT/SmallString.h"
14 #include "llvm/ADT/StringExtras.h"
15 #include "llvm/Support/Format.h"
16 
17 using namespace llvm;
18 
19 static 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 
32 static HexPrintStyle intHexStyleToHexStyle(IntegerStyle S) {
33   assert(isHexStyle(S));
34   switch (S) {
35   case IntegerStyle::HexLowerNoPrefix:
36     return HexPrintStyle::Lower;
37   case IntegerStyle::HexLowerPrefix:
38     return HexPrintStyle::PrefixLower;
39   case IntegerStyle::HexUpperNoPrefix:
40     return HexPrintStyle::Upper;
41   case IntegerStyle::HexUpperPrefix:
42     return HexPrintStyle::PrefixUpper;
43   default:
44     break;
45   }
46   LLVM_BUILTIN_UNREACHABLE;
47 }
48 
49 static 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 
59 template<typename T, std::size_t N>
60 static int format_to_buffer(T Value, char (&Buffer)[N]) {
61   char *EndPtr = std::end(Buffer);
62   char *CurPtr = EndPtr;
63 
64   do {
65     *--CurPtr = '0' + char(Value % 10);
66     Value /= 10;
67   } while (Value);
68   return EndPtr - CurPtr;
69 }
70 
71 static 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 
76 static 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 
94 template <typename T>
95 static 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);
110     return;
111   }
112 
113   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 << '%';
169 }
170 
171 template <typename T>
172 static 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 
183 template <typename T>
184 static 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 
190   if (N >= 0) {
191     write_unsigned(S, static_cast<UnsignedT>(N), Style, Precision, Width);
192     return;
193   }
194 
195   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);
201     return;
202   }
203   write_unsigned(S, UN, Style, Precision, Width, true);
204 }
205 
206 void 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);
209 }
210 
211 void 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 
216 void 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 
221 void 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 
226 void 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 
232 void 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 
237 void llvm::write_hex(raw_ostream &S, uint64_t N, HexPrintStyle Style,
238                      Optional<size_t> Precision, Optional<int> Width) {
239   const size_t kMaxWidth = 128u;
240 
241   size_t Prec =
242       std::min(kMaxWidth, Precision.getValueOr(getDefaultPrecision(Style)));
243 
244   unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
245   bool Prefix = (Style == HexPrintStyle::PrefixLower ||
246                  Style == HexPrintStyle::PrefixUpper);
247   bool Upper =
248       (Style == HexPrintStyle::Upper || Style == HexPrintStyle::PrefixUpper);
249   unsigned PrefixChars = Prefix ? 2 : 0;
250   unsigned NumChars = std::max(static_cast<unsigned>(Prec),
251                                std::max(1u, Nibbles) + PrefixChars);
252 
253   char NumberBuffer[kMaxWidth];
254   ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
255   if (Prefix)
256     NumberBuffer[1] = 'x';
257   char *EndPtr = NumberBuffer + NumChars;
258   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 
265   writePadding(S, Width, NumChars);
266   S.write(NumberBuffer, NumChars);
267 }
268 
269 void 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 
291   SmallString<8> Spec;
292   llvm::raw_svector_ostream Out(Spec);
293   Out << "%." << Prec << Letter;
294 
295   if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
296 #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)) {
303       const char *NegativeZero = "-0.000000e+00";
304       writePadding(S, Width, strlen(NegativeZero));
305       S << NegativeZero;
306       return;
307     }
308 #else
309     int fpcl = _fpclass(N);
310 
311     // negative zero
312     if (fpcl == _FPCLASS_NZ) {
313       const char *NegativeZero = "-0.000000e+00";
314       writePadding(S, Width, strlen(NegativeZero));
315       S << NegativeZero;
316       return;
317     }
318 #endif
319 
320     char buf[32];
321     unsigned len;
322     len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
323     if (len <= sizeof(buf) - 2) {
324       if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
325           buf[len - 3] == '0') {
326         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       }
339       writePadding(S, Width, len);
340       S << buf;
341       return;
342     }
343 #endif
344   }
345 
346   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 
360 IntegerStyle llvm::hexStyleToIntHexStyle(HexPrintStyle S) {
361   switch (S) {
362   case HexPrintStyle::Upper:
363     return IntegerStyle::HexUpperNoPrefix;
364   case HexPrintStyle::Lower:
365     return IntegerStyle::HexLowerNoPrefix;
366   case HexPrintStyle::PrefixUpper:
367     return IntegerStyle::HexUpperPrefix;
368   case HexPrintStyle::PrefixLower:
369     return IntegerStyle::HexLowerPrefix;
370   }
371   LLVM_BUILTIN_UNREACHABLE;
372 }
373 
374 size_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 
386 size_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 
407 size_t llvm::getDefaultPrecision(HexPrintStyle) {
408   // Number of digits in the resulting string.
409   return 0;
410 }
411