xref: /freebsd-src/contrib/llvm-project/clang/lib/AST/Interp/Disasm.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1a7dea167SDimitry Andric //===--- Disasm.cpp - Disassembler for bytecode functions -------*- C++ -*-===//
2a7dea167SDimitry Andric //
3a7dea167SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a7dea167SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5a7dea167SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a7dea167SDimitry Andric //
7a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
8a7dea167SDimitry Andric //
9a7dea167SDimitry Andric // Dump method for Function which disassembles the bytecode.
10a7dea167SDimitry Andric //
11a7dea167SDimitry Andric //===----------------------------------------------------------------------===//
12a7dea167SDimitry Andric 
13*0fca6ea1SDimitry Andric #include "Boolean.h"
14*0fca6ea1SDimitry Andric #include "Context.h"
15*0fca6ea1SDimitry Andric #include "EvaluationResult.h"
1606c3fb27SDimitry Andric #include "Floating.h"
17a7dea167SDimitry Andric #include "Function.h"
18*0fca6ea1SDimitry Andric #include "FunctionPointer.h"
19*0fca6ea1SDimitry Andric #include "Integral.h"
20*0fca6ea1SDimitry Andric #include "IntegralAP.h"
21*0fca6ea1SDimitry Andric #include "InterpFrame.h"
22*0fca6ea1SDimitry Andric #include "MemberPointer.h"
23a7dea167SDimitry Andric #include "Opcode.h"
24a7dea167SDimitry Andric #include "PrimType.h"
25a7dea167SDimitry Andric #include "Program.h"
26*0fca6ea1SDimitry Andric #include "clang/AST/ASTDumperUtils.h"
27a7dea167SDimitry Andric #include "clang/AST/DeclCXX.h"
28*0fca6ea1SDimitry Andric #include "clang/AST/ExprCXX.h"
29a7dea167SDimitry Andric #include "llvm/Support/Compiler.h"
305ffd83dbSDimitry Andric #include "llvm/Support/Format.h"
31a7dea167SDimitry Andric 
32a7dea167SDimitry Andric using namespace clang;
33a7dea167SDimitry Andric using namespace clang::interp;
34a7dea167SDimitry Andric 
35bdd1243dSDimitry Andric template <typename T> inline T ReadArg(Program &P, CodePtr &OpPC) {
36bdd1243dSDimitry Andric   if constexpr (std::is_pointer_v<T>) {
37349cc55cSDimitry Andric     uint32_t ID = OpPC.read<uint32_t>();
38349cc55cSDimitry Andric     return reinterpret_cast<T>(P.getNativePointer(ID));
39bdd1243dSDimitry Andric   } else {
40bdd1243dSDimitry Andric     return OpPC.read<T>();
41bdd1243dSDimitry Andric   }
42349cc55cSDimitry Andric }
43349cc55cSDimitry Andric 
445f757f3fSDimitry Andric template <> inline Floating ReadArg<Floating>(Program &P, CodePtr &OpPC) {
455f757f3fSDimitry Andric   Floating F = Floating::deserialize(*OpPC);
465f757f3fSDimitry Andric   OpPC += align(F.bytesToSerialize());
475f757f3fSDimitry Andric   return F;
485f757f3fSDimitry Andric }
495f757f3fSDimitry Andric 
50*0fca6ea1SDimitry Andric template <>
51*0fca6ea1SDimitry Andric inline IntegralAP<false> ReadArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
52*0fca6ea1SDimitry Andric   IntegralAP<false> I = IntegralAP<false>::deserialize(*OpPC);
53*0fca6ea1SDimitry Andric   OpPC += align(I.bytesToSerialize());
54*0fca6ea1SDimitry Andric   return I;
55*0fca6ea1SDimitry Andric }
56*0fca6ea1SDimitry Andric 
57*0fca6ea1SDimitry Andric template <>
58*0fca6ea1SDimitry Andric inline IntegralAP<true> ReadArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
59*0fca6ea1SDimitry Andric   IntegralAP<true> I = IntegralAP<true>::deserialize(*OpPC);
60*0fca6ea1SDimitry Andric   OpPC += align(I.bytesToSerialize());
61*0fca6ea1SDimitry Andric   return I;
62*0fca6ea1SDimitry Andric }
63*0fca6ea1SDimitry Andric 
64a7dea167SDimitry Andric LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
65a7dea167SDimitry Andric 
66a7dea167SDimitry Andric LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
67*0fca6ea1SDimitry Andric   {
68*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_GREEN, true});
6906c3fb27SDimitry Andric     OS << getName() << " " << (const void *)this << "\n";
70*0fca6ea1SDimitry Andric   }
71a7dea167SDimitry Andric   OS << "frame size: " << getFrameSize() << "\n";
72a7dea167SDimitry Andric   OS << "arg size:   " << getArgSize() << "\n";
73a7dea167SDimitry Andric   OS << "rvo:        " << hasRVO() << "\n";
74bdd1243dSDimitry Andric   OS << "this arg:   " << hasThisPointer() << "\n";
75a7dea167SDimitry Andric 
76a7dea167SDimitry Andric   auto PrintName = [&OS](const char *Name) {
77a7dea167SDimitry Andric     OS << Name;
7806c3fb27SDimitry Andric     long N = 30 - strlen(Name);
7906c3fb27SDimitry Andric     if (N > 0)
8006c3fb27SDimitry Andric       OS.indent(N);
81a7dea167SDimitry Andric   };
82a7dea167SDimitry Andric 
83a7dea167SDimitry Andric   for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
84a7dea167SDimitry Andric     size_t Addr = PC - Start;
85a7dea167SDimitry Andric     auto Op = PC.read<Opcode>();
86a7dea167SDimitry Andric     OS << llvm::format("%8d", Addr) << " ";
87a7dea167SDimitry Andric     switch (Op) {
88a7dea167SDimitry Andric #define GET_DISASM
89a7dea167SDimitry Andric #include "Opcodes.inc"
90a7dea167SDimitry Andric #undef GET_DISASM
91a7dea167SDimitry Andric     }
92a7dea167SDimitry Andric   }
93a7dea167SDimitry Andric }
94a7dea167SDimitry Andric 
95a7dea167SDimitry Andric LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
96a7dea167SDimitry Andric 
97*0fca6ea1SDimitry Andric static const char *primTypeToString(PrimType T) {
98*0fca6ea1SDimitry Andric   switch (T) {
99*0fca6ea1SDimitry Andric   case PT_Sint8:
100*0fca6ea1SDimitry Andric     return "Sint8";
101*0fca6ea1SDimitry Andric   case PT_Uint8:
102*0fca6ea1SDimitry Andric     return "Uint8";
103*0fca6ea1SDimitry Andric   case PT_Sint16:
104*0fca6ea1SDimitry Andric     return "Sint16";
105*0fca6ea1SDimitry Andric   case PT_Uint16:
106*0fca6ea1SDimitry Andric     return "Uint16";
107*0fca6ea1SDimitry Andric   case PT_Sint32:
108*0fca6ea1SDimitry Andric     return "Sint32";
109*0fca6ea1SDimitry Andric   case PT_Uint32:
110*0fca6ea1SDimitry Andric     return "Uint32";
111*0fca6ea1SDimitry Andric   case PT_Sint64:
112*0fca6ea1SDimitry Andric     return "Sint64";
113*0fca6ea1SDimitry Andric   case PT_Uint64:
114*0fca6ea1SDimitry Andric     return "Uint64";
115*0fca6ea1SDimitry Andric   case PT_IntAP:
116*0fca6ea1SDimitry Andric     return "IntAP";
117*0fca6ea1SDimitry Andric   case PT_IntAPS:
118*0fca6ea1SDimitry Andric     return "IntAPS";
119*0fca6ea1SDimitry Andric   case PT_Bool:
120*0fca6ea1SDimitry Andric     return "Bool";
121*0fca6ea1SDimitry Andric   case PT_Float:
122*0fca6ea1SDimitry Andric     return "Float";
123*0fca6ea1SDimitry Andric   case PT_Ptr:
124*0fca6ea1SDimitry Andric     return "Ptr";
125*0fca6ea1SDimitry Andric   case PT_FnPtr:
126*0fca6ea1SDimitry Andric     return "FnPtr";
127*0fca6ea1SDimitry Andric   case PT_MemberPtr:
128*0fca6ea1SDimitry Andric     return "MemberPtr";
129*0fca6ea1SDimitry Andric   }
130*0fca6ea1SDimitry Andric   llvm_unreachable("Unhandled PrimType");
131*0fca6ea1SDimitry Andric }
132*0fca6ea1SDimitry Andric 
133a7dea167SDimitry Andric LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
134*0fca6ea1SDimitry Andric   {
135*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
136*0fca6ea1SDimitry Andric     OS << "\n:: Program\n";
137*0fca6ea1SDimitry Andric   }
138*0fca6ea1SDimitry Andric 
139*0fca6ea1SDimitry Andric   {
140*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
141*0fca6ea1SDimitry Andric     OS << "Total memory : " << Allocator.getTotalMemory() << " bytes\n";
142bdd1243dSDimitry Andric     OS << "Global Variables: " << Globals.size() << "\n";
143*0fca6ea1SDimitry Andric   }
144*0fca6ea1SDimitry Andric   unsigned GI = 0;
145*0fca6ea1SDimitry Andric   for (const Global *G : Globals) {
146*0fca6ea1SDimitry Andric     const Descriptor *Desc = G->block()->getDescriptor();
147*0fca6ea1SDimitry Andric     Pointer GP = getPtrGlobal(GI);
148*0fca6ea1SDimitry Andric 
149*0fca6ea1SDimitry Andric     OS << GI << ": " << (const void *)G->block() << " ";
150*0fca6ea1SDimitry Andric     {
151*0fca6ea1SDimitry Andric       ColorScope SC(OS, true,
152*0fca6ea1SDimitry Andric                     GP.isInitialized()
153*0fca6ea1SDimitry Andric                         ? TerminalColor{llvm::raw_ostream::GREEN, false}
154*0fca6ea1SDimitry Andric                         : TerminalColor{llvm::raw_ostream::RED, false});
155*0fca6ea1SDimitry Andric       OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
156*0fca6ea1SDimitry Andric     }
157*0fca6ea1SDimitry Andric     Desc->dump(OS);
158*0fca6ea1SDimitry Andric 
159*0fca6ea1SDimitry Andric     if (GP.isInitialized() && Desc->IsTemporary) {
160*0fca6ea1SDimitry Andric       if (const auto *MTE =
161*0fca6ea1SDimitry Andric               dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->asExpr());
162*0fca6ea1SDimitry Andric           MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
163*0fca6ea1SDimitry Andric         if (const APValue *V =
164*0fca6ea1SDimitry Andric                 MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {
165*0fca6ea1SDimitry Andric           OS << " (global temporary value: ";
166*0fca6ea1SDimitry Andric           {
167*0fca6ea1SDimitry Andric             ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_MAGENTA, true});
168*0fca6ea1SDimitry Andric             std::string VStr;
169*0fca6ea1SDimitry Andric             llvm::raw_string_ostream SS(VStr);
170*0fca6ea1SDimitry Andric             V->dump(SS, Ctx.getASTContext());
171*0fca6ea1SDimitry Andric 
172*0fca6ea1SDimitry Andric             for (unsigned I = 0; I != VStr.size(); ++I) {
173*0fca6ea1SDimitry Andric               if (VStr[I] == '\n')
174*0fca6ea1SDimitry Andric                 VStr[I] = ' ';
175*0fca6ea1SDimitry Andric             }
176*0fca6ea1SDimitry Andric             VStr.pop_back(); // Remove the newline (or now space) at the end.
177*0fca6ea1SDimitry Andric             OS << VStr;
178*0fca6ea1SDimitry Andric           }
179*0fca6ea1SDimitry Andric           OS << ')';
180*0fca6ea1SDimitry Andric         }
181*0fca6ea1SDimitry Andric       }
182*0fca6ea1SDimitry Andric     }
183*0fca6ea1SDimitry Andric 
184bdd1243dSDimitry Andric     OS << "\n";
185*0fca6ea1SDimitry Andric     if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {
186*0fca6ea1SDimitry Andric       OS << "   ";
187*0fca6ea1SDimitry Andric       {
188*0fca6ea1SDimitry Andric         ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
189*0fca6ea1SDimitry Andric         OS << primTypeToString(Desc->getPrimType()) << " ";
190*0fca6ea1SDimitry Andric       }
191*0fca6ea1SDimitry Andric       TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });
192*0fca6ea1SDimitry Andric       OS << "\n";
193*0fca6ea1SDimitry Andric     }
194*0fca6ea1SDimitry Andric     ++GI;
195*0fca6ea1SDimitry Andric   }
196*0fca6ea1SDimitry Andric 
197*0fca6ea1SDimitry Andric   {
198*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
199*0fca6ea1SDimitry Andric     OS << "Functions: " << Funcs.size() << "\n";
200*0fca6ea1SDimitry Andric   }
201*0fca6ea1SDimitry Andric   for (const auto &Func : Funcs) {
202a7dea167SDimitry Andric     Func.second->dump();
203a7dea167SDimitry Andric   }
204*0fca6ea1SDimitry Andric   for (const auto &Anon : AnonFuncs) {
205a7dea167SDimitry Andric     Anon->dump();
206a7dea167SDimitry Andric   }
207a7dea167SDimitry Andric }
208*0fca6ea1SDimitry Andric 
209*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void Descriptor::dump() const {
210*0fca6ea1SDimitry Andric   dump(llvm::errs());
211*0fca6ea1SDimitry Andric   llvm::errs() << '\n';
212*0fca6ea1SDimitry Andric }
213*0fca6ea1SDimitry Andric 
214*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
215*0fca6ea1SDimitry Andric   // Source
216*0fca6ea1SDimitry Andric   {
217*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
218*0fca6ea1SDimitry Andric     if (const auto *ND = dyn_cast_if_present<NamedDecl>(asDecl()))
219*0fca6ea1SDimitry Andric       ND->printQualifiedName(OS);
220*0fca6ea1SDimitry Andric     else if (asExpr())
221*0fca6ea1SDimitry Andric       OS << "Expr " << (const void *)asExpr();
222*0fca6ea1SDimitry Andric   }
223*0fca6ea1SDimitry Andric 
224*0fca6ea1SDimitry Andric   // Print a few interesting bits about the descriptor.
225*0fca6ea1SDimitry Andric   if (isPrimitiveArray())
226*0fca6ea1SDimitry Andric     OS << " primitive-array";
227*0fca6ea1SDimitry Andric   else if (isCompositeArray())
228*0fca6ea1SDimitry Andric     OS << " composite-array";
229*0fca6ea1SDimitry Andric   else if (isRecord())
230*0fca6ea1SDimitry Andric     OS << " record";
231*0fca6ea1SDimitry Andric   else if (isPrimitive())
232*0fca6ea1SDimitry Andric     OS << " primitive";
233*0fca6ea1SDimitry Andric 
234*0fca6ea1SDimitry Andric   if (isZeroSizeArray())
235*0fca6ea1SDimitry Andric     OS << " zero-size-array";
236*0fca6ea1SDimitry Andric   else if (isUnknownSizeArray())
237*0fca6ea1SDimitry Andric     OS << " unknown-size-array";
238*0fca6ea1SDimitry Andric 
239*0fca6ea1SDimitry Andric   if (isDummy())
240*0fca6ea1SDimitry Andric     OS << " dummy";
241*0fca6ea1SDimitry Andric }
242*0fca6ea1SDimitry Andric 
243*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const {
244*0fca6ea1SDimitry Andric   {
245*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
246*0fca6ea1SDimitry Andric     OS << "InlineDescriptor " << (const void *)this << "\n";
247*0fca6ea1SDimitry Andric   }
248*0fca6ea1SDimitry Andric   OS << "Offset: " << Offset << "\n";
249*0fca6ea1SDimitry Andric   OS << "IsConst: " << IsConst << "\n";
250*0fca6ea1SDimitry Andric   OS << "IsInitialized: " << IsInitialized << "\n";
251*0fca6ea1SDimitry Andric   OS << "IsBase: " << IsBase << "\n";
252*0fca6ea1SDimitry Andric   OS << "IsActive: " << IsActive << "\n";
253*0fca6ea1SDimitry Andric   OS << "IsFieldMutable: " << IsFieldMutable << "\n";
254*0fca6ea1SDimitry Andric   OS << "Desc: ";
255*0fca6ea1SDimitry Andric   if (Desc)
256*0fca6ea1SDimitry Andric     Desc->dump(OS);
257*0fca6ea1SDimitry Andric   else
258*0fca6ea1SDimitry Andric     OS << "nullptr";
259*0fca6ea1SDimitry Andric   OS << "\n";
260*0fca6ea1SDimitry Andric }
261*0fca6ea1SDimitry Andric 
262*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
263*0fca6ea1SDimitry Andric                                         unsigned Indent) const {
264*0fca6ea1SDimitry Andric   unsigned Spaces = Indent * 2;
265*0fca6ea1SDimitry Andric   {
266*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
267*0fca6ea1SDimitry Andric     OS.indent(Spaces);
268*0fca6ea1SDimitry Andric     if (getCallee())
269*0fca6ea1SDimitry Andric       describe(OS);
270*0fca6ea1SDimitry Andric     else
271*0fca6ea1SDimitry Andric       OS << "Frame (Depth: " << getDepth() << ")";
272*0fca6ea1SDimitry Andric     OS << "\n";
273*0fca6ea1SDimitry Andric   }
274*0fca6ea1SDimitry Andric   OS.indent(Spaces) << "Function: " << getFunction();
275*0fca6ea1SDimitry Andric   if (const Function *F = getFunction()) {
276*0fca6ea1SDimitry Andric     OS << " (" << F->getName() << ")";
277*0fca6ea1SDimitry Andric   }
278*0fca6ea1SDimitry Andric   OS << "\n";
279*0fca6ea1SDimitry Andric   OS.indent(Spaces) << "This: " << getThis() << "\n";
280*0fca6ea1SDimitry Andric   OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
281*0fca6ea1SDimitry Andric 
282*0fca6ea1SDimitry Andric   while (const InterpFrame *F = this->Caller) {
283*0fca6ea1SDimitry Andric     F->dump(OS, Indent + 1);
284*0fca6ea1SDimitry Andric     F = F->Caller;
285*0fca6ea1SDimitry Andric   }
286*0fca6ea1SDimitry Andric }
287*0fca6ea1SDimitry Andric 
288*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
289*0fca6ea1SDimitry Andric                                    unsigned Offset) const {
290*0fca6ea1SDimitry Andric   unsigned Indent = Indentation * 2;
291*0fca6ea1SDimitry Andric   OS.indent(Indent);
292*0fca6ea1SDimitry Andric   {
293*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
294*0fca6ea1SDimitry Andric     OS << getName() << "\n";
295*0fca6ea1SDimitry Andric   }
296*0fca6ea1SDimitry Andric 
297*0fca6ea1SDimitry Andric   unsigned I = 0;
298*0fca6ea1SDimitry Andric   for (const Record::Base &B : bases()) {
299*0fca6ea1SDimitry Andric     OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
300*0fca6ea1SDimitry Andric                       << "\n";
301*0fca6ea1SDimitry Andric     B.R->dump(OS, Indentation + 1, Offset + B.Offset);
302*0fca6ea1SDimitry Andric     ++I;
303*0fca6ea1SDimitry Andric   }
304*0fca6ea1SDimitry Andric 
305*0fca6ea1SDimitry Andric   I = 0;
306*0fca6ea1SDimitry Andric   for (const Record::Field &F : fields()) {
307*0fca6ea1SDimitry Andric     OS.indent(Indent) << "- Field " << I << ": ";
308*0fca6ea1SDimitry Andric     {
309*0fca6ea1SDimitry Andric       ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
310*0fca6ea1SDimitry Andric       OS << F.Decl->getName();
311*0fca6ea1SDimitry Andric     }
312*0fca6ea1SDimitry Andric     OS << ". Offset " << (Offset + F.Offset) << "\n";
313*0fca6ea1SDimitry Andric     ++I;
314*0fca6ea1SDimitry Andric   }
315*0fca6ea1SDimitry Andric 
316*0fca6ea1SDimitry Andric   I = 0;
317*0fca6ea1SDimitry Andric   for (const Record::Base &B : virtual_bases()) {
318*0fca6ea1SDimitry Andric     OS.indent(Indent) << "- Virtual Base " << I << ". Offset "
319*0fca6ea1SDimitry Andric                       << (Offset + B.Offset) << "\n";
320*0fca6ea1SDimitry Andric     B.R->dump(OS, Indentation + 1, Offset + B.Offset);
321*0fca6ea1SDimitry Andric     ++I;
322*0fca6ea1SDimitry Andric   }
323*0fca6ea1SDimitry Andric }
324*0fca6ea1SDimitry Andric 
325*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
326*0fca6ea1SDimitry Andric   {
327*0fca6ea1SDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});
328*0fca6ea1SDimitry Andric     OS << "Block " << (const void *)this;
329*0fca6ea1SDimitry Andric   }
330*0fca6ea1SDimitry Andric   OS << " (";
331*0fca6ea1SDimitry Andric   Desc->dump(OS);
332*0fca6ea1SDimitry Andric   OS << ")\n";
333*0fca6ea1SDimitry Andric   unsigned NPointers = 0;
334*0fca6ea1SDimitry Andric   for (const Pointer *P = Pointers; P; P = P->Next) {
335*0fca6ea1SDimitry Andric     ++NPointers;
336*0fca6ea1SDimitry Andric   }
337*0fca6ea1SDimitry Andric   OS << "  Pointers: " << NPointers << "\n";
338*0fca6ea1SDimitry Andric   OS << "  Dead: " << IsDead << "\n";
339*0fca6ea1SDimitry Andric   OS << "  Static: " << IsStatic << "\n";
340*0fca6ea1SDimitry Andric   OS << "  Extern: " << IsExtern << "\n";
341*0fca6ea1SDimitry Andric   OS << "  Initialized: " << IsInitialized << "\n";
342*0fca6ea1SDimitry Andric }
343*0fca6ea1SDimitry Andric 
344*0fca6ea1SDimitry Andric LLVM_DUMP_METHOD void EvaluationResult::dump() const {
345*0fca6ea1SDimitry Andric   assert(Ctx);
346*0fca6ea1SDimitry Andric   auto &OS = llvm::errs();
347*0fca6ea1SDimitry Andric   const ASTContext &ASTCtx = Ctx->getASTContext();
348*0fca6ea1SDimitry Andric 
349*0fca6ea1SDimitry Andric   switch (Kind) {
350*0fca6ea1SDimitry Andric   case Empty:
351*0fca6ea1SDimitry Andric     OS << "Empty\n";
352*0fca6ea1SDimitry Andric     break;
353*0fca6ea1SDimitry Andric   case RValue:
354*0fca6ea1SDimitry Andric     OS << "RValue: ";
355*0fca6ea1SDimitry Andric     std::get<APValue>(Value).dump(OS, ASTCtx);
356*0fca6ea1SDimitry Andric     break;
357*0fca6ea1SDimitry Andric   case LValue: {
358*0fca6ea1SDimitry Andric     assert(Source);
359*0fca6ea1SDimitry Andric     QualType SourceType;
360*0fca6ea1SDimitry Andric     if (const auto *D = Source.dyn_cast<const Decl *>()) {
361*0fca6ea1SDimitry Andric       if (const auto *VD = dyn_cast<ValueDecl>(D))
362*0fca6ea1SDimitry Andric         SourceType = VD->getType();
363*0fca6ea1SDimitry Andric     } else if (const auto *E = Source.dyn_cast<const Expr *>()) {
364*0fca6ea1SDimitry Andric       SourceType = E->getType();
365*0fca6ea1SDimitry Andric     }
366*0fca6ea1SDimitry Andric 
367*0fca6ea1SDimitry Andric     OS << "LValue: ";
368*0fca6ea1SDimitry Andric     if (const auto *P = std::get_if<Pointer>(&Value))
369*0fca6ea1SDimitry Andric       P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
370*0fca6ea1SDimitry Andric     else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
371*0fca6ea1SDimitry Andric       FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
372*0fca6ea1SDimitry Andric     OS << "\n";
373*0fca6ea1SDimitry Andric     break;
374*0fca6ea1SDimitry Andric   }
375*0fca6ea1SDimitry Andric   case Invalid:
376*0fca6ea1SDimitry Andric     OS << "Invalid\n";
377*0fca6ea1SDimitry Andric     break;
378*0fca6ea1SDimitry Andric   case Valid:
379*0fca6ea1SDimitry Andric     OS << "Valid\n";
380*0fca6ea1SDimitry Andric     break;
381*0fca6ea1SDimitry Andric   }
382*0fca6ea1SDimitry Andric }
383