2016-05-03 02:28:04 +02:00
|
|
|
//===-- ScopedPrinter.h ---------------------------------------------------===//
|
2013-04-03 20:31:38 +02:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
#ifndef LLVM_SUPPORT_SCOPEDPRINTER_H
|
|
|
|
#define LLVM_SUPPORT_SCOPEDPRINTER_H
|
2013-04-03 20:31:38 +02:00
|
|
|
|
2016-01-13 20:32:35 +01:00
|
|
|
#include "llvm/ADT/APSInt.h"
|
2013-04-03 20:31:38 +02:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2014-01-13 09:04:33 +01:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2013-04-03 20:31:38 +02:00
|
|
|
#include "llvm/Support/DataTypes.h"
|
|
|
|
#include "llvm/Support/Endian.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T> struct EnumEntry {
|
2013-04-03 20:31:38 +02:00
|
|
|
StringRef Name;
|
2016-02-10 21:40:55 +01:00
|
|
|
// While Name suffices in most of the cases, in certain cases
|
|
|
|
// GNU style and LLVM style of ELFDumper do not
|
|
|
|
// display same string for same enum. The AltName if initialized appropriately
|
|
|
|
// will hold the string that GNU style emits.
|
|
|
|
// Example:
|
|
|
|
// "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to
|
|
|
|
// "Advanced Micro Devices X86-64" on GNU style
|
|
|
|
StringRef AltName;
|
2013-04-03 20:31:38 +02:00
|
|
|
T Value;
|
2016-02-10 21:40:55 +01:00
|
|
|
EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {}
|
|
|
|
EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {}
|
2013-04-03 20:31:38 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct HexNumber {
|
|
|
|
// To avoid sign-extension we have to explicitly cast to the appropriate
|
|
|
|
// unsigned type. The overloads are here so that every type that is implicitly
|
|
|
|
// convertible to an integer (including enums and endian helpers) can be used
|
|
|
|
// without requiring type traits or call-site changes.
|
2016-05-03 02:28:04 +02:00
|
|
|
HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {}
|
|
|
|
HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {}
|
|
|
|
HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {}
|
|
|
|
HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {}
|
|
|
|
HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {}
|
|
|
|
HexNumber(signed long long Value)
|
|
|
|
: Value(static_cast<unsigned long long>(Value)) {}
|
|
|
|
HexNumber(unsigned char Value) : Value(Value) {}
|
|
|
|
HexNumber(unsigned short Value) : Value(Value) {}
|
|
|
|
HexNumber(unsigned int Value) : Value(Value) {}
|
|
|
|
HexNumber(unsigned long Value) : Value(Value) {}
|
|
|
|
HexNumber(unsigned long long Value) : Value(Value) {}
|
2013-04-03 20:31:38 +02:00
|
|
|
uint64_t Value;
|
|
|
|
};
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value);
|
2016-02-10 21:40:55 +01:00
|
|
|
const std::string to_hexString(uint64_t Value, bool UpperCase = true);
|
2016-03-15 18:25:31 +01:00
|
|
|
|
|
|
|
template <class T> const std::string to_string(const T &Value) {
|
|
|
|
std::string number;
|
|
|
|
llvm::raw_string_ostream stream(number);
|
|
|
|
stream << Value;
|
|
|
|
return stream.str();
|
|
|
|
}
|
2013-04-03 20:31:38 +02:00
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
class ScopedPrinter {
|
2013-04-03 20:31:38 +02:00
|
|
|
public:
|
2016-05-03 02:28:04 +02:00
|
|
|
ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {}
|
2013-04-03 20:31:38 +02:00
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
void flush() { OS.flush(); }
|
2013-04-03 20:31:38 +02:00
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
void indent(int Levels = 1) { IndentLevel += Levels; }
|
2013-04-03 20:31:38 +02:00
|
|
|
|
|
|
|
void unindent(int Levels = 1) {
|
|
|
|
IndentLevel = std::max(0, IndentLevel - Levels);
|
|
|
|
}
|
|
|
|
|
[codeview] Improve readability of type record assembly
Adds the method MCStreamer::EmitBinaryData, which is usually an alias
for EmitBytes. In the MCAsmStreamer case, it is overridden to emit hex
dump output like this:
.byte 0x0e, 0x00, 0x08, 0x10
.byte 0x03, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x10, 0x00, 0x00
Also, when verbose asm comments are enabled, this patch prints the dump
output for each comment before its record, like this:
# ArgList (0x1000) {
# TypeLeafKind: LF_ARGLIST (0x1201)
# NumArgs: 0
# Arguments [
# ]
# }
.byte 0x06, 0x00, 0x01, 0x12
.byte 0x00, 0x00, 0x00, 0x00
This should make debugging easier and testing more convenient.
Reviewers: aaboud
Subscribers: majnemer, zturner, amccarth, aaboud, llvm-commits
Differential Revision: http://reviews.llvm.org/D20711
llvm-svn: 271313
2016-05-31 20:45:36 +02:00
|
|
|
void resetIndent() { IndentLevel = 0; }
|
|
|
|
|
|
|
|
void setPrefix(StringRef P) { Prefix = P; }
|
|
|
|
|
2013-04-03 20:31:38 +02:00
|
|
|
void printIndent() {
|
[codeview] Improve readability of type record assembly
Adds the method MCStreamer::EmitBinaryData, which is usually an alias
for EmitBytes. In the MCAsmStreamer case, it is overridden to emit hex
dump output like this:
.byte 0x0e, 0x00, 0x08, 0x10
.byte 0x03, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x10, 0x00, 0x00
Also, when verbose asm comments are enabled, this patch prints the dump
output for each comment before its record, like this:
# ArgList (0x1000) {
# TypeLeafKind: LF_ARGLIST (0x1201)
# NumArgs: 0
# Arguments [
# ]
# }
.byte 0x06, 0x00, 0x01, 0x12
.byte 0x00, 0x00, 0x00, 0x00
This should make debugging easier and testing more convenient.
Reviewers: aaboud
Subscribers: majnemer, zturner, amccarth, aaboud, llvm-commits
Differential Revision: http://reviews.llvm.org/D20711
llvm-svn: 271313
2016-05-31 20:45:36 +02:00
|
|
|
OS << Prefix;
|
2013-04-03 20:31:38 +02:00
|
|
|
for (int i = 0; i < IndentLevel; ++i)
|
|
|
|
OS << " ";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T> HexNumber hex(T Value) { return HexNumber(Value); }
|
2013-04-03 20:31:38 +02:00
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T, typename TEnum>
|
2013-04-03 20:31:38 +02:00
|
|
|
void printEnum(StringRef Label, T Value,
|
2016-05-03 02:28:04 +02:00
|
|
|
ArrayRef<EnumEntry<TEnum>> EnumValues) {
|
2013-04-03 20:31:38 +02:00
|
|
|
StringRef Name;
|
|
|
|
bool Found = false;
|
2014-04-20 23:05:30 +02:00
|
|
|
for (const auto &EnumItem : EnumValues) {
|
|
|
|
if (EnumItem.Value == Value) {
|
|
|
|
Name = EnumItem.Name;
|
2013-04-03 20:31:38 +02:00
|
|
|
Found = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Found) {
|
|
|
|
startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
|
|
|
|
} else {
|
|
|
|
startLine() << Label << ": " << hex(Value) << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-05-07 16:04:44 +02:00
|
|
|
template <typename T, typename TFlag>
|
|
|
|
void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
|
2015-05-08 09:04:59 +02:00
|
|
|
TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
|
|
|
|
TFlag EnumMask3 = {}) {
|
2013-04-03 20:31:38 +02:00
|
|
|
typedef EnumEntry<TFlag> FlagEntry;
|
|
|
|
typedef SmallVector<FlagEntry, 10> FlagVector;
|
|
|
|
FlagVector SetFlags;
|
|
|
|
|
2014-04-20 23:05:30 +02:00
|
|
|
for (const auto &Flag : Flags) {
|
|
|
|
if (Flag.Value == 0)
|
2013-04-03 20:31:38 +02:00
|
|
|
continue;
|
|
|
|
|
2015-05-07 16:04:44 +02:00
|
|
|
TFlag EnumMask{};
|
|
|
|
if (Flag.Value & EnumMask1)
|
|
|
|
EnumMask = EnumMask1;
|
|
|
|
else if (Flag.Value & EnumMask2)
|
|
|
|
EnumMask = EnumMask2;
|
2015-05-08 09:04:59 +02:00
|
|
|
else if (Flag.Value & EnumMask3)
|
|
|
|
EnumMask = EnumMask3;
|
2014-04-20 23:05:30 +02:00
|
|
|
bool IsEnum = (Flag.Value & EnumMask) != 0;
|
|
|
|
if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
|
2016-05-03 02:28:04 +02:00
|
|
|
(IsEnum && (Value & EnumMask) == Flag.Value)) {
|
2014-04-20 23:05:30 +02:00
|
|
|
SetFlags.push_back(Flag);
|
2013-04-03 20:31:38 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
|
|
|
|
|
|
|
|
startLine() << Label << " [ (" << hex(Value) << ")\n";
|
2014-04-20 23:05:30 +02:00
|
|
|
for (const auto &Flag : SetFlags) {
|
|
|
|
startLine() << " " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
|
2013-04-03 20:31:38 +02:00
|
|
|
}
|
|
|
|
startLine() << "]\n";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T> void printFlags(StringRef Label, T Value) {
|
2013-04-03 20:31:38 +02:00
|
|
|
startLine() << Label << " [ (" << hex(Value) << ")\n";
|
|
|
|
uint64_t Flag = 1;
|
|
|
|
uint64_t Curr = Value;
|
|
|
|
while (Curr > 0) {
|
|
|
|
if (Curr & 1)
|
|
|
|
startLine() << " " << hex(Flag) << "\n";
|
|
|
|
Curr >>= 1;
|
|
|
|
Flag <<= 1;
|
|
|
|
}
|
|
|
|
startLine() << "]\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, uint64_t Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, uint32_t Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, uint16_t Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, uint8_t Value) {
|
|
|
|
startLine() << Label << ": " << unsigned(Value) << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, int64_t Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, int32_t Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, int16_t Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printNumber(StringRef Label, int8_t Value) {
|
|
|
|
startLine() << Label << ": " << int(Value) << "\n";
|
|
|
|
}
|
|
|
|
|
2016-06-08 21:09:22 +02:00
|
|
|
void printNumber(StringRef Label, const APSInt &Value) {
|
2016-01-13 20:32:35 +01:00
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
2014-06-04 17:47:11 +02:00
|
|
|
void printBoolean(StringRef Label, bool Value) {
|
|
|
|
startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
|
|
|
|
}
|
|
|
|
|
2016-05-04 18:09:04 +02:00
|
|
|
template <typename... T> void printVersion(StringRef Label, T... Version) {
|
|
|
|
startLine() << Label << ": ";
|
|
|
|
printVersionInternal(Version...);
|
|
|
|
getOStream() << "\n";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T> void printList(StringRef Label, const T &List) {
|
2014-01-30 05:46:33 +01:00
|
|
|
startLine() << Label << ": [";
|
|
|
|
bool Comma = false;
|
2014-04-20 23:05:30 +02:00
|
|
|
for (const auto &Item : List) {
|
2014-01-30 05:46:33 +01:00
|
|
|
if (Comma)
|
|
|
|
OS << ", ";
|
2014-04-20 23:05:30 +02:00
|
|
|
OS << Item;
|
2014-01-30 05:46:33 +01:00
|
|
|
Comma = true;
|
|
|
|
}
|
|
|
|
OS << "]\n";
|
|
|
|
}
|
|
|
|
|
2016-05-27 05:51:53 +02:00
|
|
|
template <typename T, typename U>
|
|
|
|
void printList(StringRef Label, const T &List, const U &Printer) {
|
|
|
|
startLine() << Label << ": [";
|
|
|
|
bool Comma = false;
|
|
|
|
for (const auto &Item : List) {
|
|
|
|
if (Comma)
|
|
|
|
OS << ", ";
|
|
|
|
Printer(OS, Item);
|
|
|
|
Comma = true;
|
|
|
|
}
|
|
|
|
OS << "]\n";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T> void printHexList(StringRef Label, const T &List) {
|
2015-10-14 14:11:50 +02:00
|
|
|
startLine() << Label << ": [";
|
|
|
|
bool Comma = false;
|
|
|
|
for (const auto &Item : List) {
|
|
|
|
if (Comma)
|
|
|
|
OS << ", ";
|
|
|
|
OS << hex(Item);
|
|
|
|
Comma = true;
|
|
|
|
}
|
|
|
|
OS << "]\n";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T> void printHex(StringRef Label, T Value) {
|
2013-04-03 20:31:38 +02:00
|
|
|
startLine() << Label << ": " << hex(Value) << "\n";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T> void printHex(StringRef Label, StringRef Str, T Value) {
|
2013-04-03 20:31:38 +02:00
|
|
|
startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
|
|
|
|
}
|
|
|
|
|
2016-01-14 18:51:54 +01:00
|
|
|
template <typename T>
|
|
|
|
void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) {
|
|
|
|
startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n';
|
|
|
|
}
|
|
|
|
|
2016-05-04 18:09:04 +02:00
|
|
|
void printString(StringRef Value) { startLine() << Value << "\n"; }
|
|
|
|
|
2013-04-03 20:31:38 +02:00
|
|
|
void printString(StringRef Label, StringRef Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printString(StringRef Label, const std::string &Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T>
|
2013-04-03 20:31:38 +02:00
|
|
|
void printNumber(StringRef Label, StringRef Str, T Value) {
|
|
|
|
startLine() << Label << ": " << Str << " (" << Value << ")\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
|
|
|
|
printBinaryImpl(Label, Str, Value, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
|
2016-05-03 02:28:04 +02:00
|
|
|
auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
2014-08-27 07:25:25 +02:00
|
|
|
Value.size());
|
2013-04-03 20:31:38 +02:00
|
|
|
printBinaryImpl(Label, Str, V, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
|
|
|
|
printBinaryImpl(Label, StringRef(), Value, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printBinary(StringRef Label, ArrayRef<char> Value) {
|
2016-05-03 02:28:04 +02:00
|
|
|
auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
2014-08-27 07:25:25 +02:00
|
|
|
Value.size());
|
2013-04-03 20:31:38 +02:00
|
|
|
printBinaryImpl(Label, StringRef(), V, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void printBinary(StringRef Label, StringRef Value) {
|
2016-05-03 02:28:04 +02:00
|
|
|
auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
2014-08-27 07:25:25 +02:00
|
|
|
Value.size());
|
2013-04-03 20:31:38 +02:00
|
|
|
printBinaryImpl(Label, StringRef(), V, false);
|
|
|
|
}
|
|
|
|
|
2016-05-04 21:39:28 +02:00
|
|
|
void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
|
|
|
|
printBinaryImpl(Label, StringRef(), Value, true);
|
|
|
|
}
|
|
|
|
|
2013-04-03 20:31:38 +02:00
|
|
|
void printBinaryBlock(StringRef Label, StringRef Value) {
|
2016-05-03 02:28:04 +02:00
|
|
|
auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
|
2014-08-27 07:25:25 +02:00
|
|
|
Value.size());
|
2013-04-03 20:31:38 +02:00
|
|
|
printBinaryImpl(Label, StringRef(), V, true);
|
|
|
|
}
|
|
|
|
|
2016-05-04 18:09:04 +02:00
|
|
|
template <typename T> void printObject(StringRef Label, const T &Value) {
|
|
|
|
startLine() << Label << ": " << Value << "\n";
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
raw_ostream &startLine() {
|
2013-04-03 20:31:38 +02:00
|
|
|
printIndent();
|
|
|
|
return OS;
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
raw_ostream &getOStream() { return OS; }
|
2013-04-03 20:31:38 +02:00
|
|
|
|
|
|
|
private:
|
2016-05-04 18:09:04 +02:00
|
|
|
template <typename T> void printVersionInternal(T Value) {
|
|
|
|
getOStream() << Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename S, typename T, typename... TArgs>
|
|
|
|
void printVersionInternal(S Value, T Value2, TArgs... Args) {
|
|
|
|
getOStream() << Value << ".";
|
|
|
|
printVersionInternal(Value2, Args...);
|
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
template <typename T>
|
|
|
|
static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
|
2013-04-03 20:31:38 +02:00
|
|
|
return lhs.Name < rhs.Name;
|
|
|
|
}
|
|
|
|
|
|
|
|
void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
|
|
|
|
bool Block);
|
|
|
|
|
|
|
|
raw_ostream &OS;
|
|
|
|
int IndentLevel;
|
[codeview] Improve readability of type record assembly
Adds the method MCStreamer::EmitBinaryData, which is usually an alias
for EmitBytes. In the MCAsmStreamer case, it is overridden to emit hex
dump output like this:
.byte 0x0e, 0x00, 0x08, 0x10
.byte 0x03, 0x00, 0x00, 0x00
.byte 0x00, 0x00, 0x00, 0x00
.byte 0x00, 0x10, 0x00, 0x00
Also, when verbose asm comments are enabled, this patch prints the dump
output for each comment before its record, like this:
# ArgList (0x1000) {
# TypeLeafKind: LF_ARGLIST (0x1201)
# NumArgs: 0
# Arguments [
# ]
# }
.byte 0x06, 0x00, 0x01, 0x12
.byte 0x00, 0x00, 0x00, 0x00
This should make debugging easier and testing more convenient.
Reviewers: aaboud
Subscribers: majnemer, zturner, amccarth, aaboud, llvm-commits
Differential Revision: http://reviews.llvm.org/D20711
llvm-svn: 271313
2016-05-31 20:45:36 +02:00
|
|
|
StringRef Prefix;
|
2013-04-03 20:31:38 +02:00
|
|
|
};
|
|
|
|
|
2016-01-13 20:32:35 +01:00
|
|
|
template <>
|
2016-01-14 00:44:57 +01:00
|
|
|
inline void
|
2016-05-03 02:28:04 +02:00
|
|
|
ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label,
|
|
|
|
support::ulittle16_t Value) {
|
2016-01-13 20:32:35 +01:00
|
|
|
startLine() << Label << ": " << hex(Value) << "\n";
|
|
|
|
}
|
|
|
|
|
2016-05-04 03:46:59 +02:00
|
|
|
template<char Open, char Close>
|
|
|
|
struct DelimitedScope {
|
2016-05-04 18:09:04 +02:00
|
|
|
explicit DelimitedScope(ScopedPrinter &W) : W(W) {
|
|
|
|
W.startLine() << Open << '\n';
|
|
|
|
W.indent();
|
|
|
|
}
|
|
|
|
|
2016-05-04 03:46:59 +02:00
|
|
|
DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) {
|
|
|
|
W.startLine() << N;
|
|
|
|
if (!N.empty())
|
|
|
|
W.getOStream() << ' ';
|
|
|
|
W.getOStream() << Open << '\n';
|
2013-04-03 20:31:38 +02:00
|
|
|
W.indent();
|
|
|
|
}
|
|
|
|
|
2016-05-04 03:46:59 +02:00
|
|
|
~DelimitedScope() {
|
2013-04-03 20:31:38 +02:00
|
|
|
W.unindent();
|
2016-05-04 03:46:59 +02:00
|
|
|
W.startLine() << Close << '\n';
|
2013-04-03 20:31:38 +02:00
|
|
|
}
|
|
|
|
|
2016-05-03 02:28:04 +02:00
|
|
|
ScopedPrinter &W;
|
2013-04-03 20:31:38 +02:00
|
|
|
};
|
|
|
|
|
2016-05-04 03:46:59 +02:00
|
|
|
using DictScope = DelimitedScope<'{', '}'>;
|
|
|
|
using ListScope = DelimitedScope<'[', ']'>;
|
2013-04-03 20:31:38 +02:00
|
|
|
|
|
|
|
} // namespace llvm
|
|
|
|
|
|
|
|
#endif
|