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"
21*1beeda68SPavel 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 
28758657e5SAleksandr Urakov class FPOProgramNode;
29758657e5SAleksandr Urakov class FPOProgramASTVisitor;
30758657e5SAleksandr Urakov 
311c4ee160SPavel Labath class NodeAllocator {
321c4ee160SPavel Labath public:
331c4ee160SPavel Labath   template <typename T, typename... Args> T *makeNode(Args &&... args) {
341c4ee160SPavel Labath     void *new_node_mem = m_alloc.Allocate(sizeof(T), alignof(T));
351c4ee160SPavel Labath     return new (new_node_mem) T(std::forward<Args>(args)...);
361c4ee160SPavel Labath   }
371c4ee160SPavel Labath 
381c4ee160SPavel Labath private:
391c4ee160SPavel Labath   llvm::BumpPtrAllocator m_alloc;
401c4ee160SPavel Labath };
411c4ee160SPavel Labath 
42758657e5SAleksandr Urakov class FPOProgramNode {
43758657e5SAleksandr Urakov public:
44758657e5SAleksandr Urakov   enum Kind {
451c4ee160SPavel Labath     Symbol,
46758657e5SAleksandr Urakov     Register,
47758657e5SAleksandr Urakov     IntegerLiteral,
48758657e5SAleksandr Urakov     BinaryOp,
49758657e5SAleksandr Urakov     UnaryOp,
50758657e5SAleksandr Urakov   };
51758657e5SAleksandr Urakov 
52758657e5SAleksandr Urakov protected:
53758657e5SAleksandr Urakov   FPOProgramNode(Kind kind) : m_token_kind(kind) {}
54758657e5SAleksandr Urakov 
55758657e5SAleksandr Urakov public:
56758657e5SAleksandr Urakov   virtual ~FPOProgramNode() = default;
5794cd0667SPavel Labath   virtual void Accept(FPOProgramASTVisitor &visitor) = 0;
58758657e5SAleksandr Urakov 
59758657e5SAleksandr Urakov   Kind GetKind() const { return m_token_kind; }
60758657e5SAleksandr Urakov 
61758657e5SAleksandr Urakov private:
62758657e5SAleksandr Urakov   Kind m_token_kind;
63758657e5SAleksandr Urakov };
64758657e5SAleksandr Urakov 
651c4ee160SPavel Labath class FPOProgramNodeSymbol: public FPOProgramNode {
66758657e5SAleksandr Urakov public:
671c4ee160SPavel Labath   FPOProgramNodeSymbol(llvm::StringRef name)
681c4ee160SPavel Labath       : FPOProgramNode(Symbol), m_name(name) {}
69758657e5SAleksandr Urakov 
7094cd0667SPavel Labath   void Accept(FPOProgramASTVisitor &visitor) override;
71758657e5SAleksandr Urakov 
72758657e5SAleksandr Urakov   llvm::StringRef GetName() const { return m_name; }
73758657e5SAleksandr Urakov 
74*1beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
75*1beeda68SPavel Labath     return node->GetKind() == Symbol;
76*1beeda68SPavel Labath   }
77*1beeda68SPavel Labath 
78758657e5SAleksandr Urakov private:
79758657e5SAleksandr Urakov   llvm::StringRef m_name;
80758657e5SAleksandr Urakov };
81758657e5SAleksandr Urakov 
821c4ee160SPavel Labath class FPOProgramNodeRegisterRef : public FPOProgramNode {
831c4ee160SPavel Labath public:
841c4ee160SPavel Labath   FPOProgramNodeRegisterRef(uint32_t lldb_reg_num)
851c4ee160SPavel Labath       : FPOProgramNode(Register), m_lldb_reg_num(lldb_reg_num) {}
86758657e5SAleksandr Urakov 
8794cd0667SPavel Labath   void Accept(FPOProgramASTVisitor &visitor) override;
88758657e5SAleksandr Urakov 
891c4ee160SPavel Labath   uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; }
90758657e5SAleksandr Urakov 
91*1beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
92*1beeda68SPavel Labath     return node->GetKind() == Register;
93*1beeda68SPavel Labath   }
94*1beeda68SPavel Labath 
951c4ee160SPavel Labath private:
961c4ee160SPavel Labath   uint32_t m_lldb_reg_num;
971c4ee160SPavel Labath };
98758657e5SAleksandr Urakov 
99758657e5SAleksandr Urakov class FPOProgramNodeIntegerLiteral : public FPOProgramNode {
100758657e5SAleksandr Urakov public:
101758657e5SAleksandr Urakov   FPOProgramNodeIntegerLiteral(uint32_t value)
102758657e5SAleksandr Urakov       : FPOProgramNode(IntegerLiteral), m_value(value) {}
103758657e5SAleksandr Urakov 
10494cd0667SPavel Labath   void Accept(FPOProgramASTVisitor &visitor) override;
105758657e5SAleksandr Urakov 
106758657e5SAleksandr Urakov   uint32_t GetValue() const { return m_value; }
107758657e5SAleksandr Urakov 
108*1beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
109*1beeda68SPavel Labath     return node->GetKind() == IntegerLiteral;
110*1beeda68SPavel Labath   }
111*1beeda68SPavel Labath 
112758657e5SAleksandr Urakov private:
113758657e5SAleksandr Urakov   uint32_t m_value;
114758657e5SAleksandr Urakov };
115758657e5SAleksandr Urakov 
116758657e5SAleksandr Urakov class FPOProgramNodeBinaryOp : public FPOProgramNode {
117758657e5SAleksandr Urakov public:
118758657e5SAleksandr Urakov   enum OpType {
119758657e5SAleksandr Urakov     Plus,
120758657e5SAleksandr Urakov     Minus,
121758657e5SAleksandr Urakov     Align,
122758657e5SAleksandr Urakov   };
123758657e5SAleksandr Urakov 
12494cd0667SPavel Labath   FPOProgramNodeBinaryOp(OpType op_type, FPOProgramNode &left,
12594cd0667SPavel Labath                          FPOProgramNode &right)
12694cd0667SPavel Labath       : FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(&left),
12794cd0667SPavel Labath         m_right(&right) {}
128758657e5SAleksandr Urakov 
12994cd0667SPavel Labath   void Accept(FPOProgramASTVisitor &visitor) override;
130758657e5SAleksandr Urakov 
131758657e5SAleksandr Urakov   OpType GetOpType() const { return m_op_type; }
132758657e5SAleksandr Urakov 
133758657e5SAleksandr Urakov   const FPOProgramNode *Left() const { return m_left; }
134758657e5SAleksandr Urakov   FPOProgramNode *&Left() { return m_left; }
135758657e5SAleksandr Urakov 
136758657e5SAleksandr Urakov   const FPOProgramNode *Right() const { return m_right; }
137758657e5SAleksandr Urakov   FPOProgramNode *&Right() { return m_right; }
138758657e5SAleksandr Urakov 
139*1beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
140*1beeda68SPavel Labath     return node->GetKind() == BinaryOp;
141*1beeda68SPavel Labath   }
142*1beeda68SPavel Labath 
143758657e5SAleksandr Urakov private:
144758657e5SAleksandr Urakov   OpType m_op_type;
145758657e5SAleksandr Urakov   FPOProgramNode *m_left;
146758657e5SAleksandr Urakov   FPOProgramNode *m_right;
147758657e5SAleksandr Urakov };
148758657e5SAleksandr Urakov 
149758657e5SAleksandr Urakov class FPOProgramNodeUnaryOp : public FPOProgramNode {
150758657e5SAleksandr Urakov public:
151758657e5SAleksandr Urakov   enum OpType {
152758657e5SAleksandr Urakov     Deref,
153758657e5SAleksandr Urakov   };
154758657e5SAleksandr Urakov 
15594cd0667SPavel Labath   FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode &operand)
15694cd0667SPavel Labath       : FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(&operand) {}
157758657e5SAleksandr Urakov 
15894cd0667SPavel Labath   void Accept(FPOProgramASTVisitor &visitor) override;
159758657e5SAleksandr Urakov 
160758657e5SAleksandr Urakov   OpType GetOpType() const { return m_op_type; }
161758657e5SAleksandr Urakov 
162758657e5SAleksandr Urakov   const FPOProgramNode *Operand() const { return m_operand; }
163758657e5SAleksandr Urakov   FPOProgramNode *&Operand() { return m_operand; }
164758657e5SAleksandr Urakov 
165*1beeda68SPavel Labath   static bool classof(const FPOProgramNode *node) {
166*1beeda68SPavel Labath     return node->GetKind() == UnaryOp;
167*1beeda68SPavel Labath   }
168*1beeda68SPavel Labath 
169758657e5SAleksandr Urakov private:
170758657e5SAleksandr Urakov   OpType m_op_type;
171758657e5SAleksandr Urakov   FPOProgramNode *m_operand;
172758657e5SAleksandr Urakov };
173758657e5SAleksandr Urakov 
174758657e5SAleksandr Urakov class FPOProgramASTVisitor {
175758657e5SAleksandr Urakov public:
176758657e5SAleksandr Urakov   virtual ~FPOProgramASTVisitor() = default;
177758657e5SAleksandr Urakov 
17894cd0667SPavel Labath   virtual void Visit(FPOProgramNodeSymbol &node) {}
17994cd0667SPavel Labath   virtual void Visit(FPOProgramNodeRegisterRef &node) {}
18094cd0667SPavel Labath   virtual void Visit(FPOProgramNodeIntegerLiteral &node) {}
18194cd0667SPavel Labath   virtual void Visit(FPOProgramNodeBinaryOp &node) {}
18294cd0667SPavel Labath   virtual void Visit(FPOProgramNodeUnaryOp &node) {}
183758657e5SAleksandr Urakov };
184758657e5SAleksandr Urakov 
18594cd0667SPavel Labath void FPOProgramNodeSymbol::Accept(FPOProgramASTVisitor &visitor) {
18694cd0667SPavel Labath   visitor.Visit(*this);
1871c4ee160SPavel Labath }
1881c4ee160SPavel Labath 
18994cd0667SPavel Labath void FPOProgramNodeRegisterRef::Accept(FPOProgramASTVisitor &visitor) {
19094cd0667SPavel Labath   visitor.Visit(*this);
191758657e5SAleksandr Urakov }
192758657e5SAleksandr Urakov 
19394cd0667SPavel Labath void FPOProgramNodeIntegerLiteral::Accept(FPOProgramASTVisitor &visitor) {
19494cd0667SPavel Labath   visitor.Visit(*this);
195758657e5SAleksandr Urakov }
196758657e5SAleksandr Urakov 
19794cd0667SPavel Labath void FPOProgramNodeBinaryOp::Accept(FPOProgramASTVisitor &visitor) {
19894cd0667SPavel Labath   visitor.Visit(*this);
199758657e5SAleksandr Urakov }
200758657e5SAleksandr Urakov 
20194cd0667SPavel Labath void FPOProgramNodeUnaryOp::Accept(FPOProgramASTVisitor &visitor) {
20294cd0667SPavel Labath   visitor.Visit(*this);
203758657e5SAleksandr Urakov }
204758657e5SAleksandr Urakov 
205758657e5SAleksandr Urakov class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor {
206758657e5SAleksandr Urakov public:
207758657e5SAleksandr Urakov   FPOProgramASTVisitorMergeDependent(
208758657e5SAleksandr Urakov       const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
209758657e5SAleksandr Urakov           &dependent_programs)
210758657e5SAleksandr Urakov       : m_dependent_programs(dependent_programs) {}
211758657e5SAleksandr Urakov 
212758657e5SAleksandr Urakov   void Merge(FPOProgramNode *&node_ref);
213758657e5SAleksandr Urakov 
214758657e5SAleksandr Urakov private:
21594cd0667SPavel Labath   void Visit(FPOProgramNodeBinaryOp &node) override;
21694cd0667SPavel Labath   void Visit(FPOProgramNodeUnaryOp &node) override;
217758657e5SAleksandr Urakov 
218758657e5SAleksandr Urakov   void TryReplace(FPOProgramNode *&node_ref) const;
219758657e5SAleksandr Urakov 
220758657e5SAleksandr Urakov private:
221758657e5SAleksandr Urakov   const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
222758657e5SAleksandr Urakov };
223758657e5SAleksandr Urakov 
224758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::Merge(FPOProgramNode *&node_ref) {
225758657e5SAleksandr Urakov   TryReplace(node_ref);
22694cd0667SPavel Labath   node_ref->Accept(*this);
227758657e5SAleksandr Urakov }
228758657e5SAleksandr Urakov 
22994cd0667SPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeBinaryOp &node) {
23094cd0667SPavel Labath   Merge(node.Left());
23194cd0667SPavel Labath   Merge(node.Right());
232758657e5SAleksandr Urakov }
23394cd0667SPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeUnaryOp &node) {
23494cd0667SPavel Labath   Merge(node.Operand());
235758657e5SAleksandr Urakov }
236758657e5SAleksandr Urakov 
237758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::TryReplace(
238758657e5SAleksandr Urakov     FPOProgramNode *&node_ref) const {
239758657e5SAleksandr Urakov 
240*1beeda68SPavel Labath   while (auto *symbol = llvm::dyn_cast<FPOProgramNodeSymbol>(node_ref)) {
241*1beeda68SPavel Labath     auto it = m_dependent_programs.find(symbol->GetName());
242758657e5SAleksandr Urakov     if (it == m_dependent_programs.end()) {
243758657e5SAleksandr Urakov       break;
244758657e5SAleksandr Urakov     }
245758657e5SAleksandr Urakov 
246758657e5SAleksandr Urakov     node_ref = it->second;
247758657e5SAleksandr Urakov   }
248758657e5SAleksandr Urakov }
249758657e5SAleksandr Urakov 
250758657e5SAleksandr Urakov class FPOProgramASTVisitorResolveRegisterRefs : public FPOProgramASTVisitor {
251758657e5SAleksandr Urakov public:
252758657e5SAleksandr Urakov   FPOProgramASTVisitorResolveRegisterRefs(
253758657e5SAleksandr Urakov       const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
254758657e5SAleksandr Urakov           &dependent_programs,
2551c4ee160SPavel Labath       llvm::Triple::ArchType arch_type, NodeAllocator &alloc)
2561c4ee160SPavel Labath       : m_dependent_programs(dependent_programs), m_arch_type(arch_type),
2571c4ee160SPavel Labath         m_alloc(alloc) {}
258758657e5SAleksandr Urakov 
2591c4ee160SPavel Labath   bool Resolve(FPOProgramNode *&program);
260758657e5SAleksandr Urakov 
261758657e5SAleksandr Urakov private:
26294cd0667SPavel Labath   void Visit(FPOProgramNodeBinaryOp &node) override;
26394cd0667SPavel Labath   void Visit(FPOProgramNodeUnaryOp &node) override;
264758657e5SAleksandr Urakov 
2651c4ee160SPavel Labath   bool TryReplace(FPOProgramNode *&node_ref);
2661c4ee160SPavel Labath 
267758657e5SAleksandr Urakov   const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
268758657e5SAleksandr Urakov   llvm::Triple::ArchType m_arch_type;
2691c4ee160SPavel Labath   NodeAllocator &m_alloc;
270758657e5SAleksandr Urakov   bool m_no_error_flag = true;
271758657e5SAleksandr Urakov };
272758657e5SAleksandr Urakov 
2731c4ee160SPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::Resolve(FPOProgramNode *&program) {
2741c4ee160SPavel Labath   if (!TryReplace(program))
2751c4ee160SPavel Labath     return false;
27694cd0667SPavel Labath   program->Accept(*this);
277758657e5SAleksandr Urakov   return m_no_error_flag;
278758657e5SAleksandr Urakov }
279758657e5SAleksandr Urakov 
2801c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
2811c4ee160SPavel Labath   // lookup register name to get lldb register number
2821c4ee160SPavel Labath   llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
2831c4ee160SPavel Labath       llvm::codeview::getRegisterNames();
2841c4ee160SPavel Labath   auto it = llvm::find_if(
2851c4ee160SPavel Labath       register_names,
2861c4ee160SPavel Labath       [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
2871c4ee160SPavel Labath         return reg_name.compare_lower(register_entry.Name) == 0;
2881c4ee160SPavel Labath       });
289758657e5SAleksandr Urakov 
2901c4ee160SPavel Labath   if (it == register_names.end())
2911c4ee160SPavel Labath     return LLDB_INVALID_REGNUM;
2921c4ee160SPavel Labath 
2931c4ee160SPavel Labath   auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
2941c4ee160SPavel Labath   return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
295758657e5SAleksandr Urakov }
2961c4ee160SPavel Labath 
2971c4ee160SPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::TryReplace(
2981c4ee160SPavel Labath     FPOProgramNode *&node_ref) {
299*1beeda68SPavel Labath   auto *symbol = llvm::dyn_cast<FPOProgramNodeSymbol>(node_ref);
300*1beeda68SPavel Labath   if (!symbol)
3011c4ee160SPavel Labath     return true;
3021c4ee160SPavel Labath 
3031c4ee160SPavel Labath   // Look up register reference as lvalue in preceding assignments.
3041c4ee160SPavel Labath   auto it = m_dependent_programs.find(symbol->GetName());
3051c4ee160SPavel Labath   if (it != m_dependent_programs.end()) {
3061c4ee160SPavel Labath     // Dependent programs are handled elsewhere.
3071c4ee160SPavel Labath     return true;
3081c4ee160SPavel Labath   }
3091c4ee160SPavel Labath 
3101c4ee160SPavel Labath   uint32_t reg_num =
3111c4ee160SPavel Labath       ResolveLLDBRegisterNum(symbol->GetName().drop_front(1), m_arch_type);
3121c4ee160SPavel Labath 
3131c4ee160SPavel Labath   if (reg_num == LLDB_INVALID_REGNUM)
3141c4ee160SPavel Labath     return false;
3151c4ee160SPavel Labath 
3161c4ee160SPavel Labath   node_ref = m_alloc.makeNode<FPOProgramNodeRegisterRef>(reg_num);
3171c4ee160SPavel Labath   return true;
318758657e5SAleksandr Urakov }
319758657e5SAleksandr Urakov 
320758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit(
32194cd0667SPavel Labath     FPOProgramNodeBinaryOp &node) {
32294cd0667SPavel Labath   m_no_error_flag = Resolve(node.Left()) && Resolve(node.Right());
323758657e5SAleksandr Urakov }
324758657e5SAleksandr Urakov 
325758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit(
32694cd0667SPavel Labath     FPOProgramNodeUnaryOp &node) {
32794cd0667SPavel Labath   m_no_error_flag = Resolve(node.Operand());
328758657e5SAleksandr Urakov }
329758657e5SAleksandr Urakov 
330758657e5SAleksandr Urakov class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor {
331758657e5SAleksandr Urakov public:
332758657e5SAleksandr Urakov   FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {}
333758657e5SAleksandr Urakov 
33494cd0667SPavel Labath   void Emit(FPOProgramNode &program);
335758657e5SAleksandr Urakov 
336758657e5SAleksandr Urakov private:
33794cd0667SPavel Labath   void Visit(FPOProgramNodeRegisterRef &node) override;
33894cd0667SPavel Labath   void Visit(FPOProgramNodeIntegerLiteral &node) override;
33994cd0667SPavel Labath   void Visit(FPOProgramNodeBinaryOp &node) override;
34094cd0667SPavel Labath   void Visit(FPOProgramNodeUnaryOp &node) override;
341758657e5SAleksandr Urakov 
342758657e5SAleksandr Urakov private:
343758657e5SAleksandr Urakov   Stream &m_out_stream;
344758657e5SAleksandr Urakov };
345758657e5SAleksandr Urakov 
34694cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Emit(FPOProgramNode &program) {
34794cd0667SPavel Labath   program.Accept(*this);
348758657e5SAleksandr Urakov }
349758657e5SAleksandr Urakov 
35094cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef &node) {
351758657e5SAleksandr Urakov 
35294cd0667SPavel Labath   uint32_t reg_num = node.GetLLDBRegNum();
353758657e5SAleksandr Urakov   lldbassert(reg_num != LLDB_INVALID_REGNUM);
354758657e5SAleksandr Urakov 
355758657e5SAleksandr Urakov   if (reg_num > 31) {
356758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_bregx);
357758657e5SAleksandr Urakov     m_out_stream.PutULEB128(reg_num);
358758657e5SAleksandr Urakov   } else
359758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
360758657e5SAleksandr Urakov 
361758657e5SAleksandr Urakov   m_out_stream.PutSLEB128(0);
362758657e5SAleksandr Urakov }
363758657e5SAleksandr Urakov 
364758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit(
36594cd0667SPavel Labath     FPOProgramNodeIntegerLiteral &node) {
36694cd0667SPavel Labath   uint32_t value = node.GetValue();
367758657e5SAleksandr Urakov   m_out_stream.PutHex8(DW_OP_constu);
368758657e5SAleksandr Urakov   m_out_stream.PutULEB128(value);
369758657e5SAleksandr Urakov }
370758657e5SAleksandr Urakov 
37194cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp &node) {
372758657e5SAleksandr Urakov 
37394cd0667SPavel Labath   Emit(*node.Left());
37494cd0667SPavel Labath   Emit(*node.Right());
375758657e5SAleksandr Urakov 
37694cd0667SPavel Labath   switch (node.GetOpType()) {
377758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Plus:
378758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_plus);
379758657e5SAleksandr Urakov     // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
380758657e5SAleksandr Urakov     //       if right child node is constant value
381758657e5SAleksandr Urakov     break;
382758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Minus:
383758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
384758657e5SAleksandr Urakov     break;
385758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Align:
386758657e5SAleksandr Urakov     // emit align operator a @ b as
387758657e5SAleksandr Urakov     // a & ~(b - 1)
388758657e5SAleksandr Urakov     // NOTE: implicitly assuming that b is power of 2
389758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_lit1);
390758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
391758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_not);
392758657e5SAleksandr Urakov 
393758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_and);
394758657e5SAleksandr Urakov     break;
395758657e5SAleksandr Urakov   }
396758657e5SAleksandr Urakov }
397758657e5SAleksandr Urakov 
39894cd0667SPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp &node) {
39994cd0667SPavel Labath   Emit(*node.Operand());
400758657e5SAleksandr Urakov 
40194cd0667SPavel Labath   switch (node.GetOpType()) {
402758657e5SAleksandr Urakov   case FPOProgramNodeUnaryOp::Deref:
403758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_deref);
404758657e5SAleksandr Urakov     break;
405758657e5SAleksandr Urakov   }
406758657e5SAleksandr Urakov }
407758657e5SAleksandr Urakov 
408758657e5SAleksandr Urakov } // namespace
409758657e5SAleksandr Urakov 
410758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program,
411758657e5SAleksandr Urakov                                             NodeAllocator &alloc,
412758657e5SAleksandr Urakov                                             llvm::StringRef &register_name,
413758657e5SAleksandr Urakov                                             FPOProgramNode *&ast) {
414758657e5SAleksandr Urakov   llvm::SmallVector<llvm::StringRef, 16> tokens;
415758657e5SAleksandr Urakov   llvm::SplitString(program, tokens, " ");
416758657e5SAleksandr Urakov 
417758657e5SAleksandr Urakov   if (tokens.empty())
418758657e5SAleksandr Urakov     return false;
419758657e5SAleksandr Urakov 
420758657e5SAleksandr Urakov   llvm::SmallVector<FPOProgramNode *, 4> eval_stack;
421758657e5SAleksandr Urakov 
422758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNodeBinaryOp::OpType> ops_binary = {
423758657e5SAleksandr Urakov       {"+", FPOProgramNodeBinaryOp::Plus},
424758657e5SAleksandr Urakov       {"-", FPOProgramNodeBinaryOp::Minus},
425758657e5SAleksandr Urakov       {"@", FPOProgramNodeBinaryOp::Align},
426758657e5SAleksandr Urakov   };
427758657e5SAleksandr Urakov 
428758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNodeUnaryOp::OpType> ops_unary = {
429758657e5SAleksandr Urakov       {"^", FPOProgramNodeUnaryOp::Deref},
430758657e5SAleksandr Urakov   };
431758657e5SAleksandr Urakov 
432758657e5SAleksandr Urakov   constexpr llvm::StringLiteral ra_search_keyword = ".raSearch";
433758657e5SAleksandr Urakov 
434758657e5SAleksandr Urakov   // lvalue of assignment is always first token
435758657e5SAleksandr Urakov   // rvalue program goes next
436758657e5SAleksandr Urakov   for (size_t i = 1; i < tokens.size(); ++i) {
437758657e5SAleksandr Urakov     llvm::StringRef cur = tokens[i];
438758657e5SAleksandr Urakov 
439758657e5SAleksandr Urakov     auto ops_binary_it = ops_binary.find(cur);
440758657e5SAleksandr Urakov     if (ops_binary_it != ops_binary.end()) {
441758657e5SAleksandr Urakov       // token is binary operator
442758657e5SAleksandr Urakov       if (eval_stack.size() < 2) {
443758657e5SAleksandr Urakov         return false;
444758657e5SAleksandr Urakov       }
445758657e5SAleksandr Urakov       FPOProgramNode *right = eval_stack.pop_back_val();
446758657e5SAleksandr Urakov       FPOProgramNode *left = eval_stack.pop_back_val();
447758657e5SAleksandr Urakov       FPOProgramNode *node = alloc.makeNode<FPOProgramNodeBinaryOp>(
44894cd0667SPavel Labath           ops_binary_it->second, *left, *right);
449758657e5SAleksandr Urakov       eval_stack.push_back(node);
450758657e5SAleksandr Urakov       continue;
451758657e5SAleksandr Urakov     }
452758657e5SAleksandr Urakov 
453758657e5SAleksandr Urakov     auto ops_unary_it = ops_unary.find(cur);
454758657e5SAleksandr Urakov     if (ops_unary_it != ops_unary.end()) {
455758657e5SAleksandr Urakov       // token is unary operator
456758657e5SAleksandr Urakov       if (eval_stack.empty()) {
457758657e5SAleksandr Urakov         return false;
458758657e5SAleksandr Urakov       }
459758657e5SAleksandr Urakov       FPOProgramNode *operand = eval_stack.pop_back_val();
460758657e5SAleksandr Urakov       FPOProgramNode *node =
46194cd0667SPavel Labath           alloc.makeNode<FPOProgramNodeUnaryOp>(ops_unary_it->second, *operand);
462758657e5SAleksandr Urakov       eval_stack.push_back(node);
463758657e5SAleksandr Urakov       continue;
464758657e5SAleksandr Urakov     }
465758657e5SAleksandr Urakov 
466758657e5SAleksandr Urakov     if (cur.startswith("$")) {
4671c4ee160SPavel Labath       eval_stack.push_back(alloc.makeNode<FPOProgramNodeSymbol>(cur));
468758657e5SAleksandr Urakov       continue;
469758657e5SAleksandr Urakov     }
470758657e5SAleksandr Urakov 
471758657e5SAleksandr Urakov     if (cur == ra_search_keyword) {
472758657e5SAleksandr Urakov       // TODO: .raSearch is unsupported
473758657e5SAleksandr Urakov       return false;
474758657e5SAleksandr Urakov     }
475758657e5SAleksandr Urakov 
476758657e5SAleksandr Urakov     uint32_t value;
477758657e5SAleksandr Urakov     if (!cur.getAsInteger(10, value)) {
478758657e5SAleksandr Urakov       // token is integer literal
479758657e5SAleksandr Urakov       eval_stack.push_back(alloc.makeNode<FPOProgramNodeIntegerLiteral>(value));
480758657e5SAleksandr Urakov       continue;
481758657e5SAleksandr Urakov     }
482758657e5SAleksandr Urakov 
483758657e5SAleksandr Urakov     // unexpected token
484758657e5SAleksandr Urakov     return false;
485758657e5SAleksandr Urakov   }
486758657e5SAleksandr Urakov 
487758657e5SAleksandr Urakov   if (eval_stack.size() != 1) {
488758657e5SAleksandr Urakov     return false;
489758657e5SAleksandr Urakov   }
490758657e5SAleksandr Urakov 
491758657e5SAleksandr Urakov   register_name = tokens[0];
492758657e5SAleksandr Urakov   ast = eval_stack.pop_back_val();
493758657e5SAleksandr Urakov 
494758657e5SAleksandr Urakov   return true;
495758657e5SAleksandr Urakov }
496758657e5SAleksandr Urakov 
497758657e5SAleksandr Urakov static FPOProgramNode *ParseFPOProgram(llvm::StringRef program,
498758657e5SAleksandr Urakov                                        llvm::StringRef register_name,
499758657e5SAleksandr Urakov                                        llvm::Triple::ArchType arch_type,
500758657e5SAleksandr Urakov                                        NodeAllocator &alloc) {
501758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNode *> dependent_programs;
502758657e5SAleksandr Urakov 
503758657e5SAleksandr Urakov   size_t cur = 0;
504758657e5SAleksandr Urakov   while (true) {
505758657e5SAleksandr Urakov     size_t assign_index = program.find('=', cur);
506758657e5SAleksandr Urakov     if (assign_index == llvm::StringRef::npos) {
507758657e5SAleksandr Urakov       llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos);
508758657e5SAleksandr Urakov       if (!tail.trim().empty()) {
509758657e5SAleksandr Urakov         // missing assign operator
510758657e5SAleksandr Urakov         return nullptr;
511758657e5SAleksandr Urakov       }
512758657e5SAleksandr Urakov       break;
513758657e5SAleksandr Urakov     }
514758657e5SAleksandr Urakov     llvm::StringRef assignment_program = program.slice(cur, assign_index);
515758657e5SAleksandr Urakov 
516758657e5SAleksandr Urakov     llvm::StringRef lvalue_name;
517758657e5SAleksandr Urakov     FPOProgramNode *rvalue_ast = nullptr;
518758657e5SAleksandr Urakov     if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name,
519758657e5SAleksandr Urakov                                          rvalue_ast)) {
520758657e5SAleksandr Urakov       return nullptr;
521758657e5SAleksandr Urakov     }
522758657e5SAleksandr Urakov 
523758657e5SAleksandr Urakov     lldbassert(rvalue_ast);
524758657e5SAleksandr Urakov 
525758657e5SAleksandr Urakov     // check & resolve assignment program
526758657e5SAleksandr Urakov     FPOProgramASTVisitorResolveRegisterRefs resolver(dependent_programs,
5271c4ee160SPavel Labath                                                      arch_type, alloc);
528758657e5SAleksandr Urakov     if (!resolver.Resolve(rvalue_ast)) {
529758657e5SAleksandr Urakov       return nullptr;
530758657e5SAleksandr Urakov     }
531758657e5SAleksandr Urakov 
532758657e5SAleksandr Urakov     if (lvalue_name == register_name) {
533758657e5SAleksandr Urakov       // found target assignment program - no need to parse further
534758657e5SAleksandr Urakov 
535758657e5SAleksandr Urakov       // emplace valid dependent subtrees to make target assignment independent
536758657e5SAleksandr Urakov       // from predecessors
537758657e5SAleksandr Urakov       FPOProgramASTVisitorMergeDependent merger(dependent_programs);
538758657e5SAleksandr Urakov       merger.Merge(rvalue_ast);
539758657e5SAleksandr Urakov 
540758657e5SAleksandr Urakov       return rvalue_ast;
541758657e5SAleksandr Urakov     }
542758657e5SAleksandr Urakov 
543758657e5SAleksandr Urakov     dependent_programs[lvalue_name] = rvalue_ast;
544758657e5SAleksandr Urakov     cur = assign_index + 1;
545758657e5SAleksandr Urakov   }
546758657e5SAleksandr Urakov 
547758657e5SAleksandr Urakov   return nullptr;
548758657e5SAleksandr Urakov }
549758657e5SAleksandr Urakov 
550758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
551758657e5SAleksandr Urakov     llvm::StringRef program, llvm::StringRef register_name,
552758657e5SAleksandr Urakov     llvm::Triple::ArchType arch_type, Stream &stream) {
553758657e5SAleksandr Urakov   NodeAllocator node_alloc;
554758657e5SAleksandr Urakov   FPOProgramNode *target_program =
555758657e5SAleksandr Urakov       ParseFPOProgram(program, register_name, arch_type, node_alloc);
556758657e5SAleksandr Urakov   if (target_program == nullptr) {
557758657e5SAleksandr Urakov     return false;
558758657e5SAleksandr Urakov   }
559758657e5SAleksandr Urakov 
560758657e5SAleksandr Urakov   FPOProgramASTVisitorDWARFCodegen codegen(stream);
56194cd0667SPavel Labath   codegen.Emit(*target_program);
562758657e5SAleksandr Urakov   return true;
563758657e5SAleksandr Urakov }
564