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 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 
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, 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 
244   unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
245   bool Prefix =
246       (Style == HexStyle::PrefixLower || Style == HexStyle::PrefixUpper);
247   bool Upper = (Style == HexStyle::Upper || Style == HexStyle::PrefixUpper);
248   unsigned PrefixChars = Prefix ? 2 : 0;
249   unsigned NumChars = std::max(static_cast<unsigned>(Prec),
250                                std::max(1u, Nibbles) + PrefixChars);
251 
252   char NumberBuffer[kMaxWidth];
253   ::memset(NumberBuffer, '0', llvm::array_lengthof(NumberBuffer));
254   if (Prefix)
255     NumberBuffer[1] = 'x';
256   char *EndPtr = NumberBuffer + NumChars;
257   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 
264   writePadding(S, Width, NumChars);
265   S.write(NumberBuffer, NumChars);
266 }
267 
268 void 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 
290   SmallString<8> Spec;
291   llvm::raw_svector_ostream Out(Spec);
292   Out << "%." << Prec << Letter;
293 
294   if (Style == FloatStyle::Exponent || Style == FloatStyle::ExponentUpper) {
295 #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)) {
302       const char *NegativeZero = "-0.000000e+00";
303       writePadding(S, Width, strlen(NegativeZero));
304       S << NegativeZero;
305       return;
306     }
307 #else
308     int fpcl = _fpclass(N);
309 
310     // negative zero
311     if (fpcl == _FPCLASS_NZ) {
312       const char *NegativeZero = "-0.000000e+00";
313       writePadding(S, Width, strlen(NegativeZero));
314       S << NegativeZero;
315       return;
316     }
317 #endif
318 
319     char buf[32];
320     unsigned len;
321     len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
322     if (len <= sizeof(buf) - 2) {
323       if (len >= 5 && (buf[len - 5] == 'e' || buf[len - 5] == 'E') &&
324           buf[len - 3] == '0') {
325         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       }
338       writePadding(S, Width, len);
339       S << buf;
340       return;
341     }
342 #endif
343   }
344 
345   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 
359 IntegerStyle 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 
373 size_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 
385 size_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 
406 size_t llvm::getDefaultPrecision(HexStyle) {
407   // Number of digits in the resulting string.
408   return 0;
409 }
410