1758657e5SAleksandr Urakov //===-- PDBFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===//
2758657e5SAleksandr Urakov //
3*ee21a66aSAleksandr Urakov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*ee21a66aSAleksandr Urakov // See https://llvm.org/LICENSE.txt for license information.
5*ee21a66aSAleksandr 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"
21758657e5SAleksandr Urakov 
22758657e5SAleksandr Urakov using namespace lldb;
23758657e5SAleksandr Urakov using namespace lldb_private;
24758657e5SAleksandr Urakov 
25758657e5SAleksandr Urakov namespace {
26758657e5SAleksandr Urakov 
27758657e5SAleksandr Urakov class FPOProgramNode;
28758657e5SAleksandr Urakov class FPOProgramASTVisitor;
29758657e5SAleksandr Urakov 
30758657e5SAleksandr Urakov class FPOProgramNode {
31758657e5SAleksandr Urakov public:
32758657e5SAleksandr Urakov   enum Kind {
33758657e5SAleksandr Urakov     Register,
34758657e5SAleksandr Urakov     IntegerLiteral,
35758657e5SAleksandr Urakov     BinaryOp,
36758657e5SAleksandr Urakov     UnaryOp,
37758657e5SAleksandr Urakov   };
38758657e5SAleksandr Urakov 
39758657e5SAleksandr Urakov protected:
40758657e5SAleksandr Urakov   FPOProgramNode(Kind kind) : m_token_kind(kind) {}
41758657e5SAleksandr Urakov 
42758657e5SAleksandr Urakov public:
43758657e5SAleksandr Urakov   virtual ~FPOProgramNode() = default;
44758657e5SAleksandr Urakov   virtual void Accept(FPOProgramASTVisitor *visitor) = 0;
45758657e5SAleksandr Urakov 
46758657e5SAleksandr Urakov   Kind GetKind() const { return m_token_kind; }
47758657e5SAleksandr Urakov 
48758657e5SAleksandr Urakov private:
49758657e5SAleksandr Urakov   Kind m_token_kind;
50758657e5SAleksandr Urakov };
51758657e5SAleksandr Urakov 
52758657e5SAleksandr Urakov class FPOProgramNodeRegisterRef : public FPOProgramNode {
53758657e5SAleksandr Urakov public:
54758657e5SAleksandr Urakov   FPOProgramNodeRegisterRef(llvm::StringRef name)
55758657e5SAleksandr Urakov       : FPOProgramNode(Register), m_name(name) {}
56758657e5SAleksandr Urakov 
57758657e5SAleksandr Urakov   void Accept(FPOProgramASTVisitor *visitor) override;
58758657e5SAleksandr Urakov 
59758657e5SAleksandr Urakov   llvm::StringRef GetName() const { return m_name; }
60758657e5SAleksandr Urakov   uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; }
61758657e5SAleksandr Urakov 
62758657e5SAleksandr Urakov   bool ResolveLLDBRegisterNum(llvm::Triple::ArchType arch_type);
63758657e5SAleksandr Urakov 
64758657e5SAleksandr Urakov private:
65758657e5SAleksandr Urakov   llvm::StringRef m_name;
66758657e5SAleksandr Urakov   uint32_t m_lldb_reg_num = LLDB_INVALID_REGNUM;
67758657e5SAleksandr Urakov };
68758657e5SAleksandr Urakov 
69758657e5SAleksandr Urakov bool FPOProgramNodeRegisterRef::ResolveLLDBRegisterNum(
70758657e5SAleksandr Urakov     llvm::Triple::ArchType arch_type) {
71758657e5SAleksandr Urakov 
72758657e5SAleksandr Urakov   llvm::StringRef reg_name = m_name.slice(1, m_name.size());
73758657e5SAleksandr Urakov 
74758657e5SAleksandr Urakov   // lookup register name to get lldb register number
75758657e5SAleksandr Urakov   llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
76758657e5SAleksandr Urakov       llvm::codeview::getRegisterNames();
77758657e5SAleksandr Urakov   auto it = llvm::find_if(
78758657e5SAleksandr Urakov       register_names,
79758657e5SAleksandr Urakov       [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
80758657e5SAleksandr Urakov         return reg_name.compare_lower(register_entry.Name) == 0;
81758657e5SAleksandr Urakov       });
82758657e5SAleksandr Urakov 
83758657e5SAleksandr Urakov   if (it == register_names.end()) {
84758657e5SAleksandr Urakov     return false;
85758657e5SAleksandr Urakov   }
86758657e5SAleksandr Urakov 
87758657e5SAleksandr Urakov   auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
88758657e5SAleksandr Urakov   m_lldb_reg_num = npdb::GetLLDBRegisterNumber(arch_type, reg_id);
89758657e5SAleksandr Urakov 
90758657e5SAleksandr Urakov   return m_lldb_reg_num != LLDB_INVALID_REGNUM;
91758657e5SAleksandr Urakov }
92758657e5SAleksandr Urakov 
93758657e5SAleksandr Urakov class FPOProgramNodeIntegerLiteral : public FPOProgramNode {
94758657e5SAleksandr Urakov public:
95758657e5SAleksandr Urakov   FPOProgramNodeIntegerLiteral(uint32_t value)
96758657e5SAleksandr Urakov       : FPOProgramNode(IntegerLiteral), m_value(value) {}
97758657e5SAleksandr Urakov 
98758657e5SAleksandr Urakov   void Accept(FPOProgramASTVisitor *visitor) override;
99758657e5SAleksandr Urakov 
100758657e5SAleksandr Urakov   uint32_t GetValue() const { return m_value; }
101758657e5SAleksandr Urakov 
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 
114758657e5SAleksandr Urakov   FPOProgramNodeBinaryOp(OpType op_type, FPOProgramNode *left,
115758657e5SAleksandr Urakov                          FPOProgramNode *right)
116758657e5SAleksandr Urakov       : FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(left),
117758657e5SAleksandr Urakov         m_right(right) {}
118758657e5SAleksandr Urakov 
119758657e5SAleksandr Urakov   void Accept(FPOProgramASTVisitor *visitor) override;
120758657e5SAleksandr Urakov 
121758657e5SAleksandr Urakov   OpType GetOpType() const { return m_op_type; }
122758657e5SAleksandr Urakov 
123758657e5SAleksandr Urakov   const FPOProgramNode *Left() const { return m_left; }
124758657e5SAleksandr Urakov   FPOProgramNode *&Left() { return m_left; }
125758657e5SAleksandr Urakov 
126758657e5SAleksandr Urakov   const FPOProgramNode *Right() const { return m_right; }
127758657e5SAleksandr Urakov   FPOProgramNode *&Right() { return m_right; }
128758657e5SAleksandr Urakov 
129758657e5SAleksandr Urakov private:
130758657e5SAleksandr Urakov   OpType m_op_type;
131758657e5SAleksandr Urakov   FPOProgramNode *m_left;
132758657e5SAleksandr Urakov   FPOProgramNode *m_right;
133758657e5SAleksandr Urakov };
134758657e5SAleksandr Urakov 
135758657e5SAleksandr Urakov class FPOProgramNodeUnaryOp : public FPOProgramNode {
136758657e5SAleksandr Urakov public:
137758657e5SAleksandr Urakov   enum OpType {
138758657e5SAleksandr Urakov     Deref,
139758657e5SAleksandr Urakov   };
140758657e5SAleksandr Urakov 
141758657e5SAleksandr Urakov   FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode *operand)
142758657e5SAleksandr Urakov       : FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(operand) {}
143758657e5SAleksandr Urakov 
144758657e5SAleksandr Urakov   void Accept(FPOProgramASTVisitor *visitor) override;
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 
151758657e5SAleksandr Urakov private:
152758657e5SAleksandr Urakov   OpType m_op_type;
153758657e5SAleksandr Urakov   FPOProgramNode *m_operand;
154758657e5SAleksandr Urakov };
155758657e5SAleksandr Urakov 
156758657e5SAleksandr Urakov class FPOProgramASTVisitor {
157758657e5SAleksandr Urakov public:
158758657e5SAleksandr Urakov   virtual ~FPOProgramASTVisitor() = default;
159758657e5SAleksandr Urakov 
160758657e5SAleksandr Urakov   virtual void Visit(FPOProgramNodeRegisterRef *node) {}
161758657e5SAleksandr Urakov   virtual void Visit(FPOProgramNodeIntegerLiteral *node) {}
162758657e5SAleksandr Urakov   virtual void Visit(FPOProgramNodeBinaryOp *node) {}
163758657e5SAleksandr Urakov   virtual void Visit(FPOProgramNodeUnaryOp *node) {}
164758657e5SAleksandr Urakov };
165758657e5SAleksandr Urakov 
166758657e5SAleksandr Urakov void FPOProgramNodeRegisterRef::Accept(FPOProgramASTVisitor *visitor) {
167758657e5SAleksandr Urakov   visitor->Visit(this);
168758657e5SAleksandr Urakov }
169758657e5SAleksandr Urakov 
170758657e5SAleksandr Urakov void FPOProgramNodeIntegerLiteral::Accept(FPOProgramASTVisitor *visitor) {
171758657e5SAleksandr Urakov   visitor->Visit(this);
172758657e5SAleksandr Urakov }
173758657e5SAleksandr Urakov 
174758657e5SAleksandr Urakov void FPOProgramNodeBinaryOp::Accept(FPOProgramASTVisitor *visitor) {
175758657e5SAleksandr Urakov   visitor->Visit(this);
176758657e5SAleksandr Urakov }
177758657e5SAleksandr Urakov 
178758657e5SAleksandr Urakov void FPOProgramNodeUnaryOp::Accept(FPOProgramASTVisitor *visitor) {
179758657e5SAleksandr Urakov   visitor->Visit(this);
180758657e5SAleksandr Urakov }
181758657e5SAleksandr Urakov 
182758657e5SAleksandr Urakov class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor {
183758657e5SAleksandr Urakov public:
184758657e5SAleksandr Urakov   FPOProgramASTVisitorMergeDependent(
185758657e5SAleksandr Urakov       const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
186758657e5SAleksandr Urakov           &dependent_programs)
187758657e5SAleksandr Urakov       : m_dependent_programs(dependent_programs) {}
188758657e5SAleksandr Urakov 
189758657e5SAleksandr Urakov   void Merge(FPOProgramNode *&node_ref);
190758657e5SAleksandr Urakov 
191758657e5SAleksandr Urakov private:
192758657e5SAleksandr Urakov   void Visit(FPOProgramNodeRegisterRef *node) override {}
193758657e5SAleksandr Urakov   void Visit(FPOProgramNodeIntegerLiteral *node) override {}
194758657e5SAleksandr Urakov   void Visit(FPOProgramNodeBinaryOp *node) override;
195758657e5SAleksandr Urakov   void Visit(FPOProgramNodeUnaryOp *node) override;
196758657e5SAleksandr Urakov 
197758657e5SAleksandr Urakov   void TryReplace(FPOProgramNode *&node_ref) const;
198758657e5SAleksandr Urakov 
199758657e5SAleksandr Urakov private:
200758657e5SAleksandr Urakov   const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
201758657e5SAleksandr Urakov };
202758657e5SAleksandr Urakov 
203758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::Merge(FPOProgramNode *&node_ref) {
204758657e5SAleksandr Urakov   TryReplace(node_ref);
205758657e5SAleksandr Urakov   node_ref->Accept(this);
206758657e5SAleksandr Urakov }
207758657e5SAleksandr Urakov 
208758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeBinaryOp *node) {
209758657e5SAleksandr Urakov   Merge(node->Left());
210758657e5SAleksandr Urakov   Merge(node->Right());
211758657e5SAleksandr Urakov }
212758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeUnaryOp *node) {
213758657e5SAleksandr Urakov   Merge(node->Operand());
214758657e5SAleksandr Urakov }
215758657e5SAleksandr Urakov 
216758657e5SAleksandr Urakov void FPOProgramASTVisitorMergeDependent::TryReplace(
217758657e5SAleksandr Urakov     FPOProgramNode *&node_ref) const {
218758657e5SAleksandr Urakov 
219758657e5SAleksandr Urakov   while (node_ref->GetKind() == FPOProgramNode::Register) {
220758657e5SAleksandr Urakov     auto *node_register_ref =
221758657e5SAleksandr Urakov         static_cast<FPOProgramNodeRegisterRef *>(node_ref);
222758657e5SAleksandr Urakov 
223758657e5SAleksandr Urakov     auto it = m_dependent_programs.find(node_register_ref->GetName());
224758657e5SAleksandr Urakov     if (it == m_dependent_programs.end()) {
225758657e5SAleksandr Urakov       break;
226758657e5SAleksandr Urakov     }
227758657e5SAleksandr Urakov 
228758657e5SAleksandr Urakov     node_ref = it->second;
229758657e5SAleksandr Urakov   }
230758657e5SAleksandr Urakov }
231758657e5SAleksandr Urakov 
232758657e5SAleksandr Urakov class FPOProgramASTVisitorResolveRegisterRefs : public FPOProgramASTVisitor {
233758657e5SAleksandr Urakov public:
234758657e5SAleksandr Urakov   FPOProgramASTVisitorResolveRegisterRefs(
235758657e5SAleksandr Urakov       const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
236758657e5SAleksandr Urakov           &dependent_programs,
237758657e5SAleksandr Urakov       llvm::Triple::ArchType arch_type)
238758657e5SAleksandr Urakov       : m_dependent_programs(dependent_programs), m_arch_type(arch_type) {}
239758657e5SAleksandr Urakov 
240758657e5SAleksandr Urakov   bool Resolve(FPOProgramNode *program);
241758657e5SAleksandr Urakov 
242758657e5SAleksandr Urakov private:
243758657e5SAleksandr Urakov   void Visit(FPOProgramNodeRegisterRef *node) override;
244758657e5SAleksandr Urakov   void Visit(FPOProgramNodeIntegerLiteral *node) override {}
245758657e5SAleksandr Urakov   void Visit(FPOProgramNodeBinaryOp *node) override;
246758657e5SAleksandr Urakov   void Visit(FPOProgramNodeUnaryOp *node) override;
247758657e5SAleksandr Urakov 
248758657e5SAleksandr Urakov private:
249758657e5SAleksandr Urakov   const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
250758657e5SAleksandr Urakov   llvm::Triple::ArchType m_arch_type;
251758657e5SAleksandr Urakov   bool m_no_error_flag = true;
252758657e5SAleksandr Urakov };
253758657e5SAleksandr Urakov 
254758657e5SAleksandr Urakov bool FPOProgramASTVisitorResolveRegisterRefs::Resolve(FPOProgramNode *program) {
255758657e5SAleksandr Urakov   program->Accept(this);
256758657e5SAleksandr Urakov   return m_no_error_flag;
257758657e5SAleksandr Urakov }
258758657e5SAleksandr Urakov 
259758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit(
260758657e5SAleksandr Urakov     FPOProgramNodeRegisterRef *node) {
261758657e5SAleksandr Urakov 
262758657e5SAleksandr Urakov   // lookup register reference as lvalue in predecedent assignments
263758657e5SAleksandr Urakov   auto it = m_dependent_programs.find(node->GetName());
264758657e5SAleksandr Urakov   if (it != m_dependent_programs.end()) {
265758657e5SAleksandr Urakov     // dependent programs are already resolved and valid
266758657e5SAleksandr Urakov     return;
267758657e5SAleksandr Urakov   }
268758657e5SAleksandr Urakov   // try to resolve register reference as lldb register name
269758657e5SAleksandr Urakov   m_no_error_flag = node->ResolveLLDBRegisterNum(m_arch_type);
270758657e5SAleksandr Urakov }
271758657e5SAleksandr Urakov 
272758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit(
273758657e5SAleksandr Urakov     FPOProgramNodeBinaryOp *node) {
274758657e5SAleksandr Urakov   m_no_error_flag = Resolve(node->Left()) && Resolve(node->Right());
275758657e5SAleksandr Urakov }
276758657e5SAleksandr Urakov 
277758657e5SAleksandr Urakov void FPOProgramASTVisitorResolveRegisterRefs::Visit(
278758657e5SAleksandr Urakov     FPOProgramNodeUnaryOp *node) {
279758657e5SAleksandr Urakov   m_no_error_flag = Resolve(node->Operand());
280758657e5SAleksandr Urakov }
281758657e5SAleksandr Urakov 
282758657e5SAleksandr Urakov class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor {
283758657e5SAleksandr Urakov public:
284758657e5SAleksandr Urakov   FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {}
285758657e5SAleksandr Urakov 
286758657e5SAleksandr Urakov   void Emit(FPOProgramNode *program);
287758657e5SAleksandr Urakov 
288758657e5SAleksandr Urakov private:
289758657e5SAleksandr Urakov   void Visit(FPOProgramNodeRegisterRef *node) override;
290758657e5SAleksandr Urakov   void Visit(FPOProgramNodeIntegerLiteral *node) override;
291758657e5SAleksandr Urakov   void Visit(FPOProgramNodeBinaryOp *node) override;
292758657e5SAleksandr Urakov   void Visit(FPOProgramNodeUnaryOp *node) override;
293758657e5SAleksandr Urakov 
294758657e5SAleksandr Urakov private:
295758657e5SAleksandr Urakov   Stream &m_out_stream;
296758657e5SAleksandr Urakov };
297758657e5SAleksandr Urakov 
298758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Emit(FPOProgramNode *program) {
299758657e5SAleksandr Urakov   program->Accept(this);
300758657e5SAleksandr Urakov }
301758657e5SAleksandr Urakov 
302758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef *node) {
303758657e5SAleksandr Urakov 
304758657e5SAleksandr Urakov   uint32_t reg_num = node->GetLLDBRegNum();
305758657e5SAleksandr Urakov   lldbassert(reg_num != LLDB_INVALID_REGNUM);
306758657e5SAleksandr Urakov 
307758657e5SAleksandr Urakov   if (reg_num > 31) {
308758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_bregx);
309758657e5SAleksandr Urakov     m_out_stream.PutULEB128(reg_num);
310758657e5SAleksandr Urakov   } else
311758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
312758657e5SAleksandr Urakov 
313758657e5SAleksandr Urakov   m_out_stream.PutSLEB128(0);
314758657e5SAleksandr Urakov }
315758657e5SAleksandr Urakov 
316758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit(
317758657e5SAleksandr Urakov     FPOProgramNodeIntegerLiteral *node) {
318758657e5SAleksandr Urakov   uint32_t value = node->GetValue();
319758657e5SAleksandr Urakov   m_out_stream.PutHex8(DW_OP_constu);
320758657e5SAleksandr Urakov   m_out_stream.PutULEB128(value);
321758657e5SAleksandr Urakov }
322758657e5SAleksandr Urakov 
323758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp *node) {
324758657e5SAleksandr Urakov 
325758657e5SAleksandr Urakov   Emit(node->Left());
326758657e5SAleksandr Urakov   Emit(node->Right());
327758657e5SAleksandr Urakov 
328758657e5SAleksandr Urakov   switch (node->GetOpType()) {
329758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Plus:
330758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_plus);
331758657e5SAleksandr Urakov     // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
332758657e5SAleksandr Urakov     //       if right child node is constant value
333758657e5SAleksandr Urakov     break;
334758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Minus:
335758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
336758657e5SAleksandr Urakov     break;
337758657e5SAleksandr Urakov   case FPOProgramNodeBinaryOp::Align:
338758657e5SAleksandr Urakov     // emit align operator a @ b as
339758657e5SAleksandr Urakov     // a & ~(b - 1)
340758657e5SAleksandr Urakov     // NOTE: implicitly assuming that b is power of 2
341758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_lit1);
342758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
343758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_not);
344758657e5SAleksandr Urakov 
345758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_and);
346758657e5SAleksandr Urakov     break;
347758657e5SAleksandr Urakov   }
348758657e5SAleksandr Urakov }
349758657e5SAleksandr Urakov 
350758657e5SAleksandr Urakov void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp *node) {
351758657e5SAleksandr Urakov   Emit(node->Operand());
352758657e5SAleksandr Urakov 
353758657e5SAleksandr Urakov   switch (node->GetOpType()) {
354758657e5SAleksandr Urakov   case FPOProgramNodeUnaryOp::Deref:
355758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_deref);
356758657e5SAleksandr Urakov     break;
357758657e5SAleksandr Urakov   }
358758657e5SAleksandr Urakov }
359758657e5SAleksandr Urakov 
360758657e5SAleksandr Urakov class NodeAllocator {
361758657e5SAleksandr Urakov public:
362758657e5SAleksandr Urakov   template <typename T, typename... Args> T *makeNode(Args &&... args) {
363758657e5SAleksandr Urakov     void *new_node_mem = m_alloc.Allocate(sizeof(T), alignof(T));
364758657e5SAleksandr Urakov     return new (new_node_mem) T(std::forward<Args>(args)...);
365758657e5SAleksandr Urakov   }
366758657e5SAleksandr Urakov 
367758657e5SAleksandr Urakov private:
368758657e5SAleksandr Urakov   llvm::BumpPtrAllocator m_alloc;
369758657e5SAleksandr Urakov };
370758657e5SAleksandr Urakov 
371758657e5SAleksandr Urakov } // namespace
372758657e5SAleksandr Urakov 
373758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program,
374758657e5SAleksandr Urakov                                             NodeAllocator &alloc,
375758657e5SAleksandr Urakov                                             llvm::StringRef &register_name,
376758657e5SAleksandr Urakov                                             FPOProgramNode *&ast) {
377758657e5SAleksandr Urakov   llvm::SmallVector<llvm::StringRef, 16> tokens;
378758657e5SAleksandr Urakov   llvm::SplitString(program, tokens, " ");
379758657e5SAleksandr Urakov 
380758657e5SAleksandr Urakov   if (tokens.empty())
381758657e5SAleksandr Urakov     return false;
382758657e5SAleksandr Urakov 
383758657e5SAleksandr Urakov   llvm::SmallVector<FPOProgramNode *, 4> eval_stack;
384758657e5SAleksandr Urakov 
385758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNodeBinaryOp::OpType> ops_binary = {
386758657e5SAleksandr Urakov       {"+", FPOProgramNodeBinaryOp::Plus},
387758657e5SAleksandr Urakov       {"-", FPOProgramNodeBinaryOp::Minus},
388758657e5SAleksandr Urakov       {"@", FPOProgramNodeBinaryOp::Align},
389758657e5SAleksandr Urakov   };
390758657e5SAleksandr Urakov 
391758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNodeUnaryOp::OpType> ops_unary = {
392758657e5SAleksandr Urakov       {"^", FPOProgramNodeUnaryOp::Deref},
393758657e5SAleksandr Urakov   };
394758657e5SAleksandr Urakov 
395758657e5SAleksandr Urakov   constexpr llvm::StringLiteral ra_search_keyword = ".raSearch";
396758657e5SAleksandr Urakov 
397758657e5SAleksandr Urakov   // lvalue of assignment is always first token
398758657e5SAleksandr Urakov   // rvalue program goes next
399758657e5SAleksandr Urakov   for (size_t i = 1; i < tokens.size(); ++i) {
400758657e5SAleksandr Urakov     llvm::StringRef cur = tokens[i];
401758657e5SAleksandr Urakov 
402758657e5SAleksandr Urakov     auto ops_binary_it = ops_binary.find(cur);
403758657e5SAleksandr Urakov     if (ops_binary_it != ops_binary.end()) {
404758657e5SAleksandr Urakov       // token is binary operator
405758657e5SAleksandr Urakov       if (eval_stack.size() < 2) {
406758657e5SAleksandr Urakov         return false;
407758657e5SAleksandr Urakov       }
408758657e5SAleksandr Urakov       FPOProgramNode *right = eval_stack.pop_back_val();
409758657e5SAleksandr Urakov       FPOProgramNode *left = eval_stack.pop_back_val();
410758657e5SAleksandr Urakov       FPOProgramNode *node = alloc.makeNode<FPOProgramNodeBinaryOp>(
411758657e5SAleksandr Urakov           ops_binary_it->second, left, right);
412758657e5SAleksandr Urakov       eval_stack.push_back(node);
413758657e5SAleksandr Urakov       continue;
414758657e5SAleksandr Urakov     }
415758657e5SAleksandr Urakov 
416758657e5SAleksandr Urakov     auto ops_unary_it = ops_unary.find(cur);
417758657e5SAleksandr Urakov     if (ops_unary_it != ops_unary.end()) {
418758657e5SAleksandr Urakov       // token is unary operator
419758657e5SAleksandr Urakov       if (eval_stack.empty()) {
420758657e5SAleksandr Urakov         return false;
421758657e5SAleksandr Urakov       }
422758657e5SAleksandr Urakov       FPOProgramNode *operand = eval_stack.pop_back_val();
423758657e5SAleksandr Urakov       FPOProgramNode *node =
424758657e5SAleksandr Urakov           alloc.makeNode<FPOProgramNodeUnaryOp>(ops_unary_it->second, operand);
425758657e5SAleksandr Urakov       eval_stack.push_back(node);
426758657e5SAleksandr Urakov       continue;
427758657e5SAleksandr Urakov     }
428758657e5SAleksandr Urakov 
429758657e5SAleksandr Urakov     if (cur.startswith("$")) {
430758657e5SAleksandr Urakov       // token is register ref
431758657e5SAleksandr Urakov       eval_stack.push_back(alloc.makeNode<FPOProgramNodeRegisterRef>(cur));
432758657e5SAleksandr Urakov       continue;
433758657e5SAleksandr Urakov     }
434758657e5SAleksandr Urakov 
435758657e5SAleksandr Urakov     if (cur == ra_search_keyword) {
436758657e5SAleksandr Urakov       // TODO: .raSearch is unsupported
437758657e5SAleksandr Urakov       return false;
438758657e5SAleksandr Urakov     }
439758657e5SAleksandr Urakov 
440758657e5SAleksandr Urakov     uint32_t value;
441758657e5SAleksandr Urakov     if (!cur.getAsInteger(10, value)) {
442758657e5SAleksandr Urakov       // token is integer literal
443758657e5SAleksandr Urakov       eval_stack.push_back(alloc.makeNode<FPOProgramNodeIntegerLiteral>(value));
444758657e5SAleksandr Urakov       continue;
445758657e5SAleksandr Urakov     }
446758657e5SAleksandr Urakov 
447758657e5SAleksandr Urakov     // unexpected token
448758657e5SAleksandr Urakov     return false;
449758657e5SAleksandr Urakov   }
450758657e5SAleksandr Urakov 
451758657e5SAleksandr Urakov   if (eval_stack.size() != 1) {
452758657e5SAleksandr Urakov     return false;
453758657e5SAleksandr Urakov   }
454758657e5SAleksandr Urakov 
455758657e5SAleksandr Urakov   register_name = tokens[0];
456758657e5SAleksandr Urakov   ast = eval_stack.pop_back_val();
457758657e5SAleksandr Urakov 
458758657e5SAleksandr Urakov   return true;
459758657e5SAleksandr Urakov }
460758657e5SAleksandr Urakov 
461758657e5SAleksandr Urakov static FPOProgramNode *ParseFPOProgram(llvm::StringRef program,
462758657e5SAleksandr Urakov                                        llvm::StringRef register_name,
463758657e5SAleksandr Urakov                                        llvm::Triple::ArchType arch_type,
464758657e5SAleksandr Urakov                                        NodeAllocator &alloc) {
465758657e5SAleksandr Urakov   llvm::DenseMap<llvm::StringRef, FPOProgramNode *> dependent_programs;
466758657e5SAleksandr Urakov 
467758657e5SAleksandr Urakov   size_t cur = 0;
468758657e5SAleksandr Urakov   while (true) {
469758657e5SAleksandr Urakov     size_t assign_index = program.find('=', cur);
470758657e5SAleksandr Urakov     if (assign_index == llvm::StringRef::npos) {
471758657e5SAleksandr Urakov       llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos);
472758657e5SAleksandr Urakov       if (!tail.trim().empty()) {
473758657e5SAleksandr Urakov         // missing assign operator
474758657e5SAleksandr Urakov         return nullptr;
475758657e5SAleksandr Urakov       }
476758657e5SAleksandr Urakov       break;
477758657e5SAleksandr Urakov     }
478758657e5SAleksandr Urakov     llvm::StringRef assignment_program = program.slice(cur, assign_index);
479758657e5SAleksandr Urakov 
480758657e5SAleksandr Urakov     llvm::StringRef lvalue_name;
481758657e5SAleksandr Urakov     FPOProgramNode *rvalue_ast = nullptr;
482758657e5SAleksandr Urakov     if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name,
483758657e5SAleksandr Urakov                                          rvalue_ast)) {
484758657e5SAleksandr Urakov       return nullptr;
485758657e5SAleksandr Urakov     }
486758657e5SAleksandr Urakov 
487758657e5SAleksandr Urakov     lldbassert(rvalue_ast);
488758657e5SAleksandr Urakov 
489758657e5SAleksandr Urakov     // check & resolve assignment program
490758657e5SAleksandr Urakov     FPOProgramASTVisitorResolveRegisterRefs resolver(dependent_programs,
491758657e5SAleksandr Urakov                                                      arch_type);
492758657e5SAleksandr Urakov     if (!resolver.Resolve(rvalue_ast)) {
493758657e5SAleksandr Urakov       return nullptr;
494758657e5SAleksandr Urakov     }
495758657e5SAleksandr Urakov 
496758657e5SAleksandr Urakov     if (lvalue_name == register_name) {
497758657e5SAleksandr Urakov       // found target assignment program - no need to parse further
498758657e5SAleksandr Urakov 
499758657e5SAleksandr Urakov       // emplace valid dependent subtrees to make target assignment independent
500758657e5SAleksandr Urakov       // from predecessors
501758657e5SAleksandr Urakov       FPOProgramASTVisitorMergeDependent merger(dependent_programs);
502758657e5SAleksandr Urakov       merger.Merge(rvalue_ast);
503758657e5SAleksandr Urakov 
504758657e5SAleksandr Urakov       return rvalue_ast;
505758657e5SAleksandr Urakov     }
506758657e5SAleksandr Urakov 
507758657e5SAleksandr Urakov     dependent_programs[lvalue_name] = rvalue_ast;
508758657e5SAleksandr Urakov     cur = assign_index + 1;
509758657e5SAleksandr Urakov   }
510758657e5SAleksandr Urakov 
511758657e5SAleksandr Urakov   return nullptr;
512758657e5SAleksandr Urakov }
513758657e5SAleksandr Urakov 
514758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
515758657e5SAleksandr Urakov     llvm::StringRef program, llvm::StringRef register_name,
516758657e5SAleksandr Urakov     llvm::Triple::ArchType arch_type, Stream &stream) {
517758657e5SAleksandr Urakov   NodeAllocator node_alloc;
518758657e5SAleksandr Urakov   FPOProgramNode *target_program =
519758657e5SAleksandr Urakov       ParseFPOProgram(program, register_name, arch_type, node_alloc);
520758657e5SAleksandr Urakov   if (target_program == nullptr) {
521758657e5SAleksandr Urakov     return false;
522758657e5SAleksandr Urakov   }
523758657e5SAleksandr Urakov 
524758657e5SAleksandr Urakov   FPOProgramASTVisitorDWARFCodegen codegen(stream);
525758657e5SAleksandr Urakov   codegen.Emit(target_program);
526758657e5SAleksandr Urakov   return true;
527758657e5SAleksandr Urakov }
528