Home | History | Annotate | Download | only in Support
      1 //===-- ScopedPrinter.h ---------------------------------------------------===//
      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 #ifndef LLVM_SUPPORT_SCOPEDPRINTER_H
     11 #define LLVM_SUPPORT_SCOPEDPRINTER_H
     12 
     13 #include "llvm/ADT/APSInt.h"
     14 #include "llvm/ADT/ArrayRef.h"
     15 #include "llvm/ADT/SmallVector.h"
     16 #include "llvm/ADT/StringRef.h"
     17 #include "llvm/Support/DataTypes.h"
     18 #include "llvm/Support/Endian.h"
     19 #include "llvm/Support/raw_ostream.h"
     20 #include <algorithm>
     21 
     22 namespace llvm {
     23 
     24 template <typename T> struct EnumEntry {
     25   StringRef Name;
     26   // While Name suffices in most of the cases, in certain cases
     27   // GNU style and LLVM style of ELFDumper do not
     28   // display same string for same enum. The AltName if initialized appropriately
     29   // will hold the string that GNU style emits.
     30   // Example:
     31   // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to
     32   // "Advanced Micro Devices X86-64" on GNU style
     33   StringRef AltName;
     34   T Value;
     35   EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {}
     36   EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {}
     37 };
     38 
     39 struct HexNumber {
     40   // To avoid sign-extension we have to explicitly cast to the appropriate
     41   // unsigned type. The overloads are here so that every type that is implicitly
     42   // convertible to an integer (including enums and endian helpers) can be used
     43   // without requiring type traits or call-site changes.
     44   HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {}
     45   HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {}
     46   HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {}
     47   HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {}
     48   HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {}
     49   HexNumber(signed long long Value)
     50       : Value(static_cast<unsigned long long>(Value)) {}
     51   HexNumber(unsigned char Value) : Value(Value) {}
     52   HexNumber(unsigned short Value) : Value(Value) {}
     53   HexNumber(unsigned int Value) : Value(Value) {}
     54   HexNumber(unsigned long Value) : Value(Value) {}
     55   HexNumber(unsigned long long Value) : Value(Value) {}
     56   uint64_t Value;
     57 };
     58 
     59 raw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value);
     60 const std::string to_hexString(uint64_t Value, bool UpperCase = true);
     61 
     62 template <class T> const std::string to_string(const T &Value) {
     63   std::string number;
     64   llvm::raw_string_ostream stream(number);
     65   stream << Value;
     66   return stream.str();
     67 }
     68 
     69 class ScopedPrinter {
     70 public:
     71   ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {}
     72 
     73   void flush() { OS.flush(); }
     74 
     75   void indent(int Levels = 1) { IndentLevel += Levels; }
     76 
     77   void unindent(int Levels = 1) {
     78     IndentLevel = std::max(0, IndentLevel - Levels);
     79   }
     80 
     81   void resetIndent() { IndentLevel = 0; }
     82 
     83   void setPrefix(StringRef P) { Prefix = P; }
     84 
     85   void printIndent() {
     86     OS << Prefix;
     87     for (int i = 0; i < IndentLevel; ++i)
     88       OS << "  ";
     89   }
     90 
     91   template <typename T> HexNumber hex(T Value) { return HexNumber(Value); }
     92 
     93   template <typename T, typename TEnum>
     94   void printEnum(StringRef Label, T Value,
     95                  ArrayRef<EnumEntry<TEnum>> EnumValues) {
     96     StringRef Name;
     97     bool Found = false;
     98     for (const auto &EnumItem : EnumValues) {
     99       if (EnumItem.Value == Value) {
    100         Name = EnumItem.Name;
    101         Found = true;
    102         break;
    103       }
    104     }
    105 
    106     if (Found) {
    107       startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
    108     } else {
    109       startLine() << Label << ": " << hex(Value) << "\n";
    110     }
    111   }
    112 
    113   template <typename T, typename TFlag>
    114   void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
    115                   TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
    116                   TFlag EnumMask3 = {}) {
    117     typedef EnumEntry<TFlag> FlagEntry;
    118     typedef SmallVector<FlagEntry, 10> FlagVector;
    119     FlagVector SetFlags;
    120 
    121     for (const auto &Flag : Flags) {
    122       if (Flag.Value == 0)
    123         continue;
    124 
    125       TFlag EnumMask{};
    126       if (Flag.Value & EnumMask1)
    127         EnumMask = EnumMask1;
    128       else if (Flag.Value & EnumMask2)
    129         EnumMask = EnumMask2;
    130       else if (Flag.Value & EnumMask3)
    131         EnumMask = EnumMask3;
    132       bool IsEnum = (Flag.Value & EnumMask) != 0;
    133       if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
    134           (IsEnum && (Value & EnumMask) == Flag.Value)) {
    135         SetFlags.push_back(Flag);
    136       }
    137     }
    138 
    139     std::sort(SetFlags.begin(), SetFlags.end(), &flagName<TFlag>);
    140 
    141     startLine() << Label << " [ (" << hex(Value) << ")\n";
    142     for (const auto &Flag : SetFlags) {
    143       startLine() << "  " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
    144     }
    145     startLine() << "]\n";
    146   }
    147 
    148   template <typename T> void printFlags(StringRef Label, T Value) {
    149     startLine() << Label << " [ (" << hex(Value) << ")\n";
    150     uint64_t Flag = 1;
    151     uint64_t Curr = Value;
    152     while (Curr > 0) {
    153       if (Curr & 1)
    154         startLine() << "  " << hex(Flag) << "\n";
    155       Curr >>= 1;
    156       Flag <<= 1;
    157     }
    158     startLine() << "]\n";
    159   }
    160 
    161   void printNumber(StringRef Label, uint64_t Value) {
    162     startLine() << Label << ": " << Value << "\n";
    163   }
    164 
    165   void printNumber(StringRef Label, uint32_t Value) {
    166     startLine() << Label << ": " << Value << "\n";
    167   }
    168 
    169   void printNumber(StringRef Label, uint16_t Value) {
    170     startLine() << Label << ": " << Value << "\n";
    171   }
    172 
    173   void printNumber(StringRef Label, uint8_t Value) {
    174     startLine() << Label << ": " << unsigned(Value) << "\n";
    175   }
    176 
    177   void printNumber(StringRef Label, int64_t Value) {
    178     startLine() << Label << ": " << Value << "\n";
    179   }
    180 
    181   void printNumber(StringRef Label, int32_t Value) {
    182     startLine() << Label << ": " << Value << "\n";
    183   }
    184 
    185   void printNumber(StringRef Label, int16_t Value) {
    186     startLine() << Label << ": " << Value << "\n";
    187   }
    188 
    189   void printNumber(StringRef Label, int8_t Value) {
    190     startLine() << Label << ": " << int(Value) << "\n";
    191   }
    192 
    193   void printNumber(StringRef Label, const APSInt &Value) {
    194     startLine() << Label << ": " << Value << "\n";
    195   }
    196 
    197   void printBoolean(StringRef Label, bool Value) {
    198     startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
    199   }
    200 
    201   template <typename... T> void printVersion(StringRef Label, T... Version) {
    202     startLine() << Label << ": ";
    203     printVersionInternal(Version...);
    204     getOStream() << "\n";
    205   }
    206 
    207   template <typename T> void printList(StringRef Label, const T &List) {
    208     startLine() << Label << ": [";
    209     bool Comma = false;
    210     for (const auto &Item : List) {
    211       if (Comma)
    212         OS << ", ";
    213       OS << Item;
    214       Comma = true;
    215     }
    216     OS << "]\n";
    217   }
    218 
    219   template <typename T, typename U>
    220   void printList(StringRef Label, const T &List, const U &Printer) {
    221     startLine() << Label << ": [";
    222     bool Comma = false;
    223     for (const auto &Item : List) {
    224       if (Comma)
    225         OS << ", ";
    226       Printer(OS, Item);
    227       Comma = true;
    228     }
    229     OS << "]\n";
    230   }
    231 
    232   template <typename T> void printHexList(StringRef Label, const T &List) {
    233     startLine() << Label << ": [";
    234     bool Comma = false;
    235     for (const auto &Item : List) {
    236       if (Comma)
    237         OS << ", ";
    238       OS << hex(Item);
    239       Comma = true;
    240     }
    241     OS << "]\n";
    242   }
    243 
    244   template <typename T> void printHex(StringRef Label, T Value) {
    245     startLine() << Label << ": " << hex(Value) << "\n";
    246   }
    247 
    248   template <typename T> void printHex(StringRef Label, StringRef Str, T Value) {
    249     startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
    250   }
    251 
    252   template <typename T>
    253   void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) {
    254     startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n';
    255   }
    256 
    257   void printString(StringRef Value) { startLine() << Value << "\n"; }
    258 
    259   void printString(StringRef Label, StringRef Value) {
    260     startLine() << Label << ": " << Value << "\n";
    261   }
    262 
    263   void printString(StringRef Label, const std::string &Value) {
    264     startLine() << Label << ": " << Value << "\n";
    265   }
    266 
    267   template <typename T>
    268   void printNumber(StringRef Label, StringRef Str, T Value) {
    269     startLine() << Label << ": " << Str << " (" << Value << ")\n";
    270   }
    271 
    272   void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
    273     printBinaryImpl(Label, Str, Value, false);
    274   }
    275 
    276   void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
    277     auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
    278                           Value.size());
    279     printBinaryImpl(Label, Str, V, false);
    280   }
    281 
    282   void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
    283     printBinaryImpl(Label, StringRef(), Value, false);
    284   }
    285 
    286   void printBinary(StringRef Label, ArrayRef<char> Value) {
    287     auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
    288                           Value.size());
    289     printBinaryImpl(Label, StringRef(), V, false);
    290   }
    291 
    292   void printBinary(StringRef Label, StringRef Value) {
    293     auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
    294                           Value.size());
    295     printBinaryImpl(Label, StringRef(), V, false);
    296   }
    297 
    298   void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
    299                         uint32_t StartOffset) {
    300     printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
    301   }
    302 
    303   void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
    304     printBinaryImpl(Label, StringRef(), Value, true);
    305   }
    306 
    307   void printBinaryBlock(StringRef Label, StringRef Value) {
    308     auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
    309                           Value.size());
    310     printBinaryImpl(Label, StringRef(), V, true);
    311   }
    312 
    313   template <typename T> void printObject(StringRef Label, const T &Value) {
    314     startLine() << Label << ": " << Value << "\n";
    315   }
    316 
    317   raw_ostream &startLine() {
    318     printIndent();
    319     return OS;
    320   }
    321 
    322   raw_ostream &getOStream() { return OS; }
    323 
    324 private:
    325   template <typename T> void printVersionInternal(T Value) {
    326     getOStream() << Value;
    327   }
    328 
    329   template <typename S, typename T, typename... TArgs>
    330   void printVersionInternal(S Value, T Value2, TArgs... Args) {
    331     getOStream() << Value << ".";
    332     printVersionInternal(Value2, Args...);
    333   }
    334 
    335   template <typename T>
    336   static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
    337     return lhs.Name < rhs.Name;
    338   }
    339 
    340   void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
    341                        bool Block, uint32_t StartOffset = 0);
    342 
    343   raw_ostream &OS;
    344   int IndentLevel;
    345   StringRef Prefix;
    346 };
    347 
    348 template <>
    349 inline void
    350 ScopedPrinter::printHex<support::ulittle16_t>(StringRef Label,
    351                                               support::ulittle16_t Value) {
    352   startLine() << Label << ": " << hex(Value) << "\n";
    353 }
    354 
    355 template<char Open, char Close>
    356 struct DelimitedScope {
    357   explicit DelimitedScope(ScopedPrinter &W) : W(W) {
    358     W.startLine() << Open << '\n';
    359     W.indent();
    360   }
    361 
    362   DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) {
    363     W.startLine() << N;
    364     if (!N.empty())
    365       W.getOStream() << ' ';
    366     W.getOStream() << Open << '\n';
    367     W.indent();
    368   }
    369 
    370   ~DelimitedScope() {
    371     W.unindent();
    372     W.startLine() << Close << '\n';
    373   }
    374 
    375   ScopedPrinter &W;
    376 };
    377 
    378 using DictScope = DelimitedScope<'{', '}'>;
    379 using ListScope = DelimitedScope<'[', ']'>;
    380 
    381 } // namespace llvm
    382 
    383 #endif
    384