xref: /freebsd/contrib/llvm-project/clang/lib/AST/ByteCode/Disasm.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //===--- Disasm.cpp - Disassembler for bytecode functions -------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // Dump method for Function which disassembles the bytecode.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #include "Boolean.h"
14*700637cbSDimitry Andric #include "Context.h"
15*700637cbSDimitry Andric #include "EvaluationResult.h"
16*700637cbSDimitry Andric #include "FixedPoint.h"
17*700637cbSDimitry Andric #include "Floating.h"
18*700637cbSDimitry Andric #include "Function.h"
19*700637cbSDimitry Andric #include "FunctionPointer.h"
20*700637cbSDimitry Andric #include "Integral.h"
21*700637cbSDimitry Andric #include "IntegralAP.h"
22*700637cbSDimitry Andric #include "InterpFrame.h"
23*700637cbSDimitry Andric #include "MemberPointer.h"
24*700637cbSDimitry Andric #include "Opcode.h"
25*700637cbSDimitry Andric #include "PrimType.h"
26*700637cbSDimitry Andric #include "Program.h"
27*700637cbSDimitry Andric #include "clang/AST/ASTDumperUtils.h"
28*700637cbSDimitry Andric #include "clang/AST/DeclCXX.h"
29*700637cbSDimitry Andric #include "clang/AST/ExprCXX.h"
30*700637cbSDimitry Andric #include "llvm/Support/Compiler.h"
31*700637cbSDimitry Andric 
32*700637cbSDimitry Andric using namespace clang;
33*700637cbSDimitry Andric using namespace clang::interp;
34*700637cbSDimitry Andric 
35*700637cbSDimitry Andric template <typename T>
printArg(Program & P,CodePtr & OpPC)36*700637cbSDimitry Andric inline static std::string printArg(Program &P, CodePtr &OpPC) {
37*700637cbSDimitry Andric   if constexpr (std::is_pointer_v<T>) {
38*700637cbSDimitry Andric     uint32_t ID = OpPC.read<uint32_t>();
39*700637cbSDimitry Andric     std::string Result;
40*700637cbSDimitry Andric     llvm::raw_string_ostream SS(Result);
41*700637cbSDimitry Andric     SS << reinterpret_cast<T>(P.getNativePointer(ID));
42*700637cbSDimitry Andric     return Result;
43*700637cbSDimitry Andric   } else {
44*700637cbSDimitry Andric     std::string Result;
45*700637cbSDimitry Andric     llvm::raw_string_ostream SS(Result);
46*700637cbSDimitry Andric     auto Arg = OpPC.read<T>();
47*700637cbSDimitry Andric     SS << Arg;
48*700637cbSDimitry Andric     return Result;
49*700637cbSDimitry Andric   }
50*700637cbSDimitry Andric }
51*700637cbSDimitry Andric 
printArg(Program & P,CodePtr & OpPC)52*700637cbSDimitry Andric template <> inline std::string printArg<Floating>(Program &P, CodePtr &OpPC) {
53*700637cbSDimitry Andric   auto Sem = Floating::deserializeSemantics(*OpPC);
54*700637cbSDimitry Andric 
55*700637cbSDimitry Andric   unsigned BitWidth = llvm::APFloatBase::semanticsSizeInBits(
56*700637cbSDimitry Andric       llvm::APFloatBase::EnumToSemantics(Sem));
57*700637cbSDimitry Andric   auto Memory =
58*700637cbSDimitry Andric       std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
59*700637cbSDimitry Andric   Floating Result(Memory.get(), Sem);
60*700637cbSDimitry Andric   Floating::deserialize(*OpPC, &Result);
61*700637cbSDimitry Andric 
62*700637cbSDimitry Andric   OpPC += align(Result.bytesToSerialize());
63*700637cbSDimitry Andric 
64*700637cbSDimitry Andric   std::string S;
65*700637cbSDimitry Andric   llvm::raw_string_ostream SS(S);
66*700637cbSDimitry Andric   SS << std::move(Result);
67*700637cbSDimitry Andric   return S;
68*700637cbSDimitry Andric }
69*700637cbSDimitry Andric 
70*700637cbSDimitry Andric template <>
printArg(Program & P,CodePtr & OpPC)71*700637cbSDimitry Andric inline std::string printArg<IntegralAP<false>>(Program &P, CodePtr &OpPC) {
72*700637cbSDimitry Andric   using T = IntegralAP<false>;
73*700637cbSDimitry Andric   uint32_t BitWidth = T::deserializeSize(*OpPC);
74*700637cbSDimitry Andric   auto Memory =
75*700637cbSDimitry Andric       std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
76*700637cbSDimitry Andric 
77*700637cbSDimitry Andric   T Result(Memory.get(), BitWidth);
78*700637cbSDimitry Andric   T::deserialize(*OpPC, &Result);
79*700637cbSDimitry Andric 
80*700637cbSDimitry Andric   OpPC += align(Result.bytesToSerialize());
81*700637cbSDimitry Andric 
82*700637cbSDimitry Andric   std::string Str;
83*700637cbSDimitry Andric   llvm::raw_string_ostream SS(Str);
84*700637cbSDimitry Andric   SS << std::move(Result);
85*700637cbSDimitry Andric   return Str;
86*700637cbSDimitry Andric }
87*700637cbSDimitry Andric 
88*700637cbSDimitry Andric template <>
printArg(Program & P,CodePtr & OpPC)89*700637cbSDimitry Andric inline std::string printArg<IntegralAP<true>>(Program &P, CodePtr &OpPC) {
90*700637cbSDimitry Andric   using T = IntegralAP<true>;
91*700637cbSDimitry Andric   uint32_t BitWidth = T::deserializeSize(*OpPC);
92*700637cbSDimitry Andric   auto Memory =
93*700637cbSDimitry Andric       std::make_unique<uint64_t[]>(llvm::APInt::getNumWords(BitWidth));
94*700637cbSDimitry Andric 
95*700637cbSDimitry Andric   T Result(Memory.get(), BitWidth);
96*700637cbSDimitry Andric   T::deserialize(*OpPC, &Result);
97*700637cbSDimitry Andric 
98*700637cbSDimitry Andric   OpPC += align(Result.bytesToSerialize());
99*700637cbSDimitry Andric 
100*700637cbSDimitry Andric   std::string Str;
101*700637cbSDimitry Andric   llvm::raw_string_ostream SS(Str);
102*700637cbSDimitry Andric   SS << std::move(Result);
103*700637cbSDimitry Andric   return Str;
104*700637cbSDimitry Andric }
105*700637cbSDimitry Andric 
printArg(Program & P,CodePtr & OpPC)106*700637cbSDimitry Andric template <> inline std::string printArg<FixedPoint>(Program &P, CodePtr &OpPC) {
107*700637cbSDimitry Andric   auto F = FixedPoint::deserialize(*OpPC);
108*700637cbSDimitry Andric   OpPC += align(F.bytesToSerialize());
109*700637cbSDimitry Andric 
110*700637cbSDimitry Andric   std::string Result;
111*700637cbSDimitry Andric   llvm::raw_string_ostream SS(Result);
112*700637cbSDimitry Andric   SS << std::move(F);
113*700637cbSDimitry Andric   return Result;
114*700637cbSDimitry Andric }
115*700637cbSDimitry Andric 
isJumpOpcode(Opcode Op)116*700637cbSDimitry Andric static bool isJumpOpcode(Opcode Op) {
117*700637cbSDimitry Andric   return Op == OP_Jmp || Op == OP_Jf || Op == OP_Jt;
118*700637cbSDimitry Andric }
119*700637cbSDimitry Andric 
getNumDisplayWidth(size_t N)120*700637cbSDimitry Andric static size_t getNumDisplayWidth(size_t N) {
121*700637cbSDimitry Andric   unsigned L = 1u, M = 10u;
122*700637cbSDimitry Andric   while (M <= N && ++L != std::numeric_limits<size_t>::digits10 + 1)
123*700637cbSDimitry Andric     M *= 10u;
124*700637cbSDimitry Andric 
125*700637cbSDimitry Andric   return L;
126*700637cbSDimitry Andric }
127*700637cbSDimitry Andric 
dump() const128*700637cbSDimitry Andric LLVM_DUMP_METHOD void Function::dump() const { dump(llvm::errs()); }
129*700637cbSDimitry Andric 
dump(llvm::raw_ostream & OS) const130*700637cbSDimitry Andric LLVM_DUMP_METHOD void Function::dump(llvm::raw_ostream &OS) const {
131*700637cbSDimitry Andric   {
132*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_GREEN, true});
133*700637cbSDimitry Andric     OS << getName() << " " << (const void *)this << "\n";
134*700637cbSDimitry Andric   }
135*700637cbSDimitry Andric   OS << "frame size: " << getFrameSize() << "\n";
136*700637cbSDimitry Andric   OS << "arg size:   " << getArgSize() << "\n";
137*700637cbSDimitry Andric   OS << "rvo:        " << hasRVO() << "\n";
138*700637cbSDimitry Andric   OS << "this arg:   " << hasThisPointer() << "\n";
139*700637cbSDimitry Andric 
140*700637cbSDimitry Andric   struct OpText {
141*700637cbSDimitry Andric     size_t Addr;
142*700637cbSDimitry Andric     std::string Op;
143*700637cbSDimitry Andric     bool IsJump;
144*700637cbSDimitry Andric     llvm::SmallVector<std::string> Args;
145*700637cbSDimitry Andric   };
146*700637cbSDimitry Andric 
147*700637cbSDimitry Andric   auto PrintName = [](const char *Name) -> std::string {
148*700637cbSDimitry Andric     return std::string(Name);
149*700637cbSDimitry Andric   };
150*700637cbSDimitry Andric 
151*700637cbSDimitry Andric   llvm::SmallVector<OpText> Code;
152*700637cbSDimitry Andric   size_t LongestAddr = 0;
153*700637cbSDimitry Andric   size_t LongestOp = 0;
154*700637cbSDimitry Andric 
155*700637cbSDimitry Andric   for (CodePtr Start = getCodeBegin(), PC = Start; PC != getCodeEnd();) {
156*700637cbSDimitry Andric     size_t Addr = PC - Start;
157*700637cbSDimitry Andric     OpText Text;
158*700637cbSDimitry Andric     auto Op = PC.read<Opcode>();
159*700637cbSDimitry Andric     Text.Addr = Addr;
160*700637cbSDimitry Andric     Text.IsJump = isJumpOpcode(Op);
161*700637cbSDimitry Andric     switch (Op) {
162*700637cbSDimitry Andric #define GET_DISASM
163*700637cbSDimitry Andric #include "Opcodes.inc"
164*700637cbSDimitry Andric #undef GET_DISASM
165*700637cbSDimitry Andric     }
166*700637cbSDimitry Andric     Code.push_back(Text);
167*700637cbSDimitry Andric     LongestOp = std::max(Text.Op.size(), LongestOp);
168*700637cbSDimitry Andric     LongestAddr = std::max(getNumDisplayWidth(Addr), LongestAddr);
169*700637cbSDimitry Andric   }
170*700637cbSDimitry Andric 
171*700637cbSDimitry Andric   // Record jumps and their targets.
172*700637cbSDimitry Andric   struct JmpData {
173*700637cbSDimitry Andric     size_t From;
174*700637cbSDimitry Andric     size_t To;
175*700637cbSDimitry Andric   };
176*700637cbSDimitry Andric   llvm::SmallVector<JmpData> Jumps;
177*700637cbSDimitry Andric   for (auto &Text : Code) {
178*700637cbSDimitry Andric     if (Text.IsJump)
179*700637cbSDimitry Andric       Jumps.push_back({Text.Addr, Text.Addr + std::stoi(Text.Args[0]) +
180*700637cbSDimitry Andric                                       align(sizeof(Opcode)) +
181*700637cbSDimitry Andric                                       align(sizeof(int32_t))});
182*700637cbSDimitry Andric   }
183*700637cbSDimitry Andric 
184*700637cbSDimitry Andric   llvm::SmallVector<std::string> Text;
185*700637cbSDimitry Andric   Text.reserve(Code.size());
186*700637cbSDimitry Andric   size_t LongestLine = 0;
187*700637cbSDimitry Andric   // Print code to a string, one at a time.
188*700637cbSDimitry Andric   for (auto C : Code) {
189*700637cbSDimitry Andric     std::string Line;
190*700637cbSDimitry Andric     llvm::raw_string_ostream LS(Line);
191*700637cbSDimitry Andric     LS << C.Addr;
192*700637cbSDimitry Andric     LS.indent(LongestAddr - getNumDisplayWidth(C.Addr) + 4);
193*700637cbSDimitry Andric     LS << C.Op;
194*700637cbSDimitry Andric     LS.indent(LongestOp - C.Op.size() + 4);
195*700637cbSDimitry Andric     for (auto &Arg : C.Args) {
196*700637cbSDimitry Andric       LS << Arg << ' ';
197*700637cbSDimitry Andric     }
198*700637cbSDimitry Andric     Text.push_back(Line);
199*700637cbSDimitry Andric     LongestLine = std::max(Line.size(), LongestLine);
200*700637cbSDimitry Andric   }
201*700637cbSDimitry Andric 
202*700637cbSDimitry Andric   assert(Code.size() == Text.size());
203*700637cbSDimitry Andric 
204*700637cbSDimitry Andric   auto spaces = [](unsigned N) -> std::string {
205*700637cbSDimitry Andric     std::string S;
206*700637cbSDimitry Andric     for (unsigned I = 0; I != N; ++I)
207*700637cbSDimitry Andric       S += ' ';
208*700637cbSDimitry Andric     return S;
209*700637cbSDimitry Andric   };
210*700637cbSDimitry Andric 
211*700637cbSDimitry Andric   // Now, draw the jump lines.
212*700637cbSDimitry Andric   for (auto &J : Jumps) {
213*700637cbSDimitry Andric     if (J.To > J.From) {
214*700637cbSDimitry Andric       bool FoundStart = false;
215*700637cbSDimitry Andric       for (size_t LineIndex = 0; LineIndex != Text.size(); ++LineIndex) {
216*700637cbSDimitry Andric         Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());
217*700637cbSDimitry Andric 
218*700637cbSDimitry Andric         if (Code[LineIndex].Addr == J.From) {
219*700637cbSDimitry Andric           Text[LineIndex] += "  --+";
220*700637cbSDimitry Andric           FoundStart = true;
221*700637cbSDimitry Andric         } else if (Code[LineIndex].Addr == J.To) {
222*700637cbSDimitry Andric           Text[LineIndex] += "  <-+";
223*700637cbSDimitry Andric           break;
224*700637cbSDimitry Andric         } else if (FoundStart) {
225*700637cbSDimitry Andric           Text[LineIndex] += "    |";
226*700637cbSDimitry Andric         }
227*700637cbSDimitry Andric       }
228*700637cbSDimitry Andric       LongestLine += 5;
229*700637cbSDimitry Andric     } else {
230*700637cbSDimitry Andric       bool FoundStart = false;
231*700637cbSDimitry Andric       for (ssize_t LineIndex = Text.size() - 1; LineIndex >= 0; --LineIndex) {
232*700637cbSDimitry Andric         Text[LineIndex] += spaces(LongestLine - Text[LineIndex].size());
233*700637cbSDimitry Andric         if (Code[LineIndex].Addr == J.From) {
234*700637cbSDimitry Andric           Text[LineIndex] += "  --+";
235*700637cbSDimitry Andric           FoundStart = true;
236*700637cbSDimitry Andric         } else if (Code[LineIndex].Addr == J.To) {
237*700637cbSDimitry Andric           Text[LineIndex] += "  <-+";
238*700637cbSDimitry Andric           break;
239*700637cbSDimitry Andric         } else if (FoundStart) {
240*700637cbSDimitry Andric           Text[LineIndex] += "    |";
241*700637cbSDimitry Andric         }
242*700637cbSDimitry Andric       }
243*700637cbSDimitry Andric       LongestLine += 5;
244*700637cbSDimitry Andric     }
245*700637cbSDimitry Andric   }
246*700637cbSDimitry Andric 
247*700637cbSDimitry Andric   for (auto &Line : Text)
248*700637cbSDimitry Andric     OS << Line << '\n';
249*700637cbSDimitry Andric }
250*700637cbSDimitry Andric 
dump() const251*700637cbSDimitry Andric LLVM_DUMP_METHOD void Program::dump() const { dump(llvm::errs()); }
252*700637cbSDimitry Andric 
primTypeToString(PrimType T)253*700637cbSDimitry Andric static const char *primTypeToString(PrimType T) {
254*700637cbSDimitry Andric   switch (T) {
255*700637cbSDimitry Andric   case PT_Sint8:
256*700637cbSDimitry Andric     return "Sint8";
257*700637cbSDimitry Andric   case PT_Uint8:
258*700637cbSDimitry Andric     return "Uint8";
259*700637cbSDimitry Andric   case PT_Sint16:
260*700637cbSDimitry Andric     return "Sint16";
261*700637cbSDimitry Andric   case PT_Uint16:
262*700637cbSDimitry Andric     return "Uint16";
263*700637cbSDimitry Andric   case PT_Sint32:
264*700637cbSDimitry Andric     return "Sint32";
265*700637cbSDimitry Andric   case PT_Uint32:
266*700637cbSDimitry Andric     return "Uint32";
267*700637cbSDimitry Andric   case PT_Sint64:
268*700637cbSDimitry Andric     return "Sint64";
269*700637cbSDimitry Andric   case PT_Uint64:
270*700637cbSDimitry Andric     return "Uint64";
271*700637cbSDimitry Andric   case PT_IntAP:
272*700637cbSDimitry Andric     return "IntAP";
273*700637cbSDimitry Andric   case PT_IntAPS:
274*700637cbSDimitry Andric     return "IntAPS";
275*700637cbSDimitry Andric   case PT_Bool:
276*700637cbSDimitry Andric     return "Bool";
277*700637cbSDimitry Andric   case PT_Float:
278*700637cbSDimitry Andric     return "Float";
279*700637cbSDimitry Andric   case PT_Ptr:
280*700637cbSDimitry Andric     return "Ptr";
281*700637cbSDimitry Andric   case PT_MemberPtr:
282*700637cbSDimitry Andric     return "MemberPtr";
283*700637cbSDimitry Andric   case PT_FixedPoint:
284*700637cbSDimitry Andric     return "FixedPoint";
285*700637cbSDimitry Andric   }
286*700637cbSDimitry Andric   llvm_unreachable("Unhandled PrimType");
287*700637cbSDimitry Andric }
288*700637cbSDimitry Andric 
dump(llvm::raw_ostream & OS) const289*700637cbSDimitry Andric LLVM_DUMP_METHOD void Program::dump(llvm::raw_ostream &OS) const {
290*700637cbSDimitry Andric   {
291*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
292*700637cbSDimitry Andric     OS << "\n:: Program\n";
293*700637cbSDimitry Andric   }
294*700637cbSDimitry Andric 
295*700637cbSDimitry Andric   {
296*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
297*700637cbSDimitry Andric     OS << "Total memory : " << Allocator.getTotalMemory() << " bytes\n";
298*700637cbSDimitry Andric     OS << "Global Variables: " << Globals.size() << "\n";
299*700637cbSDimitry Andric   }
300*700637cbSDimitry Andric   unsigned GI = 0;
301*700637cbSDimitry Andric   for (const Global *G : Globals) {
302*700637cbSDimitry Andric     const Descriptor *Desc = G->block()->getDescriptor();
303*700637cbSDimitry Andric     Pointer GP = getPtrGlobal(GI);
304*700637cbSDimitry Andric 
305*700637cbSDimitry Andric     OS << GI << ": " << (const void *)G->block() << " ";
306*700637cbSDimitry Andric     {
307*700637cbSDimitry Andric       ColorScope SC(OS, true,
308*700637cbSDimitry Andric                     GP.isInitialized()
309*700637cbSDimitry Andric                         ? TerminalColor{llvm::raw_ostream::GREEN, false}
310*700637cbSDimitry Andric                         : TerminalColor{llvm::raw_ostream::RED, false});
311*700637cbSDimitry Andric       OS << (GP.isInitialized() ? "initialized " : "uninitialized ");
312*700637cbSDimitry Andric     }
313*700637cbSDimitry Andric     Desc->dump(OS);
314*700637cbSDimitry Andric 
315*700637cbSDimitry Andric     if (GP.isInitialized() && Desc->IsTemporary) {
316*700637cbSDimitry Andric       if (const auto *MTE =
317*700637cbSDimitry Andric               dyn_cast_if_present<MaterializeTemporaryExpr>(Desc->asExpr());
318*700637cbSDimitry Andric           MTE && MTE->getLifetimeExtendedTemporaryDecl()) {
319*700637cbSDimitry Andric         if (const APValue *V =
320*700637cbSDimitry Andric                 MTE->getLifetimeExtendedTemporaryDecl()->getValue()) {
321*700637cbSDimitry Andric           OS << " (global temporary value: ";
322*700637cbSDimitry Andric           {
323*700637cbSDimitry Andric             ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_MAGENTA, true});
324*700637cbSDimitry Andric             std::string VStr;
325*700637cbSDimitry Andric             llvm::raw_string_ostream SS(VStr);
326*700637cbSDimitry Andric             V->dump(SS, Ctx.getASTContext());
327*700637cbSDimitry Andric 
328*700637cbSDimitry Andric             for (unsigned I = 0; I != VStr.size(); ++I) {
329*700637cbSDimitry Andric               if (VStr[I] == '\n')
330*700637cbSDimitry Andric                 VStr[I] = ' ';
331*700637cbSDimitry Andric             }
332*700637cbSDimitry Andric             VStr.pop_back(); // Remove the newline (or now space) at the end.
333*700637cbSDimitry Andric             OS << VStr;
334*700637cbSDimitry Andric           }
335*700637cbSDimitry Andric           OS << ')';
336*700637cbSDimitry Andric         }
337*700637cbSDimitry Andric       }
338*700637cbSDimitry Andric     }
339*700637cbSDimitry Andric 
340*700637cbSDimitry Andric     OS << "\n";
341*700637cbSDimitry Andric     if (GP.isInitialized() && Desc->isPrimitive() && !Desc->isDummy()) {
342*700637cbSDimitry Andric       OS << "   ";
343*700637cbSDimitry Andric       {
344*700637cbSDimitry Andric         ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_CYAN, false});
345*700637cbSDimitry Andric         OS << primTypeToString(Desc->getPrimType()) << " ";
346*700637cbSDimitry Andric       }
347*700637cbSDimitry Andric       TYPE_SWITCH(Desc->getPrimType(), { GP.deref<T>().print(OS); });
348*700637cbSDimitry Andric       OS << "\n";
349*700637cbSDimitry Andric     }
350*700637cbSDimitry Andric     ++GI;
351*700637cbSDimitry Andric   }
352*700637cbSDimitry Andric 
353*700637cbSDimitry Andric   {
354*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::WHITE, true});
355*700637cbSDimitry Andric     OS << "Functions: " << Funcs.size() << "\n";
356*700637cbSDimitry Andric   }
357*700637cbSDimitry Andric   for (const auto &Func : Funcs) {
358*700637cbSDimitry Andric     Func.second->dump();
359*700637cbSDimitry Andric   }
360*700637cbSDimitry Andric   for (const auto &Anon : AnonFuncs) {
361*700637cbSDimitry Andric     Anon->dump();
362*700637cbSDimitry Andric   }
363*700637cbSDimitry Andric }
364*700637cbSDimitry Andric 
dump() const365*700637cbSDimitry Andric LLVM_DUMP_METHOD void Descriptor::dump() const {
366*700637cbSDimitry Andric   dump(llvm::errs());
367*700637cbSDimitry Andric   llvm::errs() << '\n';
368*700637cbSDimitry Andric }
369*700637cbSDimitry Andric 
dump(llvm::raw_ostream & OS) const370*700637cbSDimitry Andric LLVM_DUMP_METHOD void Descriptor::dump(llvm::raw_ostream &OS) const {
371*700637cbSDimitry Andric   // Source
372*700637cbSDimitry Andric   {
373*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
374*700637cbSDimitry Andric     if (const auto *ND = dyn_cast_if_present<NamedDecl>(asDecl()))
375*700637cbSDimitry Andric       ND->printQualifiedName(OS);
376*700637cbSDimitry Andric     else if (asExpr())
377*700637cbSDimitry Andric       OS << "Expr " << (const void *)asExpr();
378*700637cbSDimitry Andric   }
379*700637cbSDimitry Andric 
380*700637cbSDimitry Andric   // Print a few interesting bits about the descriptor.
381*700637cbSDimitry Andric   if (isPrimitiveArray())
382*700637cbSDimitry Andric     OS << " primitive-array";
383*700637cbSDimitry Andric   else if (isCompositeArray())
384*700637cbSDimitry Andric     OS << " composite-array";
385*700637cbSDimitry Andric   else if (isUnion())
386*700637cbSDimitry Andric     OS << " union";
387*700637cbSDimitry Andric   else if (isRecord())
388*700637cbSDimitry Andric     OS << " record";
389*700637cbSDimitry Andric   else if (isPrimitive())
390*700637cbSDimitry Andric     OS << " primitive " << primTypeToString(getPrimType());
391*700637cbSDimitry Andric 
392*700637cbSDimitry Andric   if (isZeroSizeArray())
393*700637cbSDimitry Andric     OS << " zero-size-array";
394*700637cbSDimitry Andric   else if (isUnknownSizeArray())
395*700637cbSDimitry Andric     OS << " unknown-size-array";
396*700637cbSDimitry Andric 
397*700637cbSDimitry Andric   if (isDummy())
398*700637cbSDimitry Andric     OS << " dummy";
399*700637cbSDimitry Andric   if (IsConstexprUnknown)
400*700637cbSDimitry Andric     OS << " constexpr-unknown";
401*700637cbSDimitry Andric }
402*700637cbSDimitry Andric 
403*700637cbSDimitry Andric /// Dump descriptor, including all valid offsets.
dumpFull(unsigned Offset,unsigned Indent) const404*700637cbSDimitry Andric LLVM_DUMP_METHOD void Descriptor::dumpFull(unsigned Offset,
405*700637cbSDimitry Andric                                            unsigned Indent) const {
406*700637cbSDimitry Andric   unsigned Spaces = Indent * 2;
407*700637cbSDimitry Andric   llvm::raw_ostream &OS = llvm::errs();
408*700637cbSDimitry Andric   OS.indent(Spaces);
409*700637cbSDimitry Andric   dump(OS);
410*700637cbSDimitry Andric   OS << '\n';
411*700637cbSDimitry Andric   OS.indent(Spaces) << "Metadata: " << getMetadataSize() << " bytes\n";
412*700637cbSDimitry Andric   OS.indent(Spaces) << "Size: " << getSize() << " bytes\n";
413*700637cbSDimitry Andric   OS.indent(Spaces) << "AllocSize: " << getAllocSize() << " bytes\n";
414*700637cbSDimitry Andric   Offset += getMetadataSize();
415*700637cbSDimitry Andric   if (isCompositeArray()) {
416*700637cbSDimitry Andric     OS.indent(Spaces) << "Elements: " << getNumElems() << '\n';
417*700637cbSDimitry Andric     unsigned FO = Offset;
418*700637cbSDimitry Andric     for (unsigned I = 0; I != getNumElems(); ++I) {
419*700637cbSDimitry Andric       FO += sizeof(InlineDescriptor);
420*700637cbSDimitry Andric       assert(ElemDesc->getMetadataSize() == 0);
421*700637cbSDimitry Andric       OS.indent(Spaces) << "Element " << I << " offset: " << FO << '\n';
422*700637cbSDimitry Andric       ElemDesc->dumpFull(FO, Indent + 1);
423*700637cbSDimitry Andric 
424*700637cbSDimitry Andric       FO += ElemDesc->getAllocSize();
425*700637cbSDimitry Andric     }
426*700637cbSDimitry Andric   } else if (isRecord()) {
427*700637cbSDimitry Andric     ElemRecord->dump(OS, Indent + 1, Offset);
428*700637cbSDimitry Andric   } else if (isPrimitive()) {
429*700637cbSDimitry Andric   } else {
430*700637cbSDimitry Andric   }
431*700637cbSDimitry Andric 
432*700637cbSDimitry Andric   OS << '\n';
433*700637cbSDimitry Andric }
434*700637cbSDimitry Andric 
dump(llvm::raw_ostream & OS) const435*700637cbSDimitry Andric LLVM_DUMP_METHOD void InlineDescriptor::dump(llvm::raw_ostream &OS) const {
436*700637cbSDimitry Andric   {
437*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
438*700637cbSDimitry Andric     OS << "InlineDescriptor " << (const void *)this << "\n";
439*700637cbSDimitry Andric   }
440*700637cbSDimitry Andric   OS << "Offset: " << Offset << "\n";
441*700637cbSDimitry Andric   OS << "IsConst: " << IsConst << "\n";
442*700637cbSDimitry Andric   OS << "IsInitialized: " << IsInitialized << "\n";
443*700637cbSDimitry Andric   OS << "IsBase: " << IsBase << "\n";
444*700637cbSDimitry Andric   OS << "IsActive: " << IsActive << "\n";
445*700637cbSDimitry Andric   OS << "InUnion: " << InUnion << "\n";
446*700637cbSDimitry Andric   OS << "IsFieldMutable: " << IsFieldMutable << "\n";
447*700637cbSDimitry Andric   OS << "IsArrayElement: " << IsArrayElement << "\n";
448*700637cbSDimitry Andric   OS << "Desc: ";
449*700637cbSDimitry Andric   if (Desc)
450*700637cbSDimitry Andric     Desc->dump(OS);
451*700637cbSDimitry Andric   else
452*700637cbSDimitry Andric     OS << "nullptr";
453*700637cbSDimitry Andric   OS << "\n";
454*700637cbSDimitry Andric }
455*700637cbSDimitry Andric 
dump(llvm::raw_ostream & OS,unsigned Indent) const456*700637cbSDimitry Andric LLVM_DUMP_METHOD void InterpFrame::dump(llvm::raw_ostream &OS,
457*700637cbSDimitry Andric                                         unsigned Indent) const {
458*700637cbSDimitry Andric   unsigned Spaces = Indent * 2;
459*700637cbSDimitry Andric   {
460*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
461*700637cbSDimitry Andric     OS.indent(Spaces);
462*700637cbSDimitry Andric     if (getCallee())
463*700637cbSDimitry Andric       describe(OS);
464*700637cbSDimitry Andric     else
465*700637cbSDimitry Andric       OS << "Frame (Depth: " << getDepth() << ")";
466*700637cbSDimitry Andric     OS << "\n";
467*700637cbSDimitry Andric   }
468*700637cbSDimitry Andric   OS.indent(Spaces) << "Function: " << getFunction();
469*700637cbSDimitry Andric   if (const Function *F = getFunction()) {
470*700637cbSDimitry Andric     OS << " (" << F->getName() << ")";
471*700637cbSDimitry Andric   }
472*700637cbSDimitry Andric   OS << "\n";
473*700637cbSDimitry Andric   OS.indent(Spaces) << "This: " << getThis() << "\n";
474*700637cbSDimitry Andric   OS.indent(Spaces) << "RVO: " << getRVOPtr() << "\n";
475*700637cbSDimitry Andric   OS.indent(Spaces) << "Depth: " << Depth << "\n";
476*700637cbSDimitry Andric   OS.indent(Spaces) << "ArgSize: " << ArgSize << "\n";
477*700637cbSDimitry Andric   OS.indent(Spaces) << "Args: " << (void *)Args << "\n";
478*700637cbSDimitry Andric   OS.indent(Spaces) << "FrameOffset: " << FrameOffset << "\n";
479*700637cbSDimitry Andric   OS.indent(Spaces) << "FrameSize: " << (Func ? Func->getFrameSize() : 0)
480*700637cbSDimitry Andric                     << "\n";
481*700637cbSDimitry Andric 
482*700637cbSDimitry Andric   for (const InterpFrame *F = this->Caller; F; F = F->Caller) {
483*700637cbSDimitry Andric     F->dump(OS, Indent + 1);
484*700637cbSDimitry Andric   }
485*700637cbSDimitry Andric }
486*700637cbSDimitry Andric 
dump(llvm::raw_ostream & OS,unsigned Indentation,unsigned Offset) const487*700637cbSDimitry Andric LLVM_DUMP_METHOD void Record::dump(llvm::raw_ostream &OS, unsigned Indentation,
488*700637cbSDimitry Andric                                    unsigned Offset) const {
489*700637cbSDimitry Andric   unsigned Indent = Indentation * 2;
490*700637cbSDimitry Andric   OS.indent(Indent);
491*700637cbSDimitry Andric   {
492*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BLUE, true});
493*700637cbSDimitry Andric     OS << getName() << "\n";
494*700637cbSDimitry Andric   }
495*700637cbSDimitry Andric 
496*700637cbSDimitry Andric   unsigned I = 0;
497*700637cbSDimitry Andric   for (const Record::Base &B : bases()) {
498*700637cbSDimitry Andric     OS.indent(Indent) << "- Base " << I << ". Offset " << (Offset + B.Offset)
499*700637cbSDimitry Andric                       << "\n";
500*700637cbSDimitry Andric     B.R->dump(OS, Indentation + 1, Offset + B.Offset);
501*700637cbSDimitry Andric     ++I;
502*700637cbSDimitry Andric   }
503*700637cbSDimitry Andric 
504*700637cbSDimitry Andric   I = 0;
505*700637cbSDimitry Andric   for (const Record::Field &F : fields()) {
506*700637cbSDimitry Andric     OS.indent(Indent) << "- Field " << I << ": ";
507*700637cbSDimitry Andric     {
508*700637cbSDimitry Andric       ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_RED, true});
509*700637cbSDimitry Andric       OS << F.Decl->getName();
510*700637cbSDimitry Andric     }
511*700637cbSDimitry Andric     OS << ". Offset " << (Offset + F.Offset) << "\n";
512*700637cbSDimitry Andric     ++I;
513*700637cbSDimitry Andric   }
514*700637cbSDimitry Andric 
515*700637cbSDimitry Andric   I = 0;
516*700637cbSDimitry Andric   for (const Record::Base &B : virtual_bases()) {
517*700637cbSDimitry Andric     OS.indent(Indent) << "- Virtual Base " << I << ". Offset "
518*700637cbSDimitry Andric                       << (Offset + B.Offset) << "\n";
519*700637cbSDimitry Andric     B.R->dump(OS, Indentation + 1, Offset + B.Offset);
520*700637cbSDimitry Andric     ++I;
521*700637cbSDimitry Andric   }
522*700637cbSDimitry Andric }
523*700637cbSDimitry Andric 
dump(llvm::raw_ostream & OS) const524*700637cbSDimitry Andric LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
525*700637cbSDimitry Andric   {
526*700637cbSDimitry Andric     ColorScope SC(OS, true, {llvm::raw_ostream::BRIGHT_BLUE, true});
527*700637cbSDimitry Andric     OS << "Block " << (const void *)this;
528*700637cbSDimitry Andric   }
529*700637cbSDimitry Andric   OS << " (";
530*700637cbSDimitry Andric   Desc->dump(OS);
531*700637cbSDimitry Andric   OS << ")\n";
532*700637cbSDimitry Andric   unsigned NPointers = 0;
533*700637cbSDimitry Andric   for (const Pointer *P = Pointers; P; P = P->Next) {
534*700637cbSDimitry Andric     ++NPointers;
535*700637cbSDimitry Andric   }
536*700637cbSDimitry Andric   OS << "  EvalID: " << EvalID << '\n';
537*700637cbSDimitry Andric   OS << "  DeclID: ";
538*700637cbSDimitry Andric   if (DeclID)
539*700637cbSDimitry Andric     OS << *DeclID << '\n';
540*700637cbSDimitry Andric   else
541*700637cbSDimitry Andric     OS << "-\n";
542*700637cbSDimitry Andric   OS << "  Pointers: " << NPointers << "\n";
543*700637cbSDimitry Andric   OS << "  Dead: " << IsDead << "\n";
544*700637cbSDimitry Andric   OS << "  Static: " << IsStatic << "\n";
545*700637cbSDimitry Andric   OS << "  Extern: " << IsExtern << "\n";
546*700637cbSDimitry Andric   OS << "  Initialized: " << IsInitialized << "\n";
547*700637cbSDimitry Andric   OS << "  Weak: " << IsWeak << "\n";
548*700637cbSDimitry Andric   OS << "  Dynamic: " << IsDynamic << "\n";
549*700637cbSDimitry Andric }
550*700637cbSDimitry Andric 
dump() const551*700637cbSDimitry Andric LLVM_DUMP_METHOD void EvaluationResult::dump() const {
552*700637cbSDimitry Andric   assert(Ctx);
553*700637cbSDimitry Andric   auto &OS = llvm::errs();
554*700637cbSDimitry Andric   const ASTContext &ASTCtx = Ctx->getASTContext();
555*700637cbSDimitry Andric 
556*700637cbSDimitry Andric   switch (Kind) {
557*700637cbSDimitry Andric   case Empty:
558*700637cbSDimitry Andric     OS << "Empty\n";
559*700637cbSDimitry Andric     break;
560*700637cbSDimitry Andric   case RValue:
561*700637cbSDimitry Andric     OS << "RValue: ";
562*700637cbSDimitry Andric     std::get<APValue>(Value).dump(OS, ASTCtx);
563*700637cbSDimitry Andric     break;
564*700637cbSDimitry Andric   case LValue: {
565*700637cbSDimitry Andric     assert(Source);
566*700637cbSDimitry Andric     QualType SourceType;
567*700637cbSDimitry Andric     if (const auto *D = dyn_cast<const Decl *>(Source)) {
568*700637cbSDimitry Andric       if (const auto *VD = dyn_cast<ValueDecl>(D))
569*700637cbSDimitry Andric         SourceType = VD->getType();
570*700637cbSDimitry Andric     } else if (const auto *E = dyn_cast<const Expr *>(Source)) {
571*700637cbSDimitry Andric       SourceType = E->getType();
572*700637cbSDimitry Andric     }
573*700637cbSDimitry Andric 
574*700637cbSDimitry Andric     OS << "LValue: ";
575*700637cbSDimitry Andric     if (const auto *P = std::get_if<Pointer>(&Value))
576*700637cbSDimitry Andric       P->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
577*700637cbSDimitry Andric     else if (const auto *FP = std::get_if<FunctionPointer>(&Value)) // Nope
578*700637cbSDimitry Andric       FP->toAPValue(ASTCtx).printPretty(OS, ASTCtx, SourceType);
579*700637cbSDimitry Andric     OS << "\n";
580*700637cbSDimitry Andric     break;
581*700637cbSDimitry Andric   }
582*700637cbSDimitry Andric   case Invalid:
583*700637cbSDimitry Andric     OS << "Invalid\n";
584*700637cbSDimitry Andric     break;
585*700637cbSDimitry Andric   case Valid:
586*700637cbSDimitry Andric     OS << "Valid\n";
587*700637cbSDimitry Andric     break;
588*700637cbSDimitry Andric   }
589*700637cbSDimitry Andric }
590