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"
14*4eda12aeSPavel Labath #include "lldb/Symbol/PostfixExpression.h"
15758657e5SAleksandr Urakov #include "lldb/Utility/LLDBAssert.h"
16758657e5SAleksandr Urakov #include "lldb/Utility/Stream.h"
17758657e5SAleksandr Urakov #include "llvm/ADT/DenseMap.h"
18758657e5SAleksandr Urakov 
19758657e5SAleksandr Urakov #include "llvm/ADT/StringExtras.h"
20758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/CodeView.h"
21758657e5SAleksandr Urakov #include "llvm/DebugInfo/CodeView/EnumTables.h"
22758657e5SAleksandr Urakov 
23758657e5SAleksandr Urakov using namespace lldb;
24758657e5SAleksandr Urakov using namespace lldb_private;
25*4eda12aeSPavel Labath using namespace lldb_private::postfix;
26758657e5SAleksandr Urakov 
27758657e5SAleksandr Urakov namespace {
28758657e5SAleksandr Urakov 
291c4ee160SPavel Labath class NodeAllocator {
301c4ee160SPavel Labath public:
311c4ee160SPavel Labath   template <typename T, typename... Args> T *makeNode(Args &&... args) {
3285ce053dSPavel Labath     static_assert(std::is_trivially_destructible<T>::value,
3385ce053dSPavel Labath                   "This object will not be destroyed!");
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 
42*4eda12aeSPavel Labath class FPOProgramASTVisitorMergeDependent : public Visitor<> {
43758657e5SAleksandr Urakov public:
44*4eda12aeSPavel Labath   void Visit(BinaryOpNode &binary, Node *&) override {
4585ce053dSPavel Labath     Dispatch(binary.Left());
4685ce053dSPavel Labath     Dispatch(binary.Right());
4785ce053dSPavel Labath   }
4885ce053dSPavel Labath 
49*4eda12aeSPavel Labath   void Visit(UnaryOpNode &unary, Node *&) override {
5085ce053dSPavel Labath     Dispatch(unary.Operand());
5185ce053dSPavel Labath   }
5285ce053dSPavel Labath 
53*4eda12aeSPavel Labath   void Visit(RegisterNode &, Node *&) override {}
54*4eda12aeSPavel Labath   void Visit(IntegerNode &, Node *&) override {}
55*4eda12aeSPavel Labath   void Visit(SymbolNode &symbol, Node *&ref) override;
5685ce053dSPavel Labath 
57*4eda12aeSPavel Labath   static void
58*4eda12aeSPavel Labath   Merge(const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs,
59*4eda12aeSPavel Labath         Node *&ast) {
6085ce053dSPavel Labath     FPOProgramASTVisitorMergeDependent(dependent_programs).Dispatch(ast);
6185ce053dSPavel Labath   }
6285ce053dSPavel Labath 
6385ce053dSPavel Labath private:
64758657e5SAleksandr Urakov   FPOProgramASTVisitorMergeDependent(
65*4eda12aeSPavel Labath       const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs)
66758657e5SAleksandr Urakov       : m_dependent_programs(dependent_programs) {}
67758657e5SAleksandr Urakov 
68*4eda12aeSPavel Labath   const llvm::DenseMap<llvm::StringRef, Node *> &m_dependent_programs;
69758657e5SAleksandr Urakov };
70758657e5SAleksandr Urakov 
71*4eda12aeSPavel Labath void FPOProgramASTVisitorMergeDependent::Visit(SymbolNode &symbol, Node *&ref) {
7285ce053dSPavel Labath   auto it = m_dependent_programs.find(symbol.GetName());
7385ce053dSPavel Labath   if (it == m_dependent_programs.end())
7485ce053dSPavel Labath     return;
7585ce053dSPavel Labath 
7685ce053dSPavel Labath   ref = it->second;
7785ce053dSPavel Labath   Dispatch(ref);
78758657e5SAleksandr Urakov }
79758657e5SAleksandr Urakov 
80*4eda12aeSPavel Labath class FPOProgramASTVisitorResolveRegisterRefs : public Visitor<bool> {
81758657e5SAleksandr Urakov public:
82*4eda12aeSPavel Labath   static bool
83*4eda12aeSPavel Labath   Resolve(const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs,
84*4eda12aeSPavel Labath           llvm::Triple::ArchType arch_type, NodeAllocator &alloc, Node *&ast) {
8585ce053dSPavel Labath     return FPOProgramASTVisitorResolveRegisterRefs(dependent_programs,
8685ce053dSPavel Labath                                                    arch_type, alloc)
8785ce053dSPavel Labath         .Dispatch(ast);
8885ce053dSPavel Labath   }
8985ce053dSPavel Labath 
90*4eda12aeSPavel Labath   bool Visit(BinaryOpNode &binary, Node *&) override {
9185ce053dSPavel Labath     return Dispatch(binary.Left()) && Dispatch(binary.Right());
9285ce053dSPavel Labath   }
9385ce053dSPavel Labath 
94*4eda12aeSPavel Labath   bool Visit(UnaryOpNode &unary, Node *&) override {
9585ce053dSPavel Labath     return Dispatch(unary.Operand());
9685ce053dSPavel Labath   }
9785ce053dSPavel Labath 
98*4eda12aeSPavel Labath   bool Visit(RegisterNode &, Node *&) override { return true; }
9985ce053dSPavel Labath 
100*4eda12aeSPavel Labath   bool Visit(IntegerNode &, Node *&) override { return true; }
10185ce053dSPavel Labath 
102*4eda12aeSPavel Labath   bool Visit(SymbolNode &symbol, Node *&ref) override;
10385ce053dSPavel Labath 
10485ce053dSPavel Labath private:
105758657e5SAleksandr Urakov   FPOProgramASTVisitorResolveRegisterRefs(
106*4eda12aeSPavel Labath       const llvm::DenseMap<llvm::StringRef, Node *> &dependent_programs,
1071c4ee160SPavel Labath       llvm::Triple::ArchType arch_type, NodeAllocator &alloc)
1081c4ee160SPavel Labath       : m_dependent_programs(dependent_programs), m_arch_type(arch_type),
1091c4ee160SPavel Labath         m_alloc(alloc) {}
110758657e5SAleksandr Urakov 
111*4eda12aeSPavel Labath   const llvm::DenseMap<llvm::StringRef, Node *> &m_dependent_programs;
112758657e5SAleksandr Urakov   llvm::Triple::ArchType m_arch_type;
1131c4ee160SPavel Labath   NodeAllocator &m_alloc;
114758657e5SAleksandr Urakov };
115758657e5SAleksandr Urakov 
1161c4ee160SPavel Labath static uint32_t ResolveLLDBRegisterNum(llvm::StringRef reg_name, llvm::Triple::ArchType arch_type) {
1171c4ee160SPavel Labath   // lookup register name to get lldb register number
1181c4ee160SPavel Labath   llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
1191c4ee160SPavel Labath       llvm::codeview::getRegisterNames();
1201c4ee160SPavel Labath   auto it = llvm::find_if(
1211c4ee160SPavel Labath       register_names,
1221c4ee160SPavel Labath       [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
1231c4ee160SPavel Labath         return reg_name.compare_lower(register_entry.Name) == 0;
1241c4ee160SPavel Labath       });
125758657e5SAleksandr Urakov 
1261c4ee160SPavel Labath   if (it == register_names.end())
1271c4ee160SPavel Labath     return LLDB_INVALID_REGNUM;
1281c4ee160SPavel Labath 
1291c4ee160SPavel Labath   auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
1301c4ee160SPavel Labath   return npdb::GetLLDBRegisterNumber(arch_type, reg_id);
131758657e5SAleksandr Urakov }
1321c4ee160SPavel Labath 
133*4eda12aeSPavel Labath bool FPOProgramASTVisitorResolveRegisterRefs::Visit(SymbolNode &symbol,
134*4eda12aeSPavel Labath                                                     Node *&ref) {
1351c4ee160SPavel Labath   // Look up register reference as lvalue in preceding assignments.
13685ce053dSPavel Labath   auto it = m_dependent_programs.find(symbol.GetName());
1371c4ee160SPavel Labath   if (it != m_dependent_programs.end()) {
1381c4ee160SPavel Labath     // Dependent programs are handled elsewhere.
1391c4ee160SPavel Labath     return true;
1401c4ee160SPavel Labath   }
1411c4ee160SPavel Labath 
1421c4ee160SPavel Labath   uint32_t reg_num =
14385ce053dSPavel Labath       ResolveLLDBRegisterNum(symbol.GetName().drop_front(1), m_arch_type);
1441c4ee160SPavel Labath 
1451c4ee160SPavel Labath   if (reg_num == LLDB_INVALID_REGNUM)
1461c4ee160SPavel Labath     return false;
1471c4ee160SPavel Labath 
148*4eda12aeSPavel Labath   ref = m_alloc.makeNode<RegisterNode>(reg_num);
1491c4ee160SPavel Labath   return true;
150758657e5SAleksandr Urakov }
151758657e5SAleksandr Urakov 
152*4eda12aeSPavel Labath class FPOProgramASTVisitorDWARFCodegen : public Visitor<> {
153758657e5SAleksandr Urakov public:
154*4eda12aeSPavel Labath   static void Emit(Stream &stream, Node *&ast) {
15585ce053dSPavel Labath     FPOProgramASTVisitorDWARFCodegen(stream).Dispatch(ast);
15685ce053dSPavel Labath   }
15785ce053dSPavel Labath 
158*4eda12aeSPavel Labath   void Visit(RegisterNode &reg, Node *&);
159*4eda12aeSPavel Labath   void Visit(BinaryOpNode &binary, Node *&);
160*4eda12aeSPavel Labath   void Visit(UnaryOpNode &unary, Node *&);
161*4eda12aeSPavel Labath   void Visit(SymbolNode &symbol, Node *&) {
16285ce053dSPavel Labath     llvm_unreachable("Symbols should have been resolved by now!");
16385ce053dSPavel Labath   }
164*4eda12aeSPavel Labath   void Visit(IntegerNode &integer, Node *&);
16585ce053dSPavel Labath 
16685ce053dSPavel Labath private:
167758657e5SAleksandr Urakov   FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {}
168758657e5SAleksandr Urakov 
169758657e5SAleksandr Urakov   Stream &m_out_stream;
170758657e5SAleksandr Urakov };
171758657e5SAleksandr Urakov 
172*4eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(RegisterNode &reg, Node *&) {
173*4eda12aeSPavel Labath   uint32_t reg_num = reg.GetRegNum();
174758657e5SAleksandr Urakov   lldbassert(reg_num != LLDB_INVALID_REGNUM);
175758657e5SAleksandr Urakov 
176758657e5SAleksandr Urakov   if (reg_num > 31) {
177758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_bregx);
178758657e5SAleksandr Urakov     m_out_stream.PutULEB128(reg_num);
179758657e5SAleksandr Urakov   } else
180758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
181758657e5SAleksandr Urakov 
182758657e5SAleksandr Urakov   m_out_stream.PutSLEB128(0);
183758657e5SAleksandr Urakov }
184758657e5SAleksandr Urakov 
185*4eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(IntegerNode &integer, Node *&) {
18685ce053dSPavel Labath   uint32_t value = integer.GetValue();
187758657e5SAleksandr Urakov   m_out_stream.PutHex8(DW_OP_constu);
188758657e5SAleksandr Urakov   m_out_stream.PutULEB128(value);
189758657e5SAleksandr Urakov }
190758657e5SAleksandr Urakov 
191*4eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(BinaryOpNode &binary, Node *&) {
19285ce053dSPavel Labath   Dispatch(binary.Left());
19385ce053dSPavel Labath   Dispatch(binary.Right());
194758657e5SAleksandr Urakov 
19585ce053dSPavel Labath   switch (binary.GetOpType()) {
196*4eda12aeSPavel Labath   case BinaryOpNode::Plus:
197758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_plus);
198758657e5SAleksandr Urakov     // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
199758657e5SAleksandr Urakov     //       if right child node is constant value
200758657e5SAleksandr Urakov     break;
201*4eda12aeSPavel Labath   case BinaryOpNode::Minus:
202758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
203758657e5SAleksandr Urakov     break;
204*4eda12aeSPavel Labath   case BinaryOpNode::Align:
205758657e5SAleksandr Urakov     // emit align operator a @ b as
206758657e5SAleksandr Urakov     // a & ~(b - 1)
207758657e5SAleksandr Urakov     // NOTE: implicitly assuming that b is power of 2
208758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_lit1);
209758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_minus);
210758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_not);
211758657e5SAleksandr Urakov 
212758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_and);
213758657e5SAleksandr Urakov     break;
214758657e5SAleksandr Urakov   }
215758657e5SAleksandr Urakov }
216758657e5SAleksandr Urakov 
217*4eda12aeSPavel Labath void FPOProgramASTVisitorDWARFCodegen::Visit(UnaryOpNode &unary, Node *&) {
21885ce053dSPavel Labath   Dispatch(unary.Operand());
219758657e5SAleksandr Urakov 
22085ce053dSPavel Labath   switch (unary.GetOpType()) {
221*4eda12aeSPavel Labath   case UnaryOpNode::Deref:
222758657e5SAleksandr Urakov     m_out_stream.PutHex8(DW_OP_deref);
223758657e5SAleksandr Urakov     break;
224758657e5SAleksandr Urakov   }
225758657e5SAleksandr Urakov }
226758657e5SAleksandr Urakov 
227758657e5SAleksandr Urakov } // namespace
228758657e5SAleksandr Urakov 
229758657e5SAleksandr Urakov static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program,
230758657e5SAleksandr Urakov                                             NodeAllocator &alloc,
231758657e5SAleksandr Urakov                                             llvm::StringRef &register_name,
232*4eda12aeSPavel Labath                                             Node *&ast) {
233758657e5SAleksandr Urakov   llvm::SmallVector<llvm::StringRef, 16> tokens;
234758657e5SAleksandr Urakov   llvm::SplitString(program, tokens, " ");
235758657e5SAleksandr Urakov 
236758657e5SAleksandr Urakov   if (tokens.empty())
237758657e5SAleksandr Urakov     return false;
238758657e5SAleksandr Urakov 
239*4eda12aeSPavel Labath   llvm::SmallVector<Node *, 4> eval_stack;
240758657e5SAleksandr Urakov 
241*4eda12aeSPavel Labath   llvm::DenseMap<llvm::StringRef, BinaryOpNode::OpType> ops_binary = {
242*4eda12aeSPavel Labath       {"+", BinaryOpNode::Plus},
243*4eda12aeSPavel Labath       {"-", BinaryOpNode::Minus},
244*4eda12aeSPavel Labath       {"@", BinaryOpNode::Align},
245758657e5SAleksandr Urakov   };
246758657e5SAleksandr Urakov 
247*4eda12aeSPavel Labath   llvm::DenseMap<llvm::StringRef, UnaryOpNode::OpType> ops_unary = {
248*4eda12aeSPavel Labath       {"^", UnaryOpNode::Deref},
249758657e5SAleksandr Urakov   };
250758657e5SAleksandr Urakov 
251758657e5SAleksandr Urakov   constexpr llvm::StringLiteral ra_search_keyword = ".raSearch";
252758657e5SAleksandr Urakov 
253758657e5SAleksandr Urakov   // lvalue of assignment is always first token
254758657e5SAleksandr Urakov   // rvalue program goes next
255758657e5SAleksandr Urakov   for (size_t i = 1; i < tokens.size(); ++i) {
256758657e5SAleksandr Urakov     llvm::StringRef cur = tokens[i];
257758657e5SAleksandr Urakov 
258758657e5SAleksandr Urakov     auto ops_binary_it = ops_binary.find(cur);
259758657e5SAleksandr Urakov     if (ops_binary_it != ops_binary.end()) {
260758657e5SAleksandr Urakov       // token is binary operator
261758657e5SAleksandr Urakov       if (eval_stack.size() < 2) {
262758657e5SAleksandr Urakov         return false;
263758657e5SAleksandr Urakov       }
264*4eda12aeSPavel Labath       Node *right = eval_stack.pop_back_val();
265*4eda12aeSPavel Labath       Node *left = eval_stack.pop_back_val();
266*4eda12aeSPavel Labath       Node *node =
267*4eda12aeSPavel Labath           alloc.makeNode<BinaryOpNode>(ops_binary_it->second, *left, *right);
268758657e5SAleksandr Urakov       eval_stack.push_back(node);
269758657e5SAleksandr Urakov       continue;
270758657e5SAleksandr Urakov     }
271758657e5SAleksandr Urakov 
272758657e5SAleksandr Urakov     auto ops_unary_it = ops_unary.find(cur);
273758657e5SAleksandr Urakov     if (ops_unary_it != ops_unary.end()) {
274758657e5SAleksandr Urakov       // token is unary operator
275758657e5SAleksandr Urakov       if (eval_stack.empty()) {
276758657e5SAleksandr Urakov         return false;
277758657e5SAleksandr Urakov       }
278*4eda12aeSPavel Labath       Node *operand = eval_stack.pop_back_val();
279*4eda12aeSPavel Labath       Node *node = alloc.makeNode<UnaryOpNode>(ops_unary_it->second, *operand);
280758657e5SAleksandr Urakov       eval_stack.push_back(node);
281758657e5SAleksandr Urakov       continue;
282758657e5SAleksandr Urakov     }
283758657e5SAleksandr Urakov 
284758657e5SAleksandr Urakov     if (cur.startswith("$")) {
285*4eda12aeSPavel Labath       eval_stack.push_back(alloc.makeNode<SymbolNode>(cur));
286758657e5SAleksandr Urakov       continue;
287758657e5SAleksandr Urakov     }
288758657e5SAleksandr Urakov 
289758657e5SAleksandr Urakov     if (cur == ra_search_keyword) {
290758657e5SAleksandr Urakov       // TODO: .raSearch is unsupported
291758657e5SAleksandr Urakov       return false;
292758657e5SAleksandr Urakov     }
293758657e5SAleksandr Urakov 
294758657e5SAleksandr Urakov     uint32_t value;
295758657e5SAleksandr Urakov     if (!cur.getAsInteger(10, value)) {
296758657e5SAleksandr Urakov       // token is integer literal
297*4eda12aeSPavel Labath       eval_stack.push_back(alloc.makeNode<IntegerNode>(value));
298758657e5SAleksandr Urakov       continue;
299758657e5SAleksandr Urakov     }
300758657e5SAleksandr Urakov 
301758657e5SAleksandr Urakov     // unexpected token
302758657e5SAleksandr Urakov     return false;
303758657e5SAleksandr Urakov   }
304758657e5SAleksandr Urakov 
305758657e5SAleksandr Urakov   if (eval_stack.size() != 1) {
306758657e5SAleksandr Urakov     return false;
307758657e5SAleksandr Urakov   }
308758657e5SAleksandr Urakov 
309758657e5SAleksandr Urakov   register_name = tokens[0];
310758657e5SAleksandr Urakov   ast = eval_stack.pop_back_val();
311758657e5SAleksandr Urakov 
312758657e5SAleksandr Urakov   return true;
313758657e5SAleksandr Urakov }
314758657e5SAleksandr Urakov 
315*4eda12aeSPavel Labath static Node *ParseFPOProgram(llvm::StringRef program,
316758657e5SAleksandr Urakov                              llvm::StringRef register_name,
317758657e5SAleksandr Urakov                              llvm::Triple::ArchType arch_type,
318758657e5SAleksandr Urakov                              NodeAllocator &alloc) {
319*4eda12aeSPavel Labath   llvm::DenseMap<llvm::StringRef, Node *> dependent_programs;
320758657e5SAleksandr Urakov 
321758657e5SAleksandr Urakov   size_t cur = 0;
322758657e5SAleksandr Urakov   while (true) {
323758657e5SAleksandr Urakov     size_t assign_index = program.find('=', cur);
324758657e5SAleksandr Urakov     if (assign_index == llvm::StringRef::npos) {
325758657e5SAleksandr Urakov       llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos);
326758657e5SAleksandr Urakov       if (!tail.trim().empty()) {
327758657e5SAleksandr Urakov         // missing assign operator
328758657e5SAleksandr Urakov         return nullptr;
329758657e5SAleksandr Urakov       }
330758657e5SAleksandr Urakov       break;
331758657e5SAleksandr Urakov     }
332758657e5SAleksandr Urakov     llvm::StringRef assignment_program = program.slice(cur, assign_index);
333758657e5SAleksandr Urakov 
334758657e5SAleksandr Urakov     llvm::StringRef lvalue_name;
335*4eda12aeSPavel Labath     Node *rvalue_ast = nullptr;
336758657e5SAleksandr Urakov     if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name,
337758657e5SAleksandr Urakov                                          rvalue_ast)) {
338758657e5SAleksandr Urakov       return nullptr;
339758657e5SAleksandr Urakov     }
340758657e5SAleksandr Urakov 
341758657e5SAleksandr Urakov     lldbassert(rvalue_ast);
342758657e5SAleksandr Urakov 
343758657e5SAleksandr Urakov     // check & resolve assignment program
34485ce053dSPavel Labath     if (!FPOProgramASTVisitorResolveRegisterRefs::Resolve(
34585ce053dSPavel Labath             dependent_programs, arch_type, alloc, rvalue_ast))
346758657e5SAleksandr Urakov       return nullptr;
347758657e5SAleksandr Urakov 
348758657e5SAleksandr Urakov     if (lvalue_name == register_name) {
349758657e5SAleksandr Urakov       // found target assignment program - no need to parse further
350758657e5SAleksandr Urakov 
351758657e5SAleksandr Urakov       // emplace valid dependent subtrees to make target assignment independent
352758657e5SAleksandr Urakov       // from predecessors
35385ce053dSPavel Labath       FPOProgramASTVisitorMergeDependent::Merge(dependent_programs, rvalue_ast);
354758657e5SAleksandr Urakov 
355758657e5SAleksandr Urakov       return rvalue_ast;
356758657e5SAleksandr Urakov     }
357758657e5SAleksandr Urakov 
358758657e5SAleksandr Urakov     dependent_programs[lvalue_name] = rvalue_ast;
359758657e5SAleksandr Urakov     cur = assign_index + 1;
360758657e5SAleksandr Urakov   }
361758657e5SAleksandr Urakov 
362758657e5SAleksandr Urakov   return nullptr;
363758657e5SAleksandr Urakov }
364758657e5SAleksandr Urakov 
365758657e5SAleksandr Urakov bool lldb_private::npdb::TranslateFPOProgramToDWARFExpression(
366758657e5SAleksandr Urakov     llvm::StringRef program, llvm::StringRef register_name,
367758657e5SAleksandr Urakov     llvm::Triple::ArchType arch_type, Stream &stream) {
368758657e5SAleksandr Urakov   NodeAllocator node_alloc;
369*4eda12aeSPavel Labath   Node *target_program =
370758657e5SAleksandr Urakov       ParseFPOProgram(program, register_name, arch_type, node_alloc);
371758657e5SAleksandr Urakov   if (target_program == nullptr) {
372758657e5SAleksandr Urakov     return false;
373758657e5SAleksandr Urakov   }
374758657e5SAleksandr Urakov 
37585ce053dSPavel Labath   FPOProgramASTVisitorDWARFCodegen::Emit(stream, target_program);
376758657e5SAleksandr Urakov   return true;
377758657e5SAleksandr Urakov }
378