blob: 9989488ddcc44137fa24f367cc4eac71238dbf9e [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
12#include "llvm/ADT/SmallString.h"
13#include "llvm/ADT/StringExtras.h"
14#include "llvm/Support/Format.h"
15
16using namespace llvm;
17
18template<typename T, std::size_t N>
19static int format_to_buffer(T Value, char (&Buffer)[N]) {
20 char *EndPtr = std::end(Buffer);
21 char *CurPtr = EndPtr;
22
Renato Golin9ce50742016-10-18 09:30:18 +000023 while (Value) {
Zachary Turner733be512016-10-11 19:24:45 +000024 *--CurPtr = '0' + char(Value % 10);
25 Value /= 10;
Renato Golin9ce50742016-10-18 09:30:18 +000026 }
Zachary Turner733be512016-10-11 19:24:45 +000027 return EndPtr - CurPtr;
28}
29
Renato Golin9ce50742016-10-18 09:30:18 +000030void llvm::write_ulong(raw_ostream &S, unsigned long N, std::size_t MinWidth) {
31 // Zero is a special case.
32 if (N == 0) {
33 if (MinWidth > 0)
34 S.indent(MinWidth - 1);
35 S << '0';
Zachary Turner733be512016-10-11 19:24:45 +000036 return;
37 }
38
Renato Golin9ce50742016-10-18 09:30:18 +000039 char NumberBuffer[20];
40 int Len = format_to_buffer(N, NumberBuffer);
41 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
42 if (Pad > 0)
43 S.indent(Pad);
44 S.write(std::end(NumberBuffer) - Len, Len);
Zachary Turner99eef2d2016-10-17 20:57:45 +000045}
46
Renato Golin9ce50742016-10-18 09:30:18 +000047void llvm::write_long(raw_ostream &S, long N, std::size_t MinWidth) {
Zachary Turner99eef2d2016-10-17 20:57:45 +000048 if (N >= 0) {
Renato Golin9ce50742016-10-18 09:30:18 +000049 write_ulong(S, static_cast<unsigned long>(N), MinWidth);
Zachary Turner99eef2d2016-10-17 20:57:45 +000050 return;
51 }
52
Renato Golin9ce50742016-10-18 09:30:18 +000053 unsigned long UN = -(unsigned long)N;
54 if (MinWidth > 0)
55 --MinWidth;
56
57 char NumberBuffer[20];
58 int Len = format_to_buffer(UN, NumberBuffer);
59 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
60 if (Pad > 0)
61 S.indent(Pad);
62 S.write('-');
63 S.write(std::end(NumberBuffer) - Len, Len);
64}
65
66void llvm::write_ulonglong(raw_ostream &S, unsigned long long N,
67 std::size_t MinWidth) {
68 // Output using 32-bit div/mod when possible.
69 if (N == static_cast<unsigned long>(N)) {
70 write_ulong(S, static_cast<unsigned long>(N), MinWidth);
Zachary Turner9d58e362016-10-17 21:25:41 +000071 return;
72 }
Renato Golin9ce50742016-10-18 09:30:18 +000073
74 char NumberBuffer[32];
75 int Len = format_to_buffer(N, NumberBuffer);
76 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
77 if (Pad > 0)
78 S.indent(Pad);
79 S.write(std::end(NumberBuffer) - Len, Len);
Zachary Turner733be512016-10-11 19:24:45 +000080}
81
Renato Golin9ce50742016-10-18 09:30:18 +000082void llvm::write_longlong(raw_ostream &S, long long N, std::size_t MinWidth) {
83 if (N >= 0) {
84 write_ulonglong(S, static_cast<unsigned long long>(N), MinWidth);
85 return;
86 }
87
88 // Avoid undefined behavior on INT64_MIN with a cast.
89 unsigned long long UN = -(unsigned long long)N;
90 if (MinWidth > 0)
91 --MinWidth;
92
93 char NumberBuffer[32];
94 int Len = format_to_buffer(UN, NumberBuffer);
95 int Pad = (MinWidth == 0) ? 0 : MinWidth - Len;
96 if (Pad > 0)
97 S.indent(Pad);
98 S.write('-');
99 S.write(std::end(NumberBuffer) - Len, Len);
Zachary Turner733be512016-10-11 19:24:45 +0000100}
101
Renato Golin9ce50742016-10-18 09:30:18 +0000102void llvm::write_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth,
103 bool Upper, bool Prefix) {
Zachary Turner733be512016-10-11 19:24:45 +0000104 unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4;
105 unsigned PrefixChars = Prefix ? 2 : 0;
Renato Golin9ce50742016-10-18 09:30:18 +0000106 unsigned Width = std::max(static_cast<unsigned>(MinWidth),
107 std::max(1u, Nibbles) + PrefixChars);
Zachary Turner733be512016-10-11 19:24:45 +0000108
Renato Golin9ce50742016-10-18 09:30:18 +0000109 char NumberBuffer[20] = "0x0000000000000000";
110 if (!Prefix)
111 NumberBuffer[1] = '0';
112 char *EndPtr = NumberBuffer + Width;
Zachary Turner733be512016-10-11 19:24:45 +0000113 char *CurPtr = EndPtr;
114 while (N) {
115 unsigned char x = static_cast<unsigned char>(N) % 16;
116 *--CurPtr = hexdigit(x, !Upper);
117 N /= 16;
118 }
119
Renato Golin9ce50742016-10-18 09:30:18 +0000120 S.write(NumberBuffer, Width);
Zachary Turner733be512016-10-11 19:24:45 +0000121}
122
Renato Golin9ce50742016-10-18 09:30:18 +0000123void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth,
124 std::size_t MinDecimals, FloatStyle Style) {
125 char Letter = (Style == FloatStyle::Exponent) ? 'e' : 'f';
Zachary Turner733be512016-10-11 19:24:45 +0000126 SmallString<8> Spec;
127 llvm::raw_svector_ostream Out(Spec);
Renato Golin9ce50742016-10-18 09:30:18 +0000128 Out << '%';
129 if (MinWidth > 0)
130 Out << MinWidth;
131 if (MinDecimals > 0)
132 Out << '.' << MinDecimals;
133 Out << Letter;
Zachary Turner733be512016-10-11 19:24:45 +0000134
Renato Golin9ce50742016-10-18 09:30:18 +0000135 if (Style == FloatStyle::Exponent) {
Zachary Turner733be512016-10-11 19:24:45 +0000136#ifdef _WIN32
137// On MSVCRT and compatible, output of %e is incompatible to Posix
138// by default. Number of exponent digits should be at least 2. "%+03d"
139// FIXME: Implement our formatter to here or Support/Format.h!
140#if defined(__MINGW32__)
141 // FIXME: It should be generic to C++11.
142 if (N == 0.0 && std::signbit(N)) {
Renato Golin9ce50742016-10-18 09:30:18 +0000143 S << "-0.000000e+00";
Zachary Turner733be512016-10-11 19:24:45 +0000144 return;
145 }
146#else
147 int fpcl = _fpclass(N);
148
149 // negative zero
150 if (fpcl == _FPCLASS_NZ) {
Renato Golin9ce50742016-10-18 09:30:18 +0000151 S << "-0.000000e+00";
Zachary Turner733be512016-10-11 19:24:45 +0000152 return;
153 }
154#endif
155
Renato Golin9ce50742016-10-18 09:30:18 +0000156 char buf[16];
Zachary Turner733be512016-10-11 19:24:45 +0000157 unsigned len;
158 len = format(Spec.c_str(), N).snprint(buf, sizeof(buf));
159 if (len <= sizeof(buf) - 2) {
Renato Golin9ce50742016-10-18 09:30:18 +0000160 if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') {
Zachary Turner733be512016-10-11 19:24:45 +0000161 int cs = buf[len - 4];
162 if (cs == '+' || cs == '-') {
163 int c1 = buf[len - 2];
164 int c0 = buf[len - 1];
165 if (isdigit(static_cast<unsigned char>(c1)) &&
166 isdigit(static_cast<unsigned char>(c0))) {
167 // Trim leading '0': "...e+012" -> "...e+12\0"
168 buf[len - 3] = c1;
169 buf[len - 2] = c0;
170 buf[--len] = 0;
171 }
172 }
173 }
174 S << buf;
175 return;
176 }
177#endif
178 }
179
Renato Golin9ce50742016-10-18 09:30:18 +0000180 S << format(Spec.c_str(), N);
Zachary Turner733be512016-10-11 19:24:45 +0000181}