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