diff options
-rw-r--r-- | llvm/include/llvm/Support/NativeFormatting.h | 31 | ||||
-rw-r--r-- | llvm/lib/Support/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Support/NativeFormatting.cpp | 180 | ||||
-rw-r--r-- | llvm/lib/Support/raw_ostream.cpp | 156 |
4 files changed, 231 insertions, 137 deletions
diff --git a/llvm/include/llvm/Support/NativeFormatting.h b/llvm/include/llvm/Support/NativeFormatting.h new file mode 100644 index 00000000000..6f7e0773eb5 --- /dev/null +++ b/llvm/include/llvm/Support/NativeFormatting.h @@ -0,0 +1,31 @@ +//===- NativeFormatting.h - Low level formatting helpers ---------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_NATIVE_FORMATTING_H +#define LLVM_SUPPORT_NATIVE_FORMATTING_H + +#include "llvm/Support/raw_ostream.h" + +#include <cstdint> + +namespace llvm { +enum class FloatStyle { Exponent, Decimal }; + +void write_ulong(raw_ostream &S, unsigned long N, std::size_t MinWidth); +void write_long(raw_ostream &S, long N, std::size_t MinWidth); +void write_ulonglong(raw_ostream &S, unsigned long long N, + std::size_t MinWidth); +void write_longlong(raw_ostream &S, long long N, std::size_t MinWidth); +void write_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth, + bool Upper, bool Prefix); +void write_double(raw_ostream &S, double D, std::size_t MinWidth, + std::size_t MinDecimals, FloatStyle Style); +} + +#endif
\ No newline at end of file diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index 9f755450535..cf04016da2d 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -70,6 +70,7 @@ add_llvm_library(LLVMSupport MemoryBuffer.cpp MemoryObject.cpp MD5.cpp + NativeFormatting.cpp Options.cpp PluginLoader.cpp PrettyStackTrace.cpp diff --git a/llvm/lib/Support/NativeFormatting.cpp b/llvm/lib/Support/NativeFormatting.cpp new file mode 100644 index 00000000000..84f6c390b02 --- /dev/null +++ b/llvm/lib/Support/NativeFormatting.cpp @@ -0,0 +1,180 @@ +//===- NativeFormatting.cpp - Low level formatting helpers -------*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Support/NativeFormatting.h" + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/Format.h" + +using namespace llvm; + +template<typename T, std::size_t N> +static int format_to_buffer(T Value, char (&Buffer)[N]) { + char *EndPtr = std::end(Buffer); + char *CurPtr = EndPtr; + + while (Value) { + *--CurPtr = '0' + char(Value % 10); + Value /= 10; + } + return EndPtr - CurPtr; +} + +void llvm::write_ulong(raw_ostream &S, unsigned long N, std::size_t MinWidth) { + // Zero is a special case. + if (N == 0) { + if (MinWidth > 0) + S.indent(MinWidth - 1); + S << '0'; + return; + } + + char NumberBuffer[20]; + int Len = format_to_buffer(N, NumberBuffer); + int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; + if (Pad > 0) + S.indent(Pad); + S.write(std::end(NumberBuffer) - Len, Len); +} + +void llvm::write_long(raw_ostream &S, long N, std::size_t MinWidth) { + if (N >= 0) { + write_ulong(S, static_cast<unsigned long>(N), MinWidth); + return; + } + + unsigned long UN = -(unsigned long)N; + if (MinWidth > 0) + --MinWidth; + + char NumberBuffer[20]; + int Len = format_to_buffer(UN, NumberBuffer); + int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; + if (Pad > 0) + S.indent(Pad); + S.write('-'); + S.write(std::end(NumberBuffer) - Len, Len); +} + +void llvm::write_ulonglong(raw_ostream &S, unsigned long long N, + std::size_t MinWidth) { + // Output using 32-bit div/mod when possible. + if (N == static_cast<unsigned long>(N)) { + write_ulong(S, static_cast<unsigned long>(N), MinWidth); + return; + } + + char NumberBuffer[32]; + int Len = format_to_buffer(N, NumberBuffer); + int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; + if (Pad > 0) + S.indent(Pad); + S.write(std::end(NumberBuffer) - Len, Len); +} + +void llvm::write_longlong(raw_ostream &S, long long N, std::size_t MinWidth) { + if (N >= 0) { + write_ulonglong(S, static_cast<unsigned long long>(N), MinWidth); + return; + } + + // Avoid undefined behavior on INT64_MIN with a cast. + unsigned long long UN = -(unsigned long long)N; + if (MinWidth > 0) + --MinWidth; + + char NumberBuffer[32]; + int Len = format_to_buffer(UN, NumberBuffer); + int Pad = (MinWidth == 0) ? 0 : MinWidth - Len; + if (Pad > 0) + S.indent(Pad); + S.write('-'); + S.write(std::end(NumberBuffer) - Len, Len); +} + +void llvm::write_hex(raw_ostream &S, unsigned long long N, std::size_t MinWidth, + bool Upper, bool Prefix) { + unsigned Nibbles = (64 - countLeadingZeros(N) + 3) / 4; + unsigned PrefixChars = Prefix ? 2 : 0; + unsigned Width = std::max(MinWidth, std::max(1u, Nibbles) + PrefixChars); + + char NumberBuffer[20] = "0x0000000000000000"; + if (!Prefix) + NumberBuffer[1] = '0'; + char *EndPtr = NumberBuffer + Width; + char *CurPtr = EndPtr; + while (N) { + unsigned char x = static_cast<unsigned char>(N) % 16; + *--CurPtr = hexdigit(x, !Upper); + N /= 16; + } + + S.write(NumberBuffer, Width); +} + +void llvm::write_double(raw_ostream &S, double N, std::size_t MinWidth, + std::size_t MinDecimals, FloatStyle Style) { + char Letter = (Style == FloatStyle::Exponent) ? 'e' : 'f'; + SmallString<8> Spec; + llvm::raw_svector_ostream Out(Spec); + Out << '%'; + if (MinWidth > 0) + Out << MinWidth; + if (MinDecimals > 0) + Out << '.' << MinDecimals; + Out << Letter; + + if (Style == FloatStyle::Exponent) { +#ifdef _WIN32 +// On MSVCRT and compatible, output of %e is incompatible to Posix +// by default. Number of exponent digits should be at least 2. "%+03d" +// FIXME: Implement our formatter to here or Support/Format.h! +#if defined(__MINGW32__) + // FIXME: It should be generic to C++11. + if (N == 0.0 && std::signbit(N)) { + S << "-0.000000e+00"; + return; + } +#else + int fpcl = _fpclass(N); + + // negative zero + if (fpcl == _FPCLASS_NZ) { + S << "-0.000000e+00"; + return; + } +#endif + + char buf[16]; + unsigned len; + len = format(Spec.c_str(), N).snprint(buf, sizeof(buf)); + if (len <= sizeof(buf) - 2) { + if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') { + int cs = buf[len - 4]; + if (cs == '+' || cs == '-') { + int c1 = buf[len - 2]; + int c0 = buf[len - 1]; + if (isdigit(static_cast<unsigned char>(c1)) && + isdigit(static_cast<unsigned char>(c0))) { + // Trim leading '0': "...e+012" -> "...e+12\0" + buf[len - 3] = c1; + buf[len - 2] = c0; + buf[--len] = 0; + } + } + } + S << buf; + return; + } +#endif + } + + S << format(Spec.c_str(), N); +} diff --git a/llvm/lib/Support/raw_ostream.cpp b/llvm/lib/Support/raw_ostream.cpp index df4c8dc376b..8101bc1d2f3 100644 --- a/llvm/lib/Support/raw_ostream.cpp +++ b/llvm/lib/Support/raw_ostream.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/FileSystem.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/NativeFormatting.h" #include "llvm/Support/Process.h" #include "llvm/Support/Program.h" #include <algorithm> @@ -28,8 +29,8 @@ #include <cerrno> #include <cstdio> #include <iterator> -#include <system_error> #include <sys/stat.h> +#include <system_error> // <fcntl.h> may provide O_BINARY. #if defined(HAVE_FCNTL_H) @@ -113,73 +114,28 @@ void raw_ostream::SetBufferAndMode(char *BufferStart, size_t Size, } raw_ostream &raw_ostream::operator<<(unsigned long N) { - // Zero is a special case. - if (N == 0) - return *this << '0'; - - char NumberBuffer[20]; - char *EndPtr = NumberBuffer+sizeof(NumberBuffer); - char *CurPtr = EndPtr; - - while (N) { - *--CurPtr = '0' + char(N % 10); - N /= 10; - } - return write(CurPtr, EndPtr-CurPtr); + write_ulong(*this, N, 0); + return *this; } raw_ostream &raw_ostream::operator<<(long N) { - if (N < 0) { - *this << '-'; - // Avoid undefined behavior on LONG_MIN with a cast. - N = -(unsigned long)N; - } - - return this->operator<<(static_cast<unsigned long>(N)); + write_long(*this, N, 0); + return *this; } raw_ostream &raw_ostream::operator<<(unsigned long long N) { - // Output using 32-bit div/mod when possible. - if (N == static_cast<unsigned long>(N)) - return this->operator<<(static_cast<unsigned long>(N)); - - char NumberBuffer[20]; - char *EndPtr = std::end(NumberBuffer); - char *CurPtr = EndPtr; - - while (N) { - *--CurPtr = '0' + char(N % 10); - N /= 10; - } - return write(CurPtr, EndPtr-CurPtr); + write_ulonglong(*this, N, 0); + return *this; } raw_ostream &raw_ostream::operator<<(long long N) { - if (N < 0) { - *this << '-'; - // Avoid undefined behavior on INT64_MIN with a cast. - N = -(unsigned long long)N; - } - - return this->operator<<(static_cast<unsigned long long>(N)); + write_longlong(*this, N, 0); + return *this; } raw_ostream &raw_ostream::write_hex(unsigned long long N) { - // Zero is a special case. - if (N == 0) - return *this << '0'; - - char NumberBuffer[16]; - char *EndPtr = std::end(NumberBuffer); - char *CurPtr = EndPtr; - - while (N) { - unsigned char x = static_cast<unsigned char>(N) % 16; - *--CurPtr = hexdigit(x, /*LowerCase*/true); - N /= 16; - } - - return write(CurPtr, EndPtr-CurPtr); + llvm::write_hex(*this, N, 0, false, false); + return *this; } raw_ostream &raw_ostream::write_escaped(StringRef Str, @@ -223,50 +179,13 @@ raw_ostream &raw_ostream::write_escaped(StringRef Str, } raw_ostream &raw_ostream::operator<<(const void *P) { - *this << '0' << 'x'; - - return write_hex((uintptr_t) P); + llvm::write_hex(*this, (uintptr_t)P, 0, false, true); + return *this; } raw_ostream &raw_ostream::operator<<(double N) { -#ifdef _WIN32 - // On MSVCRT and compatible, output of %e is incompatible to Posix - // by default. Number of exponent digits should be at least 2. "%+03d" - // FIXME: Implement our formatter to here or Support/Format.h! -#if defined(__MINGW32__) - // FIXME: It should be generic to C++11. - if (N == 0.0 && std::signbit(N)) - return *this << "-0.000000e+00"; -#else - int fpcl = _fpclass(N); - - // negative zero - if (fpcl == _FPCLASS_NZ) - return *this << "-0.000000e+00"; -#endif - - char buf[16]; - unsigned len; - len = format("%e", N).snprint(buf, sizeof(buf)); - if (len <= sizeof(buf) - 2) { - if (len >= 5 && buf[len - 5] == 'e' && buf[len - 3] == '0') { - int cs = buf[len - 4]; - if (cs == '+' || cs == '-') { - int c1 = buf[len - 2]; - int c0 = buf[len - 1]; - if (isdigit(static_cast<unsigned char>(c1)) && - isdigit(static_cast<unsigned char>(c0))) { - // Trim leading '0': "...e+012" -> "...e+12\0" - buf[len - 3] = c1; - buf[len - 2] = c0; - buf[--len] = 0; - } - } - } - return this->operator<<(buf); - } -#endif - return this->operator<<(format("%e", N)); + llvm::write_double(*this, N, 0, 0, FloatStyle::Exponent); + return *this; } void raw_ostream::flush_nonempty() { @@ -412,48 +331,11 @@ raw_ostream &raw_ostream::operator<<(const FormattedString &FS) { raw_ostream &raw_ostream::operator<<(const FormattedNumber &FN) { if (FN.Hex) { - unsigned Nibbles = (64 - countLeadingZeros(FN.HexValue)+3)/4; - unsigned PrefixChars = FN.HexPrefix ? 2 : 0; - unsigned Width = std::max(FN.Width, Nibbles + PrefixChars); - - char NumberBuffer[20] = "0x0000000000000000"; - if (!FN.HexPrefix) - NumberBuffer[1] = '0'; - char *EndPtr = NumberBuffer+Width; - char *CurPtr = EndPtr; - unsigned long long N = FN.HexValue; - while (N) { - unsigned char x = static_cast<unsigned char>(N) % 16; - *--CurPtr = hexdigit(x, !FN.Upper); - N /= 16; - } - - return write(NumberBuffer, Width); + llvm::write_hex(*this, FN.HexValue, FN.Width, FN.Upper, FN.HexPrefix); } else { - // Zero is a special case. - if (FN.DecValue == 0) { - this->indent(FN.Width-1); - return *this << '0'; - } - char NumberBuffer[32]; - char *EndPtr = NumberBuffer+sizeof(NumberBuffer); - char *CurPtr = EndPtr; - bool Neg = (FN.DecValue < 0); - uint64_t N = Neg ? -static_cast<uint64_t>(FN.DecValue) : FN.DecValue; - while (N) { - *--CurPtr = '0' + char(N % 10); - N /= 10; - } - int Len = EndPtr - CurPtr; - int Pad = FN.Width - Len; - if (Neg) - --Pad; - if (Pad > 0) - this->indent(Pad); - if (Neg) - *this << '-'; - return write(CurPtr, Len); + llvm::write_longlong(*this, FN.DecValue, FN.Width); } + return *this; } /// indent - Insert 'NumSpaces' spaces. |