1758657e5SAleksandr Urakov //===-- PDBFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===//
2758657e5SAleksandr Urakov //
3ee21a66aSAleksandr Urakov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ee21a66aSAleksandr Urakov // See https://llvm.org/LICENSE.txt for license information.
5ee21a66aSAleksandr Urakov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6758657e5SAleksandr Urakov //
7758657e5SAleksandr Urakov //===----------------------------------------------------------------------===//
8758657e5SAleksandr Urakov 
9758657e5SAleksandr Urakov #include "PdbFPOProgramToDWARFExpression.h"
10758657e5SAleksandr Urakov #include "CodeViewRegisterMapping.h"
11758657e5SAleksandr Urakov 
12758657e5SAleksandr Urakov #include "lldb/Core/StreamBuffer.h"
13758657e5SAleksandr Urakov #include "lldb/Core/dwarf.h"
14758657e5SAleksandr Urakov #include "lldb/Utility/LLDBAssert.h"
15758657e5SAleksandr Urakov #include "lldb/Utility/Stream.h"
16758657e5SAleksandr Urakov #include "llvm/ADT/DenseMap.h"
17758657e5SAleksandr Urakov 
18758657e5SAleksandr Urakov #include "llvm/ADT/StringExtras.h"
19758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/CodeView.h"
20758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/EnumTables.h"
211beeda68SPavel Labath #include "llvm/Support/Casting.h"
22758657e5SAleksandr Urakov 
23758657e5SAleksandr Urakov using namespace lldb;
24758657e5SAleksandr Urakov using namespace lldb_private;
25758657e5SAleksandr Urakov 
26758657e5SAleksandr Urakov namespace {
27758657e5SAleksandr Urakov 
281c4ee160SPavel Labath class NodeAllocator {
291c4ee160SPavel Labath public:
301c4ee160SPavel Labath   template <typename T, typename... Args> T *makeNode(Args &&... args) {
31*85ce053dSPavel Labath     static_assert(std::is_trivially_destructible<T>::value,
32*85ce053dSPavel Labath                   "This object will not be destroyed!");
331c4ee160SPavel Labath     void *new_node_mem = m_alloc.Allocate(sizeof(T), alignof(T));
341c4ee160SPavel Labath     return new (new_node_mem) T(std::forward<Args>(args)...);
351c4ee160SPavel Labath   }
361c4ee160SPavel Labath 
371c4ee160SPavel Labath private:
381c4ee160SPavel Labath   llvm::BumpPtrAllocator m_alloc;
391c4ee160SPavel Labath };
401c4ee160SPavel Labath 
41758657e5SAleksandr Urakov class FPOProgramNode {
42758657e5SAleksandr Urakov public:
43758657e5SAleksandr Urakov   enum Kind {
441c4ee160SPavel Labath     Symbol,
45758657e5SAleksandr Urakov     Register,
46758657e5SAleksandr Urakov     IntegerLiteral,
47758657e5SAleksandr Urakov     BinaryOp,
48758657e5SAleksandr Urakov     UnaryOp,
49758657e5SAleksandr Urakov   };
50758657e5SAleksandr Urakov 
51758657e5SAleksandr Urakov protected:
52758657e5SAleksandr Urakov   FPOProgramNode(Kind kind) : m_token_kind(kind) {}
53758657e5SAleksandr Urakov 
54758657e5SAleksandr Urakov public:
55758657e5SAleksandr Urakov   Kind GetKind() const { return m_token_kind; }
56758657e5SAleksandr Urakov 
57758657e5SAleksandr Urakov private:
58758657e5SAleksandr Urakov   Kind m_token_kind;
59758657e5SAleksandr Urakov };
60758657e5SAleksandr Urakov 
611c4ee160SPavel Labath class FPOProgramNodeSymbol: public FPOProgramNode {
62758657e5SAleksandr Urakov public:
631c4ee160SPavel Labath   FPOProgramNodeSymbol(llvm::StringRef name)
641c4ee160SPavel Labath       : FPOProgramNode(Symbol), m_name(name) {}
65758657e5SAleksandr Urakov 
66758657e5SAleksandr Urakov   llvm::StringRef GetName() const { return m_name; }
67758657e5SAleksandr Urakov 
681beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
691beeda68SPavel Labath     return node->GetKind() == Symbol;
701beeda68SPavel Labath   }
711beeda68SPavel Labath 
72758657e5SAleksandr Urakov private:
73758657e5SAleksandr Urakov   llvm::StringRef m_name;
74758657e5SAleksandr Urakov };
75758657e5SAleksandr Urakov 
761c4ee160SPavel Labath class FPOProgramNodeRegisterRef : public FPOProgramNode {
771c4ee160SPavel Labath public:
781c4ee160SPavel Labath   FPOProgramNodeRegisterRef(uint32_t lldb_reg_num)
791c4ee160SPavel Labath       : FPOProgramNode(Register), m_lldb_reg_num(lldb_reg_num) {}
80758657e5SAleksandr Urakov 
811c4ee160SPavel Labath   uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; }
82758657e5SAleksandr Urakov 
831beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
841beeda68SPavel Labath     return node->GetKind() == Register;
851beeda68SPavel Labath   }
861beeda68SPavel Labath 
871c4ee160SPavel Labath private:
881c4ee160SPavel Labath   uint32_t m_lldb_reg_num;
891c4ee160SPavel Labath };
90758657e5SAleksandr Urakov 
91758657e5SAleksandr Urakov class FPOProgramNodeIntegerLiteral : public FPOProgramNode {
92758657e5SAleksandr Urakov public:
93758657e5SAleksandr Urakov   FPOProgramNodeIntegerLiteral(uint32_t value)
94758657e5SAleksandr Urakov       : FPOProgramNode(IntegerLiteral), m_value(value) {}
95758657e5SAleksandr Urakov 
96758657e5SAleksandr Urakov   uint32_t GetValue() const { return m_value; }
97758657e5SAleksandr Urakov 
981beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
991beeda68SPavel Labath     return node->GetKind() == IntegerLiteral;
1001beeda68SPavel Labath   }
1011beeda68SPavel Labath 
102758657e5SAleksandr Urakov private:
103758657e5SAleksandr Urakov   uint32_t m_value;
104758657e5SAleksandr Urakov };
105758657e5SAleksandr Urakov 
106758657e5SAleksandr Urakov class FPOProgramNodeBinaryOp : public FPOProgramNode {
107758657e5SAleksandr Urakov public:
108758657e5SAleksandr Urakov   enum OpType {
109758657e5SAleksandr Urakov     Plus,
110758657e5SAleksandr Urakov     Minus,
111758657e5SAleksandr Urakov     Align,
112758657e5SAleksandr Urakov   };
113758657e5SAleksandr Urakov 
11494cd0667SPavel Labath   FPOProgramNodeBinaryOp(OpType op_type, FPOProgramNode &left,
11594cd0667SPavel Labath                          FPOProgramNode &right)
11694cd0667SPavel Labath       : FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(&left),
11794cd0667SPavel Labath         m_right(&right) {}
118758657e5SAleksandr Urakov 
119758657e5SAleksandr Urakov   OpType GetOpType() const { return m_op_type; }
120758657e5SAleksandr Urakov 
121758657e5SAleksandr Urakov   const FPOProgramNode *Left() const { return m_left; }
122758657e5SAleksandr Urakov   FPOProgramNode *&Left() { return m_left; }
123758657e5SAleksandr Urakov 
124758657e5SAleksandr Urakov   const FPOProgramNode *Right() const { return m_right; }
125758657e5SAleksandr Urakov   FPOProgramNode *&Right() { return m_right; }
126758657e5SAleksandr Urakov 
1271beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
1281beeda68SPavel Labath     return node->GetKind() == BinaryOp;
1291beeda68SPavel Labath   }
1301beeda68SPavel Labath 
131758657e5SAleksandr Urakov private:
132758657e5SAleksandr Urakov   OpType m_op_type;
133758657e5SAleksandr Urakov   FPOProgramNode *m_left;
134758657e5SAleksandr Urakov   FPOProgramNode *m_right;
135758657e5SAleksandr Urakov };
136758657e5SAleksandr Urakov 
137758657e5SAleksandr Urakov class FPOProgramNodeUnaryOp : public FPOProgramNode {
138758657e5SAleksandr Urakov public:
139758657e5SAleksandr Urakov   enum OpType {
140758657e5SAleksandr Urakov     Deref,
141758657e5SAleksandr Urakov   };
142758657e5SAleksandr Urakov 
14394cd0667SPavel Labath   FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode &operand)
14494cd0667SPavel Labath       : FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(&operand) {}
145758657e5SAleksandr Urakov 
146758657e5SAleksandr Urakov   OpType GetOpType() const { return m_op_type; }
147758657e5SAleksandr Urakov 
148758657e5SAleksandr Urakov   const FPOProgramNode *Operand() const { return m_operand; }
149758657e5SAleksandr Urakov   FPOProgramNode *&Operand() { return m_operand; }
150758657e5SAleksandr Urakov 
1511beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
1521beeda68SPavel Labath     return node->GetKind() == UnaryOp;
1531beeda68SPavel Labath   }
1541beeda68SPavel Labath 
155758657e5SAleksandr Urakov private:
156758657e5SAleksandr Urakov   OpType m_op_type;
157758657e5SAleksandr Urakov   FPOProgramNode *m_operand;
158758657e5SAleksandr Urakov };
159758657e5SAleksandr Urakov 
160*85ce053dSPavel Labath template <typename ResultT = void>
161758657e5SAleksandr Urakov class FPOProgramASTVisitor {
162*85ce053dSPavel Labath protected:
163*85ce053dSPavel Labath   virtual ResultT Visit(FPOProgramNodeBinaryOp &binary,
164*85ce053dSPavel Labath                         FPOProgramNode *&ref) = 0;
165*85ce053dSPavel Labath   virtual ResultT Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&ref) = 0;
166*85ce053dSPavel Labath   virtual ResultT Visit(FPOProgramNodeRegisterRef &reg, FPOProgramNode *&) = 0;
167*85ce053dSPavel Labath   virtual ResultT Visit(FPOProgramNodeIntegerLiteral &integer,
168*85ce053dSPavel Labath                         FPOProgramNode *&) = 0;
169*85ce053dSPavel Labath   virtual ResultT Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) = 0;
170758657e5SAleksandr Urakov 
171*85ce053dSPavel Labath   ResultT Dispatch(FPOProgramNode *&node) {
172*85ce053dSPavel Labath     switch (node->GetKind()) {
173*85ce053dSPavel Labath     case FPOProgramNode::Register:
174*85ce053dSPavel Labath       return Visit(llvm::cast<FPOProgramNodeRegisterRef>(*node), node);
175*85ce053dSPavel Labath     case FPOProgramNode::Symbol:
176*85ce053dSPavel Labath       return Visit(llvm::cast<FPOProgramNodeSymbol>(*node), node);
177*85ce053dSPavel Labath 
178*85ce053dSPavel Labath     case FPOProgramNode::IntegerLiteral:
179*85ce053dSPavel Labath       return Visit(llvm::cast<FPOProgramNodeIntegerLiteral>(*node), node);
180*85ce053dSPavel Labath     case FPOProgramNode::UnaryOp:
181*85ce053dSPavel Labath       return Visit(llvm::cast<FPOProgramNodeUnaryOp>(*node), node);
182*85ce053dSPavel Labath     case FPOProgramNode::BinaryOp:
183*85ce053dSPavel Labath       return Visit(llvm::cast<FPOProgramNodeBinaryOp>(*node), node);
184*85ce053dSPavel Labath     }
185*85ce053dSPavel Labath     llvm_unreachable("Fully covered switch!");
186*85ce053dSPavel Labath   }
187*85ce053dSPavel Labath 
188758657e5SAleksandr Urakov };
189758657e5SAleksandr Urakov 
190*85ce053dSPavel Labath class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor<> {
191758657e5SAleksandr Urakov public:
192*85ce053dSPavel Labath   void Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&) override {
193*85ce053dSPavel Labath     Dispatch(binary.Left());
194*85ce053dSPavel Labath     Dispatch(binary.Right());
195*85ce053dSPavel Labath   }
196*85ce053dSPavel Labath 
197*85ce053dSPavel Labath   void Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&) override {
198*85ce053dSPavel Labath     Dispatch(unary.Operand());
199*85ce053dSPavel Labath   }
200*85ce053dSPavel Labath 
201*85ce053dSPavel Labath   void Visit(FPOProgramNodeRegisterRef &, FPOProgramNode *&) override {}
202*85ce053dSPavel Labath   void Visit(FPOProgramNodeIntegerLiteral &, FPOProgramNode *&) override {}
203*85ce053dSPavel Labath   void Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) override;
204*85ce053dSPavel Labath 
205*85ce053dSPavel Labath   static void Merge(const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
206*85ce053dSPavel Labath                         &dependent_programs,
207*85ce053dSPavel Labath                     FPOProgramNode *&ast) {
208*85ce053dSPavel Labath     FPOProgramASTVisitorMergeDependent(dependent_programs).Dispatch(ast);
209*85ce053dSPavel Labath   }
210*85ce053dSPavel Labath 
211*85ce053dSPavel Labath private:
212758657e5SAleksandr Urakov   FPOProgramASTVisitorMergeDependent(
213758657e5SAleksandr Urakov       const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
214758657e5SAleksandr Urakov           &dependent_programs)
215758657e5SAleksandr Urakov       : m_dependent_programs(dependent_programs) {}
216758657e5SAleksandr Urakov 
217758657e5SAleksandr Urakov   const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
218758657e5SAleksandr Urakov };
219758657e5SAleksandr Urakov 
220*85ce053dSPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeSymbol &symbol,
221*85ce053dSPavel Labath                                                FPOProgramNode *&ref) {
222*85ce053dSPavel Labath 
223*85ce053dSPavel Labath   auto it = m_dependent_programs.find(symbol.GetName());
224*85ce053dSPavel Labath   if (it == m_dependent_programs.end())
225*85ce053dSPavel Labath     return;
226*85ce053dSPavel Labath 
227*85ce053dSPavel Labath   ref = it->second;
228*85ce053dSPavel Labath   Dispatch(ref);
229758657e5SAleksandr Urakov }
230758657e5SAleksandr Urakov 
231*85ce053dSPavel Labath class FPOProgramASTVisitorResolveRegisterRefs
232*85ce053dSPavel Labath     : public FPOProgramASTVisitor<bool> {
233758657e5SAleksandr Urakov public:
234*85ce053dSPavel Labath   static bool Resolve(const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
235*85ce053dSPavel Labath                           &dependent_programs,
236*85ce053dSPavel Labath                       llvm::Triple::ArchType arch_type, NodeAllocator &alloc,
237*85ce053dSPavel Labath                       FPOProgramNode *&ast) {
238*85ce053dSPavel Labath     return FPOProgramASTVisitorResolveRegisterRefs(dependent_programs,
239*85ce053dSPavel Labath                                                    arch_type, alloc)
240*85ce053dSPavel Labath         .Dispatch(ast);
241*85ce053dSPavel Labath   }
242*85ce053dSPavel Labath 
243*85ce053dSPavel Labath   bool Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&) override {
244*85ce053dSPavel Labath     return Dispatch(binary.Left()) && Dispatch(binary.Right());
245*85ce053dSPavel Labath   }
246*85ce053dSPavel Labath 
247*85ce053dSPavel Labath   bool Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&) override {
248*85ce053dSPavel Labath     return Dispatch(unary.Operand());
249*85ce053dSPavel Labath   }
250*85ce053dSPavel Labath 
251*85ce053dSPavel Labath   bool Visit(FPOProgramNodeRegisterRef &, FPOProgramNode *&) override {
252*85ce053dSPavel Labath     return true;
253*85ce053dSPavel Labath   }
254*85ce053dSPavel Labath 
255*85ce053dSPavel Labath   bool Visit(FPOProgramNodeIntegerLiteral &, FPOProgramNode *&) override {
256*85ce053dSPavel Labath     return true;
257*85ce053dSPavel Labath   }
258*85ce053dSPavel Labath 
259*85ce053dSPavel Labath   bool Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) override;
260*85ce053dSPavel Labath 
261*85ce053dSPavel Labath private:
262758657e5SAleksandr Urakov   FPOProgramASTVisitorResolveRegisterRefs(
263758657e5SAleksandr Urakov       const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
264758657e5SAleksandr Urakov           &dependent_programs,
2651c4ee160SPavel Labath       llvm::Triple::ArchType arch_type, NodeAllocator &alloc)
2661c4ee160SPavel Labath       : m_dependent_programs(dependent_programs), m_arch_type(arch_type),
2671c4ee160SPavel Labath         m_alloc(alloc) {}
268758657e5SAleksandr Urakov 
269758657e5SAleksandr Urakov   const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
270758657e5SAleksandr Urakov   llvm::Triple::ArchType m_arch_type;
2711c4ee160SPavel Labath   NodeAllocator &m_alloc;
272758657e5SAleksandr Urakov };
273758657e5SAleksandr Urakov 
2741c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
2751c4ee160SPavel Labath   // lookup register name to get lldb register number
2761c4ee160SPavel Labath   llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
2771c4ee160SPavel Labath       llvm::codeview::getRegisterNames();
2781c4ee160SPavel Labath   auto it = llvm::find_if(
2791c4ee160SPavel Labath       register_names,
2801c4ee160SPavel Labath       [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
2811c4ee160SPavel Labath         return reg_name.compare_lower(register_entry.Name) == 0;
2821c4ee160SPavel Labath       });
283758657e5SAleksandr Urakov 
2841c4ee160SPavel Labath   if (it == register_names.end())
2851c4ee160SPavel Labath     return LLDB_INVALID_REGNUM;
2861c4ee160SPavel Labath 
2871c4ee160SPavel Labath   auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
2881c4ee160SPavel Labath   return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
289758657e5SAleksandr Urakov }
2901c4ee160SPavel Labath 
291*85ce053dSPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::Visit(
292*85ce053dSPavel Labath     FPOProgramNodeSymbol &symbol, FPOProgramNode *&ref) {
2931c4ee160SPavel Labath   // Look up register reference as lvalue in preceding assignments.
294*85ce053dSPavel Labath   auto it = m_dependent_programs.find(symbol.GetName());
2951c4ee160SPavel Labath   if (it != m_dependent_programs.end()) {
2961c4ee160SPavel Labath     // Dependent programs are handled elsewhere.
2971c4ee160SPavel Labath     return true;
2981c4ee160SPavel Labath   }
2991c4ee160SPavel Labath 
3001c4ee160SPavel Labath   uint32_t reg_num =
301*85ce053dSPavel Labath       ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), m_arch_type);
3021c4ee160SPavel Labath 
3031c4ee160SPavel Labath   if (reg_num == LLDB_INVALID_REGNUM)
3041c4ee160SPavel Labath     return false;
3051c4ee160SPavel Labath 
306*85ce053dSPavel Labath   ref = m_alloc.makeNode<FPOProgramNodeRegisterRef>(reg_num);
3071c4ee160SPavel Labath   return true;
308758657e5SAleksandr Urakov }
309758657e5SAleksandr Urakov 
310*85ce053dSPavel Labath class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor<> {
311758657e5SAleksandr Urakov public:
312*85ce053dSPavel Labath   static void Emit(Stream &stream, FPOProgramNode *&ast) {
313*85ce053dSPavel Labath     FPOProgramASTVisitorDWARFCodegen(stream).Dispatch(ast);
314*85ce053dSPavel Labath   }
315*85ce053dSPavel Labath 
316*85ce053dSPavel Labath   void Visit(FPOProgramNodeRegisterRef &reg, FPOProgramNode *&);
317*85ce053dSPavel Labath   void Visit(FPOProgramNodeBinaryOp &binary, FPOProgramNode *&);
318*85ce053dSPavel Labath   void Visit(FPOProgramNodeUnaryOp &unary, FPOProgramNode *&);
319*85ce053dSPavel Labath   void Visit(FPOProgramNodeSymbol &symbol, FPOProgramNode *&) {
320*85ce053dSPavel Labath     llvm_unreachable("Symbols should have been resolved by now!");
321*85ce053dSPavel Labath   }
322*85ce053dSPavel Labath   void Visit(FPOProgramNodeIntegerLiteral &integer, FPOProgramNode *&);
323*85ce053dSPavel Labath 
324*85ce053dSPavel Labath private:
325758657e5SAleksandr Urakov   FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {}
326758657e5SAleksandr Urakov 
327758657e5SAleksandr Urakov   Stream &m_out_stream;
328758657e5SAleksandr Urakov };
329758657e5SAleksandr Urakov 
330*85ce053dSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef &reg,
331*85ce053dSPavel Labath                                              FPOProgramNode *&) {
332758657e5SAleksandr Urakov 
333*85ce053dSPavel Labath   uint32_t reg_num = reg.GetLLDBRegNum();
334758657e5SAleksandr Urakov   lldbassert(reg_num != LLDB_INVALID_REGNUM);
335758657e5SAleksandr Urakov 
336758657e5SAleksandr Urakov   if (reg_num > 31) {
337758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_bregx);
338758657e5SAleksandr Urakov     m_out_stream.PutULEB128(reg_num);
339758657e5SAleksandr Urakov   } else
340758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
341758657e5SAleksandr Urakov 
342758657e5SAleksandr Urakov   m_out_stream.PutSLEB128(0);
343758657e5SAleksandr Urakov }
344758657e5SAleksandr Urakov 
345758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit(
346*85ce053dSPavel Labath     FPOProgramNodeIntegerLiteral &integer, FPOProgramNode *&) {
347*85ce053dSPavel Labath   uint32_t value = integer.GetValue();
348758657e5SAleksandr Urakov   m_out_stream.PutHex8(DW_OP_constu);
349758657e5SAleksandr Urakov   m_out_stream.PutULEB128(value);
350758657e5SAleksandr Urakov }
351758657e5SAleksandr Urakov 
352*85ce053dSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &binary,
353*85ce053dSPavel Labath                                              FPOProgramNode *&) {
354*85ce053dSPavel Labath   Dispatch(binary.Left());
355*85ce053dSPavel Labath   Dispatch(binary.Right());
356758657e5SAleksandr Urakov 
357*85ce053dSPavel Labath   switch (binary.GetOpType()) {
358758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Plus:
359758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_plus);
360758657e5SAleksandr Urakov     // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
361758657e5SAleksandr Urakov     //       if right child node is constant value
362758657e5SAleksandr Urakov     break;
363758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Minus:
364758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
365758657e5SAleksandr Urakov     break;
366758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Align:
367758657e5SAleksandr Urakov     // emit align operator a @ b as
368758657e5SAleksandr Urakov     // a & ~(b - 1)
369758657e5SAleksandr Urakov     // NOTE: implicitly assuming that b is power of 2
370758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_lit1);
371758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
372758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_not);
373758657e5SAleksandr Urakov 
374758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_and);
375758657e5SAleksandr Urakov     break;
376758657e5SAleksandr Urakov   }
377758657e5SAleksandr Urakov }
378758657e5SAleksandr Urakov 
379*85ce053dSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp &unary,
380*85ce053dSPavel Labath                                              FPOProgramNode *&) {
381*85ce053dSPavel Labath   Dispatch(unary.Operand());
382758657e5SAleksandr Urakov 
383*85ce053dSPavel Labath   switch (unary.GetOpType()) {
384758657e5SAleksandr Urakov   case FPOProgramNodeUnaryOp::Deref:
385758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_deref);
386758657e5SAleksandr Urakov     break;
387758657e5SAleksandr Urakov   }
388758657e5SAleksandr Urakov }
389758657e5SAleksandr Urakov 
390758657e5SAleksandr Urakov } // namespace
391758657e5SAleksandr Urakov 
392758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program,
393758657e5SAleksandr Urakov                                             NodeAllocator &alloc,
394758657e5SAleksandr Urakov                                             llvm::StringRef &register_name,
395758657e5SAleksandr Urakov                                             FPOProgramNode *&ast) {
396758657e5SAleksandr Urakov   llvm::SmallVector<llvm::StringRef, 16> tokens;
397758657e5SAleksandr Urakov   llvm::SplitString(program, tokens, " ");
398758657e5SAleksandr Urakov 
399758657e5SAleksandr Urakov   if (tokens.empty())
400758657e5SAleksandr Urakov     return false;
401758657e5SAleksandr Urakov 
402758657e5SAleksandr Urakov   llvm::SmallVector<FPOProgramNode *, 4> eval_stack;
403758657e5SAleksandr Urakov 
404758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNodeBinaryOp::OpType> ops_binary = {
405758657e5SAleksandr Urakov       {"+", FPOProgramNodeBinaryOp::Plus},
406758657e5SAleksandr Urakov       {"-", FPOProgramNodeBinaryOp::Minus},
407758657e5SAleksandr Urakov       {"@", FPOProgramNodeBinaryOp::Align},
408758657e5SAleksandr Urakov   };
409758657e5SAleksandr Urakov 
410758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNodeUnaryOp::OpType> ops_unary = {
411758657e5SAleksandr Urakov       {"^", FPOProgramNodeUnaryOp::Deref},
412758657e5SAleksandr Urakov   };
413758657e5SAleksandr Urakov 
414758657e5SAleksandr Urakov   constexpr llvm::StringLiteral ra_search_keyword = ".raSearch";
415758657e5SAleksandr Urakov 
416758657e5SAleksandr Urakov   // lvalue of assignment is always first token
417758657e5SAleksandr Urakov   // rvalue program goes next
418758657e5SAleksandr Urakov   for (size_t i = 1; i < tokens.size(); ++i) {
419758657e5SAleksandr Urakov     llvm::StringRef cur = tokens[i];
420758657e5SAleksandr Urakov 
421758657e5SAleksandr Urakov     auto ops_binary_it = ops_binary.find(cur);
422758657e5SAleksandr Urakov     if (ops_binary_it != ops_binary.end()) {
423758657e5SAleksandr Urakov       // token is binary operator
424758657e5SAleksandr Urakov       if (eval_stack.size() < 2) {
425758657e5SAleksandr Urakov         return false;
426758657e5SAleksandr Urakov       }
427758657e5SAleksandr Urakov       FPOProgramNode *right = eval_stack.pop_back_val();
428758657e5SAleksandr Urakov       FPOProgramNode *left = eval_stack.pop_back_val();
429758657e5SAleksandr Urakov       FPOProgramNode *node = alloc.makeNode<FPOProgramNodeBinaryOp>(
43094cd0667SPavel Labath           ops_binary_it->second, *left, *right);
431758657e5SAleksandr Urakov       eval_stack.push_back(node);
432758657e5SAleksandr Urakov       continue;
433758657e5SAleksandr Urakov     }
434758657e5SAleksandr Urakov 
435758657e5SAleksandr Urakov     auto ops_unary_it = ops_unary.find(cur);
436758657e5SAleksandr Urakov     if (ops_unary_it != ops_unary.end()) {
437758657e5SAleksandr Urakov       // token is unary operator
438758657e5SAleksandr Urakov       if (eval_stack.empty()) {
439758657e5SAleksandr Urakov         return false;
440758657e5SAleksandr Urakov       }
441758657e5SAleksandr Urakov       FPOProgramNode *operand = eval_stack.pop_back_val();
442758657e5SAleksandr Urakov       FPOProgramNode *node =
44394cd0667SPavel Labath           alloc.makeNode<FPOProgramNodeUnaryOp>(ops_unary_it->second, *operand);
444758657e5SAleksandr Urakov       eval_stack.push_back(node);
445758657e5SAleksandr Urakov       continue;
446758657e5SAleksandr Urakov     }
447758657e5SAleksandr Urakov 
448758657e5SAleksandr Urakov     if (cur.startswith("$")) {
4491c4ee160SPavel Labath       eval_stack.push_back(alloc.makeNode<FPOProgramNodeSymbol>(cur));
450758657e5SAleksandr Urakov       continue;
451758657e5SAleksandr Urakov     }
452758657e5SAleksandr Urakov 
453758657e5SAleksandr Urakov     if (cur == ra_search_keyword) {
454758657e5SAleksandr Urakov       // TODO: .raSearch is unsupported
455758657e5SAleksandr Urakov       return false;
456758657e5SAleksandr Urakov     }
457758657e5SAleksandr Urakov 
458758657e5SAleksandr Urakov     uint32_t value;
459758657e5SAleksandr Urakov     if (!cur.getAsInteger(10, value)) {
460758657e5SAleksandr Urakov       // token is integer literal
461758657e5SAleksandr Urakov       eval_stack.push_back(alloc.makeNode<FPOProgramNodeIntegerLiteral>(value));
462758657e5SAleksandr Urakov       continue;
463758657e5SAleksandr Urakov     }
464758657e5SAleksandr Urakov 
465758657e5SAleksandr Urakov     // unexpected token
466758657e5SAleksandr Urakov     return false;
467758657e5SAleksandr Urakov   }
468758657e5SAleksandr Urakov 
469758657e5SAleksandr Urakov   if (eval_stack.size() != 1) {
470758657e5SAleksandr Urakov     return false;
471758657e5SAleksandr Urakov   }
472758657e5SAleksandr Urakov 
473758657e5SAleksandr Urakov   register_name = tokens[0];
474758657e5SAleksandr Urakov   ast = eval_stack.pop_back_val();
475758657e5SAleksandr Urakov 
476758657e5SAleksandr Urakov   return true;
477758657e5SAleksandr Urakov }
478758657e5SAleksandr Urakov 
479758657e5SAleksandr Urakov static FPOProgramNode *ParseFPOProgram(llvm::StringRef program,
480758657e5SAleksandr Urakov                                        llvm::StringRef register_name,
481758657e5SAleksandr Urakov                                        llvm::Triple::ArchType arch_type,
482758657e5SAleksandr Urakov                                        NodeAllocator &alloc) {
483758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNode *> dependent_programs;
484758657e5SAleksandr Urakov 
485758657e5SAleksandr Urakov   size_t cur = 0;
486758657e5SAleksandr Urakov   while (true) {
487758657e5SAleksandr Urakov     size_t assign_index = program.find('=', cur);
488758657e5SAleksandr Urakov     if (assign_index == llvm::StringRef::npos) {
489758657e5SAleksandr Urakov       llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos);
490758657e5SAleksandr Urakov       if (!tail.trim().empty()) {
491758657e5SAleksandr Urakov         // missing assign operator
492758657e5SAleksandr Urakov         return nullptr;
493758657e5SAleksandr Urakov       }
494758657e5SAleksandr Urakov       break;
495758657e5SAleksandr Urakov     }
496758657e5SAleksandr Urakov     llvm::StringRef assignment_program = program.slice(cur, assign_index);
497758657e5SAleksandr Urakov 
498758657e5SAleksandr Urakov     llvm::StringRef lvalue_name;
499758657e5SAleksandr Urakov     FPOProgramNode *rvalue_ast = nullptr;
500758657e5SAleksandr Urakov     if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name,
501758657e5SAleksandr Urakov                                          rvalue_ast)) {
502758657e5SAleksandr Urakov       return nullptr;
503758657e5SAleksandr Urakov     }
504758657e5SAleksandr Urakov 
505758657e5SAleksandr Urakov     lldbassert(rvalue_ast);
506758657e5SAleksandr Urakov 
507758657e5SAleksandr Urakov     // check & resolve assignment program
508*85ce053dSPavel Labath     if (!FPOProgramASTVisitorResolveRegisterRefs::Resolve(
509*85ce053dSPavel Labath             dependent_programs, arch_type, alloc, rvalue_ast))
510758657e5SAleksandr Urakov       return nullptr;
511758657e5SAleksandr Urakov 
512758657e5SAleksandr Urakov     if (lvalue_name == register_name) {
513758657e5SAleksandr Urakov       // found target assignment program - no need to parse further
514758657e5SAleksandr Urakov 
515758657e5SAleksandr Urakov       // emplace valid dependent subtrees to make target assignment independent
516758657e5SAleksandr Urakov       // from predecessors
517*85ce053dSPavel Labath       FPOProgramASTVisitorMergeDependent::Merge(dependent_programs, rvalue_ast);
518758657e5SAleksandr Urakov 
519758657e5SAleksandr Urakov       return rvalue_ast;
520758657e5SAleksandr Urakov     }
521758657e5SAleksandr Urakov 
522758657e5SAleksandr Urakov     dependent_programs[lvalue_name] = rvalue_ast;
523758657e5SAleksandr Urakov     cur = assign_index + 1;
524758657e5SAleksandr Urakov   }
525758657e5SAleksandr Urakov 
526758657e5SAleksandr Urakov   return nullptr;
527758657e5SAleksandr Urakov }
528758657e5SAleksandr Urakov 
529758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
530758657e5SAleksandr Urakov     llvm::StringRef program, llvm::StringRef register_name,
531758657e5SAleksandr Urakov     llvm::Triple::ArchType arch_type, Stream &stream) {
532758657e5SAleksandr Urakov   NodeAllocator node_alloc;
533758657e5SAleksandr Urakov   FPOProgramNode *target_program =
534758657e5SAleksandr Urakov       ParseFPOProgram(program, register_name, arch_type, node_alloc);
535758657e5SAleksandr Urakov   if (target_program == nullptr) {
536758657e5SAleksandr Urakov     return false;
537758657e5SAleksandr Urakov   }
538758657e5SAleksandr Urakov 
539*85ce053dSPavel Labath   FPOProgramASTVisitorDWARFCodegen::Emit(stream, target_program);
540758657e5SAleksandr Urakov   return true;
541758657e5SAleksandr Urakov }
542