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