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