1353358Sdim//===-- ScopedPrinter.h ----------------------------------------*- C++ -*--===//
2303231Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6303231Sdim//
7303231Sdim//===----------------------------------------------------------------------===//
8303231Sdim
9303231Sdim#ifndef LLVM_SUPPORT_SCOPEDPRINTER_H
10303231Sdim#define LLVM_SUPPORT_SCOPEDPRINTER_H
11303231Sdim
12303231Sdim#include "llvm/ADT/APSInt.h"
13303231Sdim#include "llvm/ADT/ArrayRef.h"
14303231Sdim#include "llvm/ADT/SmallVector.h"
15303231Sdim#include "llvm/ADT/StringRef.h"
16303231Sdim#include "llvm/Support/DataTypes.h"
17303231Sdim#include "llvm/Support/Endian.h"
18303231Sdim#include "llvm/Support/raw_ostream.h"
19303231Sdim#include <algorithm>
20303231Sdim
21303231Sdimnamespace llvm {
22303231Sdim
23303231Sdimtemplate <typename T> struct EnumEntry {
24303231Sdim  StringRef Name;
25303231Sdim  // While Name suffices in most of the cases, in certain cases
26303231Sdim  // GNU style and LLVM style of ELFDumper do not
27303231Sdim  // display same string for same enum. The AltName if initialized appropriately
28303231Sdim  // will hold the string that GNU style emits.
29303231Sdim  // Example:
30303231Sdim  // "EM_X86_64" string on LLVM style for Elf_Ehdr->e_machine corresponds to
31303231Sdim  // "Advanced Micro Devices X86-64" on GNU style
32303231Sdim  StringRef AltName;
33303231Sdim  T Value;
34303231Sdim  EnumEntry(StringRef N, StringRef A, T V) : Name(N), AltName(A), Value(V) {}
35303231Sdim  EnumEntry(StringRef N, T V) : Name(N), AltName(N), Value(V) {}
36303231Sdim};
37303231Sdim
38303231Sdimstruct HexNumber {
39303231Sdim  // To avoid sign-extension we have to explicitly cast to the appropriate
40303231Sdim  // unsigned type. The overloads are here so that every type that is implicitly
41303231Sdim  // convertible to an integer (including enums and endian helpers) can be used
42303231Sdim  // without requiring type traits or call-site changes.
43303231Sdim  HexNumber(char Value) : Value(static_cast<unsigned char>(Value)) {}
44303231Sdim  HexNumber(signed char Value) : Value(static_cast<unsigned char>(Value)) {}
45303231Sdim  HexNumber(signed short Value) : Value(static_cast<unsigned short>(Value)) {}
46303231Sdim  HexNumber(signed int Value) : Value(static_cast<unsigned int>(Value)) {}
47303231Sdim  HexNumber(signed long Value) : Value(static_cast<unsigned long>(Value)) {}
48303231Sdim  HexNumber(signed long long Value)
49303231Sdim      : Value(static_cast<unsigned long long>(Value)) {}
50303231Sdim  HexNumber(unsigned char Value) : Value(Value) {}
51303231Sdim  HexNumber(unsigned short Value) : Value(Value) {}
52303231Sdim  HexNumber(unsigned int Value) : Value(Value) {}
53303231Sdim  HexNumber(unsigned long Value) : Value(Value) {}
54303231Sdim  HexNumber(unsigned long long Value) : Value(Value) {}
55303231Sdim  uint64_t Value;
56303231Sdim};
57303231Sdim
58303231Sdimraw_ostream &operator<<(raw_ostream &OS, const HexNumber &Value);
59303231Sdimconst std::string to_hexString(uint64_t Value, bool UpperCase = true);
60303231Sdim
61303231Sdimtemplate <class T> const std::string to_string(const T &Value) {
62303231Sdim  std::string number;
63303231Sdim  llvm::raw_string_ostream stream(number);
64303231Sdim  stream << Value;
65303231Sdim  return stream.str();
66303231Sdim}
67303231Sdim
68303231Sdimclass ScopedPrinter {
69303231Sdimpublic:
70303231Sdim  ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {}
71303231Sdim
72303231Sdim  void flush() { OS.flush(); }
73303231Sdim
74303231Sdim  void indent(int Levels = 1) { IndentLevel += Levels; }
75303231Sdim
76303231Sdim  void unindent(int Levels = 1) {
77303231Sdim    IndentLevel = std::max(0, IndentLevel - Levels);
78303231Sdim  }
79303231Sdim
80303231Sdim  void resetIndent() { IndentLevel = 0; }
81303231Sdim
82341825Sdim  int getIndentLevel() { return IndentLevel; }
83341825Sdim
84303231Sdim  void setPrefix(StringRef P) { Prefix = P; }
85303231Sdim
86303231Sdim  void printIndent() {
87303231Sdim    OS << Prefix;
88303231Sdim    for (int i = 0; i < IndentLevel; ++i)
89303231Sdim      OS << "  ";
90303231Sdim  }
91303231Sdim
92303231Sdim  template <typename T> HexNumber hex(T Value) { return HexNumber(Value); }
93303231Sdim
94303231Sdim  template <typename T, typename TEnum>
95303231Sdim  void printEnum(StringRef Label, T Value,
96303231Sdim                 ArrayRef<EnumEntry<TEnum>> EnumValues) {
97303231Sdim    StringRef Name;
98303231Sdim    bool Found = false;
99303231Sdim    for (const auto &EnumItem : EnumValues) {
100303231Sdim      if (EnumItem.Value == Value) {
101303231Sdim        Name = EnumItem.Name;
102303231Sdim        Found = true;
103303231Sdim        break;
104303231Sdim      }
105303231Sdim    }
106303231Sdim
107303231Sdim    if (Found) {
108303231Sdim      startLine() << Label << ": " << Name << " (" << hex(Value) << ")\n";
109303231Sdim    } else {
110303231Sdim      startLine() << Label << ": " << hex(Value) << "\n";
111303231Sdim    }
112303231Sdim  }
113303231Sdim
114303231Sdim  template <typename T, typename TFlag>
115303231Sdim  void printFlags(StringRef Label, T Value, ArrayRef<EnumEntry<TFlag>> Flags,
116303231Sdim                  TFlag EnumMask1 = {}, TFlag EnumMask2 = {},
117303231Sdim                  TFlag EnumMask3 = {}) {
118303231Sdim    typedef EnumEntry<TFlag> FlagEntry;
119303231Sdim    typedef SmallVector<FlagEntry, 10> FlagVector;
120303231Sdim    FlagVector SetFlags;
121303231Sdim
122303231Sdim    for (const auto &Flag : Flags) {
123303231Sdim      if (Flag.Value == 0)
124303231Sdim        continue;
125303231Sdim
126303231Sdim      TFlag EnumMask{};
127303231Sdim      if (Flag.Value & EnumMask1)
128303231Sdim        EnumMask = EnumMask1;
129303231Sdim      else if (Flag.Value & EnumMask2)
130303231Sdim        EnumMask = EnumMask2;
131303231Sdim      else if (Flag.Value & EnumMask3)
132303231Sdim        EnumMask = EnumMask3;
133303231Sdim      bool IsEnum = (Flag.Value & EnumMask) != 0;
134303231Sdim      if ((!IsEnum && (Value & Flag.Value) == Flag.Value) ||
135303231Sdim          (IsEnum && (Value & EnumMask) == Flag.Value)) {
136303231Sdim        SetFlags.push_back(Flag);
137303231Sdim      }
138303231Sdim    }
139303231Sdim
140344779Sdim    llvm::sort(SetFlags, &flagName<TFlag>);
141303231Sdim
142303231Sdim    startLine() << Label << " [ (" << hex(Value) << ")\n";
143303231Sdim    for (const auto &Flag : SetFlags) {
144303231Sdim      startLine() << "  " << Flag.Name << " (" << hex(Flag.Value) << ")\n";
145303231Sdim    }
146303231Sdim    startLine() << "]\n";
147303231Sdim  }
148303231Sdim
149303231Sdim  template <typename T> void printFlags(StringRef Label, T Value) {
150303231Sdim    startLine() << Label << " [ (" << hex(Value) << ")\n";
151303231Sdim    uint64_t Flag = 1;
152303231Sdim    uint64_t Curr = Value;
153303231Sdim    while (Curr > 0) {
154303231Sdim      if (Curr & 1)
155303231Sdim        startLine() << "  " << hex(Flag) << "\n";
156303231Sdim      Curr >>= 1;
157303231Sdim      Flag <<= 1;
158303231Sdim    }
159303231Sdim    startLine() << "]\n";
160303231Sdim  }
161303231Sdim
162303231Sdim  void printNumber(StringRef Label, uint64_t Value) {
163303231Sdim    startLine() << Label << ": " << Value << "\n";
164303231Sdim  }
165303231Sdim
166303231Sdim  void printNumber(StringRef Label, uint32_t Value) {
167303231Sdim    startLine() << Label << ": " << Value << "\n";
168303231Sdim  }
169303231Sdim
170303231Sdim  void printNumber(StringRef Label, uint16_t Value) {
171303231Sdim    startLine() << Label << ": " << Value << "\n";
172303231Sdim  }
173303231Sdim
174303231Sdim  void printNumber(StringRef Label, uint8_t Value) {
175303231Sdim    startLine() << Label << ": " << unsigned(Value) << "\n";
176303231Sdim  }
177303231Sdim
178303231Sdim  void printNumber(StringRef Label, int64_t Value) {
179303231Sdim    startLine() << Label << ": " << Value << "\n";
180303231Sdim  }
181303231Sdim
182303231Sdim  void printNumber(StringRef Label, int32_t Value) {
183303231Sdim    startLine() << Label << ": " << Value << "\n";
184303231Sdim  }
185303231Sdim
186303231Sdim  void printNumber(StringRef Label, int16_t Value) {
187303231Sdim    startLine() << Label << ": " << Value << "\n";
188303231Sdim  }
189303231Sdim
190303231Sdim  void printNumber(StringRef Label, int8_t Value) {
191303231Sdim    startLine() << Label << ": " << int(Value) << "\n";
192303231Sdim  }
193303231Sdim
194303231Sdim  void printNumber(StringRef Label, const APSInt &Value) {
195303231Sdim    startLine() << Label << ": " << Value << "\n";
196303231Sdim  }
197303231Sdim
198303231Sdim  void printBoolean(StringRef Label, bool Value) {
199303231Sdim    startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
200303231Sdim  }
201303231Sdim
202303231Sdim  template <typename... T> void printVersion(StringRef Label, T... Version) {
203303231Sdim    startLine() << Label << ": ";
204303231Sdim    printVersionInternal(Version...);
205303231Sdim    getOStream() << "\n";
206303231Sdim  }
207303231Sdim
208303231Sdim  template <typename T> void printList(StringRef Label, const T &List) {
209303231Sdim    startLine() << Label << ": [";
210303231Sdim    bool Comma = false;
211303231Sdim    for (const auto &Item : List) {
212303231Sdim      if (Comma)
213303231Sdim        OS << ", ";
214303231Sdim      OS << Item;
215303231Sdim      Comma = true;
216303231Sdim    }
217303231Sdim    OS << "]\n";
218303231Sdim  }
219303231Sdim
220303231Sdim  template <typename T, typename U>
221303231Sdim  void printList(StringRef Label, const T &List, const U &Printer) {
222303231Sdim    startLine() << Label << ": [";
223303231Sdim    bool Comma = false;
224303231Sdim    for (const auto &Item : List) {
225303231Sdim      if (Comma)
226303231Sdim        OS << ", ";
227303231Sdim      Printer(OS, Item);
228303231Sdim      Comma = true;
229303231Sdim    }
230303231Sdim    OS << "]\n";
231303231Sdim  }
232303231Sdim
233303231Sdim  template <typename T> void printHexList(StringRef Label, const T &List) {
234303231Sdim    startLine() << Label << ": [";
235303231Sdim    bool Comma = false;
236303231Sdim    for (const auto &Item : List) {
237303231Sdim      if (Comma)
238303231Sdim        OS << ", ";
239303231Sdim      OS << hex(Item);
240303231Sdim      Comma = true;
241303231Sdim    }
242303231Sdim    OS << "]\n";
243303231Sdim  }
244303231Sdim
245303231Sdim  template <typename T> void printHex(StringRef Label, T Value) {
246303231Sdim    startLine() << Label << ": " << hex(Value) << "\n";
247303231Sdim  }
248303231Sdim
249303231Sdim  template <typename T> void printHex(StringRef Label, StringRef Str, T Value) {
250303231Sdim    startLine() << Label << ": " << Str << " (" << hex(Value) << ")\n";
251303231Sdim  }
252303231Sdim
253303231Sdim  template <typename T>
254303231Sdim  void printSymbolOffset(StringRef Label, StringRef Symbol, T Value) {
255303231Sdim    startLine() << Label << ": " << Symbol << '+' << hex(Value) << '\n';
256303231Sdim  }
257303231Sdim
258303231Sdim  void printString(StringRef Value) { startLine() << Value << "\n"; }
259303231Sdim
260303231Sdim  void printString(StringRef Label, StringRef Value) {
261303231Sdim    startLine() << Label << ": " << Value << "\n";
262303231Sdim  }
263303231Sdim
264303231Sdim  void printString(StringRef Label, const std::string &Value) {
265341825Sdim    printString(Label, StringRef(Value));
266303231Sdim  }
267303231Sdim
268341825Sdim  void printString(StringRef Label, const char* Value) {
269341825Sdim    printString(Label, StringRef(Value));
270341825Sdim  }
271341825Sdim
272303231Sdim  template <typename T>
273303231Sdim  void printNumber(StringRef Label, StringRef Str, T Value) {
274303231Sdim    startLine() << Label << ": " << Str << " (" << Value << ")\n";
275303231Sdim  }
276303231Sdim
277303231Sdim  void printBinary(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value) {
278303231Sdim    printBinaryImpl(Label, Str, Value, false);
279303231Sdim  }
280303231Sdim
281303231Sdim  void printBinary(StringRef Label, StringRef Str, ArrayRef<char> Value) {
282303231Sdim    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
283303231Sdim                          Value.size());
284303231Sdim    printBinaryImpl(Label, Str, V, false);
285303231Sdim  }
286303231Sdim
287303231Sdim  void printBinary(StringRef Label, ArrayRef<uint8_t> Value) {
288303231Sdim    printBinaryImpl(Label, StringRef(), Value, false);
289303231Sdim  }
290303231Sdim
291303231Sdim  void printBinary(StringRef Label, ArrayRef<char> Value) {
292303231Sdim    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
293303231Sdim                          Value.size());
294303231Sdim    printBinaryImpl(Label, StringRef(), V, false);
295303231Sdim  }
296303231Sdim
297303231Sdim  void printBinary(StringRef Label, StringRef Value) {
298303231Sdim    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
299303231Sdim                          Value.size());
300303231Sdim    printBinaryImpl(Label, StringRef(), V, false);
301303231Sdim  }
302303231Sdim
303321369Sdim  void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value,
304321369Sdim                        uint32_t StartOffset) {
305321369Sdim    printBinaryImpl(Label, StringRef(), Value, true, StartOffset);
306321369Sdim  }
307321369Sdim
308303231Sdim  void printBinaryBlock(StringRef Label, ArrayRef<uint8_t> Value) {
309303231Sdim    printBinaryImpl(Label, StringRef(), Value, true);
310303231Sdim  }
311303231Sdim
312303231Sdim  void printBinaryBlock(StringRef Label, StringRef Value) {
313303231Sdim    auto V = makeArrayRef(reinterpret_cast<const uint8_t *>(Value.data()),
314303231Sdim                          Value.size());
315303231Sdim    printBinaryImpl(Label, StringRef(), V, true);
316303231Sdim  }
317303231Sdim
318303231Sdim  template <typename T> void printObject(StringRef Label, const T &Value) {
319303231Sdim    startLine() << Label << ": " << Value << "\n";
320303231Sdim  }
321303231Sdim
322303231Sdim  raw_ostream &startLine() {
323303231Sdim    printIndent();
324303231Sdim    return OS;
325303231Sdim  }
326303231Sdim
327303231Sdim  raw_ostream &getOStream() { return OS; }
328303231Sdim
329303231Sdimprivate:
330303231Sdim  template <typename T> void printVersionInternal(T Value) {
331303231Sdim    getOStream() << Value;
332303231Sdim  }
333303231Sdim
334303231Sdim  template <typename S, typename T, typename... TArgs>
335303231Sdim  void printVersionInternal(S Value, T Value2, TArgs... Args) {
336303231Sdim    getOStream() << Value << ".";
337303231Sdim    printVersionInternal(Value2, Args...);
338303231Sdim  }
339303231Sdim
340303231Sdim  template <typename T>
341303231Sdim  static bool flagName(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
342303231Sdim    return lhs.Name < rhs.Name;
343303231Sdim  }
344303231Sdim
345303231Sdim  void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef<uint8_t> Value,
346321369Sdim                       bool Block, uint32_t StartOffset = 0);
347303231Sdim
348303231Sdim  raw_ostream &OS;
349303231Sdim  int IndentLevel;
350303231Sdim  StringRef Prefix;
351303231Sdim};
352303231Sdim
353303231Sdimtemplate <>
354303231Sdiminline void
355303231SdimScopedPrinter::printHex<support::ulittle16_t>(StringRef Label,
356303231Sdim                                              support::ulittle16_t Value) {
357303231Sdim  startLine() << Label << ": " << hex(Value) << "\n";
358303231Sdim}
359303231Sdim
360303231Sdimtemplate<char Open, char Close>
361303231Sdimstruct DelimitedScope {
362303231Sdim  explicit DelimitedScope(ScopedPrinter &W) : W(W) {
363303231Sdim    W.startLine() << Open << '\n';
364303231Sdim    W.indent();
365303231Sdim  }
366303231Sdim
367303231Sdim  DelimitedScope(ScopedPrinter &W, StringRef N) : W(W) {
368303231Sdim    W.startLine() << N;
369303231Sdim    if (!N.empty())
370303231Sdim      W.getOStream() << ' ';
371303231Sdim    W.getOStream() << Open << '\n';
372303231Sdim    W.indent();
373303231Sdim  }
374303231Sdim
375303231Sdim  ~DelimitedScope() {
376303231Sdim    W.unindent();
377303231Sdim    W.startLine() << Close << '\n';
378303231Sdim  }
379303231Sdim
380303231Sdim  ScopedPrinter &W;
381303231Sdim};
382303231Sdim
383303231Sdimusing DictScope = DelimitedScope<'{', '}'>;
384303231Sdimusing ListScope = DelimitedScope<'[', ']'>;
385303231Sdim
386303231Sdim} // namespace llvm
387303231Sdim
388303231Sdim#endif
389