leonid.mashinskiy updated this revision to Diff 176411.
leonid.mashinskiy added a comment.

Added unit tests for translator and fix issues mentioned by review


Repository:
  rLLDB LLDB

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D55122/new/

https://reviews.llvm.org/D55122

Files:
  lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.cpp
  lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.script
  lit/SymbolFile/PDB/variables-locations.test
  source/Expression/DWARFExpression.cpp
  source/Plugins/SymbolFile/PDB/CMakeLists.txt
  source/Plugins/SymbolFile/PDB/CodeViewRegisterMapping.cpp
  source/Plugins/SymbolFile/PDB/CodeViewRegisterMapping.h
  source/Plugins/SymbolFile/PDB/PDBFPOProgramToDWARFExpression.cpp
  source/Plugins/SymbolFile/PDB/PDBFPOProgramToDWARFExpression.h
  source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
  source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h
  source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
  unittests/SymbolFile/PDB/CMakeLists.txt
  unittests/SymbolFile/PDB/PDBFPOProgramToDWARFExpressionTests.cpp

Index: unittests/SymbolFile/PDB/PDBFPOProgramToDWARFExpressionTests.cpp
===================================================================
--- /dev/null
+++ unittests/SymbolFile/PDB/PDBFPOProgramToDWARFExpressionTests.cpp
@@ -0,0 +1,154 @@
+//===-- PDBFPOProgramToDWARFExpressionTests.cpp -----------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "Plugins/SymbolFile/PDB/PDBFPOProgramToDWARFExpression.h"
+
+#include "lldb/Core/StreamBuffer.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Utility/ArchSpec.h"
+#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
+#include "lldb/Utility/StreamString.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// Valid programs tests
+
+static void
+CheckValidProgramTranslation(llvm::StringRef fpo_program,
+                             llvm::StringRef target_register_name,
+                             llvm::StringRef expected_dwarf_expression) {
+  // initial setup
+  ArchSpec arch_spec("i686-pc-windows");
+  llvm::Triple::ArchType arch_type = arch_spec.GetMachine();
+  ByteOrder byte_order = arch_spec.GetByteOrder();
+  uint32_t address_size = arch_spec.GetAddressByteSize();
+  uint32_t byte_size = arch_spec.GetDataByteSize();
+
+  // program translation
+  StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
+  ASSERT_TRUE(TranslateFPOProgramToDWARFExpression(
+      fpo_program, target_register_name, arch_type, stream));
+
+  // print dwarf expression to comparable textual representation
+  DataBufferSP buffer =
+      std::make_shared<DataBufferHeap>(stream.GetData(), stream.GetSize());
+  DataExtractor extractor(buffer, byte_order, address_size, byte_size);
+
+  StreamString result_dwarf_expression;
+  ASSERT_TRUE(DWARFExpression::PrintDWARFExpression(
+      result_dwarf_expression, extractor, address_size, 4, false));
+
+  // actual check
+  ASSERT_EQ(expected_dwarf_expression, result_dwarf_expression.GetString());
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, SingleAssignmentConst) {
+  CheckValidProgramTranslation("$T0 0 = ", "$T0", "DW_OP_constu 0x0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, SingleAssignmentRegisterRef) {
+  CheckValidProgramTranslation("$T0 $ebp = ", "$T0", "DW_OP_breg6 +0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, SingleAssignmentExpressionPlus) {
+  CheckValidProgramTranslation("$T0 $ebp 4 + = ", "$T0",
+                               "DW_OP_breg6 +0, DW_OP_constu 0x4, DW_OP_plus ");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, SingleAssignmentExpressionDeref) {
+  CheckValidProgramTranslation("$T0 $ebp ^ = ", "$T0",
+                               "DW_OP_breg6 +0, DW_OP_deref ");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, SingleAssignmentExpressionMinus) {
+  CheckValidProgramTranslation(
+      "$T0 $ebp 4 - = ", "$T0",
+      "DW_OP_breg6 +0, DW_OP_constu 0x4, DW_OP_minus ");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, SingleAssignmentExpressionAlign) {
+  CheckValidProgramTranslation("$T0 $ebp 128 @ = ", "$T0",
+                               "DW_OP_breg6 +0, DW_OP_constu 0x80, DW_OP_lit1 "
+                               ", DW_OP_minus , DW_OP_not , DW_OP_and ");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, MultipleIndependentAssignments) {
+  CheckValidProgramTranslation("$T1 1 = $T0 0 =", "$T0", "DW_OP_constu 0x0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, MultipleDependentAssignments) {
+  CheckValidProgramTranslation(
+      "$T1 $ebp 4 + = $T0 $T1 8 - 128 @ = ", "$T0",
+      "DW_OP_breg6 +0, DW_OP_constu 0x4, DW_OP_plus , DW_OP_constu 0x8, "
+      "DW_OP_minus , DW_OP_constu 0x80, DW_OP_lit1 , DW_OP_minus , DW_OP_not , "
+      "DW_OP_and ");
+}
+
+/// Invalid programs tests
+static void
+CheckInvalidProgramTranslation(llvm::StringRef fpo_program,
+                               llvm::StringRef target_register_name) {
+  // initial setup
+  ArchSpec arch_spec("i686-pc-windows");
+  llvm::Triple::ArchType arch_type = arch_spec.GetMachine();
+  ByteOrder byte_order = arch_spec.GetByteOrder();
+  uint32_t address_size = arch_spec.GetAddressByteSize();
+
+  // program translation
+  StreamBuffer<32> stream(Stream::eBinary, address_size, byte_order);
+  EXPECT_FALSE(TranslateFPOProgramToDWARFExpression(
+      fpo_program, target_register_name, arch_type, stream));
+  EXPECT_EQ(0, stream.GetSize());
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, InvalidAssignmentSingle) {
+  CheckInvalidProgramTranslation("$T0 0", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, InvalidAssignmentMultiple) {
+  CheckInvalidProgramTranslation("$T1 0 = $T0 0", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, UnknownOp) {
+  CheckInvalidProgramTranslation("$T0 $ebp 0 & = ", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, InvalidOpBinary) {
+  CheckInvalidProgramTranslation("$T0 0 + = ", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, InvalidOpUnary) {
+  CheckInvalidProgramTranslation("$T0 ^ = ", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, MissingTargetRegister) {
+  CheckInvalidProgramTranslation("$T1 0 = ", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, UnresolvedRegisterReference) {
+  CheckInvalidProgramTranslation("$T0 $abc = ", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests,
+     UnresolvedRegisterAssignmentReference) {
+  CheckInvalidProgramTranslation("$T2 0 = $T0 $T1 = ", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests,
+     UnresolvedCyclicRegisterAssignmentReference) {
+  CheckInvalidProgramTranslation("$T1 $T0 = $T0 $T1 = ", "$T0");
+}
+
+TEST(PDBFPOProgramToDWARFExpressionTests, UnsupportedRASearch) {
+  CheckInvalidProgramTranslation("$T0 .raSearch = ", "$T0");
+}
Index: unittests/SymbolFile/PDB/CMakeLists.txt
===================================================================
--- unittests/SymbolFile/PDB/CMakeLists.txt
+++ unittests/SymbolFile/PDB/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_lldb_unittest(SymbolFilePDBTests
   SymbolFilePDBTests.cpp
+  PDBFPOProgramToDWARFExpressionTests.cpp
 
   LINK_LIBS
     lldbCore
Index: source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
===================================================================
--- source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
+++ source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp
@@ -951,12 +951,25 @@
 
   Variable::RangeList ranges;
   SymbolContextScope *context_scope = sc.comp_unit;
-  if (scope == eValueTypeVariableLocal) {
+  if (scope == eValueTypeVariableLocal || scope == eValueTypeVariableArgument) {
     if (sc.function) {
-      context_scope = sc.function->GetBlock(true).FindBlockByID(
-          pdb_data.getLexicalParentId());
-      if (context_scope == nullptr)
-        context_scope = sc.function;
+      Block &function_block = sc.function->GetBlock(true);
+      Block *block =
+          function_block.FindBlockByID(pdb_data.getLexicalParentId());
+      if (!block)
+        block = &function_block;
+
+      context_scope = block;
+
+      for (size_t i = 0, num_ranges = block->GetNumRanges(); i < num_ranges;
+           ++i) {
+        AddressRange range;
+        if (!block->GetRangeAtIndex(i, range))
+          continue;
+
+        ranges.Append(range.GetBaseAddress().GetFileAddress(),
+                      range.GetByteSize());
+      }
     }
   }
 
@@ -969,7 +982,7 @@
 
   bool is_constant;
   DWARFExpression location = ConvertPDBLocationToDWARFExpression(
-      GetObjectFile()->GetModule(), pdb_data, is_constant);
+      GetObjectFile()->GetModule(), pdb_data, ranges, is_constant);
 
   var_sp = std::make_shared<Variable>(
       var_uid, var_name.c_str(), mangled_cstr, type_sp, scope, context_scope,
Index: source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h
===================================================================
--- source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h
+++ source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.h
@@ -11,6 +11,7 @@
 #define lldb_Plugins_SymbolFile_PDB_PDBLocationToDWARFExpression_h_
 
 #include "lldb/Core/Module.h"
+#include "lldb/Symbol/Variable.h"
 
 namespace lldb_private {
 class DWARFExpression;
@@ -31,6 +32,9 @@
 /// @param[in] symbol
 ///     The symbol with a location information to convert.
 ///
+/// @param[in] ranges
+///     Ranges where this variable is valid.
+///
 /// @param[out] is_constant
 ///     Set to \b true if the result expression is a constant value data,
 ///     and \b false if it is a DWARF bytecode.
@@ -41,5 +45,6 @@
 lldb_private::DWARFExpression
 ConvertPDBLocationToDWARFExpression(lldb::ModuleSP module,
                                     const llvm::pdb::PDBSymbolData &symbol,
+                                    const lldb_private::Variable::RangeList &ranges,
                                     bool &is_constant);
 #endif
Index: source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
===================================================================
--- source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
+++ source/Plugins/SymbolFile/PDB/PDBLocationToDWARFExpression.cpp
@@ -8,488 +8,63 @@
 //===----------------------------------------------------------------------===//
 
 #include "PDBLocationToDWARFExpression.h"
+#include "CodeViewRegisterMapping.h"
+#include "PDBFPOProgramToDWARFExpression.h"
 
 #include "lldb/Core/Section.h"
 #include "lldb/Core/StreamBuffer.h"
 #include "lldb/Core/dwarf.h"
 #include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/Variable.h"
 #include "lldb/Utility/DataBufferHeap.h"
 
 #include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
 #include "llvm/DebugInfo/PDB/PDBSymbolData.h"
 
-#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
-
 using namespace lldb;
 using namespace lldb_private;
 using namespace llvm::pdb;
 
-namespace {
-const uint32_t g_code_view_to_lldb_registers_x86[] = {
-    LLDB_INVALID_REGNUM, // NONE
-    lldb_al_i386,        // AL
-    lldb_cl_i386,        // CL
-    lldb_dl_i386,        // DL
-    lldb_bl_i386,        // BL
-    lldb_ah_i386,        // AH
-    lldb_ch_i386,        // CH
-    lldb_dh_i386,        // DH
-    lldb_bh_i386,        // BH
-    lldb_ax_i386,        // AX
-    lldb_cx_i386,        // CX
-    lldb_dx_i386,        // DX
-    lldb_bx_i386,        // BX
-    lldb_sp_i386,        // SP
-    lldb_bp_i386,        // BP
-    lldb_si_i386,        // SI
-    lldb_di_i386,        // DI
-    lldb_eax_i386,       // EAX
-    lldb_ecx_i386,       // ECX
-    lldb_edx_i386,       // EDX
-    lldb_ebx_i386,       // EBX
-    lldb_esp_i386,       // ESP
-    lldb_ebp_i386,       // EBP
-    lldb_esi_i386,       // ESI
-    lldb_edi_i386,       // EDI
-    lldb_es_i386,        // ES
-    lldb_cs_i386,        // CS
-    lldb_ss_i386,        // SS
-    lldb_ds_i386,        // DS
-    lldb_fs_i386,        // FS
-    lldb_gs_i386,        // GS
-    LLDB_INVALID_REGNUM, // IP
-    LLDB_INVALID_REGNUM, // FLAGS
-    lldb_eip_i386,       // EIP
-    lldb_eflags_i386,    // EFLAGS
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, // TEMP
-    LLDB_INVALID_REGNUM, // TEMPH
-    LLDB_INVALID_REGNUM, // QUOTE
-    LLDB_INVALID_REGNUM, // PCDR3
-    LLDB_INVALID_REGNUM, // PCDR4
-    LLDB_INVALID_REGNUM, // PCDR5
-    LLDB_INVALID_REGNUM, // PCDR6
-    LLDB_INVALID_REGNUM, // PCDR7
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, // CR0
-    LLDB_INVALID_REGNUM, // CR1
-    LLDB_INVALID_REGNUM, // CR2
-    LLDB_INVALID_REGNUM, // CR3
-    LLDB_INVALID_REGNUM, // CR4
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    lldb_dr0_i386, // DR0
-    lldb_dr1_i386, // DR1
-    lldb_dr2_i386, // DR2
-    lldb_dr3_i386, // DR3
-    lldb_dr4_i386, // DR4
-    lldb_dr5_i386, // DR5
-    lldb_dr6_i386, // DR6
-    lldb_dr7_i386, // DR7
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, // GDTR
-    LLDB_INVALID_REGNUM, // GDTL
-    LLDB_INVALID_REGNUM, // IDTR
-    LLDB_INVALID_REGNUM, // IDTL
-    LLDB_INVALID_REGNUM, // LDTR
-    LLDB_INVALID_REGNUM, // TR
-    LLDB_INVALID_REGNUM, // PSEUDO1
-    LLDB_INVALID_REGNUM, // PSEUDO2
-    LLDB_INVALID_REGNUM, // PSEUDO3
-    LLDB_INVALID_REGNUM, // PSEUDO4
-    LLDB_INVALID_REGNUM, // PSEUDO5
-    LLDB_INVALID_REGNUM, // PSEUDO6
-    LLDB_INVALID_REGNUM, // PSEUDO7
-    LLDB_INVALID_REGNUM, // PSEUDO8
-    LLDB_INVALID_REGNUM, // PSEUDO9
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    lldb_st0_i386,       // ST0
-    lldb_st1_i386,       // ST1
-    lldb_st2_i386,       // ST2
-    lldb_st3_i386,       // ST3
-    lldb_st4_i386,       // ST4
-    lldb_st5_i386,       // ST5
-    lldb_st6_i386,       // ST6
-    lldb_st7_i386,       // ST7
-    LLDB_INVALID_REGNUM, // CTRL
-    LLDB_INVALID_REGNUM, // STAT
-    LLDB_INVALID_REGNUM, // TAG
-    LLDB_INVALID_REGNUM, // FPIP
-    LLDB_INVALID_REGNUM, // FPCS
-    LLDB_INVALID_REGNUM, // FPDO
-    LLDB_INVALID_REGNUM, // FPDS
-    LLDB_INVALID_REGNUM, // ISEM
-    LLDB_INVALID_REGNUM, // FPEIP
-    LLDB_INVALID_REGNUM, // FPEDO
-    lldb_mm0_i386,       // MM0
-    lldb_mm1_i386,       // MM1
-    lldb_mm2_i386,       // MM2
-    lldb_mm3_i386,       // MM3
-    lldb_mm4_i386,       // MM4
-    lldb_mm5_i386,       // MM5
-    lldb_mm6_i386,       // MM6
-    lldb_mm7_i386,       // MM7
-    lldb_xmm0_i386,      // XMM0
-    lldb_xmm1_i386,      // XMM1
-    lldb_xmm2_i386,      // XMM2
-    lldb_xmm3_i386,      // XMM3
-    lldb_xmm4_i386,      // XMM4
-    lldb_xmm5_i386,      // XMM5
-    lldb_xmm6_i386,      // XMM6
-    lldb_xmm7_i386       // XMM7
-};
-
-const uint32_t g_code_view_to_lldb_registers_x86_64[] = {
-    LLDB_INVALID_REGNUM, // NONE
-    lldb_al_x86_64,      // AL
-    lldb_cl_x86_64,      // CL
-    lldb_dl_x86_64,      // DL
-    lldb_bl_x86_64,      // BL
-    lldb_ah_x86_64,      // AH
-    lldb_ch_x86_64,      // CH
-    lldb_dh_x86_64,      // DH
-    lldb_bh_x86_64,      // BH
-    lldb_ax_x86_64,      // AX
-    lldb_cx_x86_64,      // CX
-    lldb_dx_x86_64,      // DX
-    lldb_bx_x86_64,      // BX
-    lldb_sp_x86_64,      // SP
-    lldb_bp_x86_64,      // BP
-    lldb_si_x86_64,      // SI
-    lldb_di_x86_64,      // DI
-    lldb_eax_x86_64,     // EAX
-    lldb_ecx_x86_64,     // ECX
-    lldb_edx_x86_64,     // EDX
-    lldb_ebx_x86_64,     // EBX
-    lldb_esp_x86_64,     // ESP
-    lldb_ebp_x86_64,     // EBP
-    lldb_esi_x86_64,     // ESI
-    lldb_edi_x86_64,     // EDI
-    lldb_es_x86_64,      // ES
-    lldb_cs_x86_64,      // CS
-    lldb_ss_x86_64,      // SS
-    lldb_ds_x86_64,      // DS
-    lldb_fs_x86_64,      // FS
-    lldb_gs_x86_64,      // GS
-    LLDB_INVALID_REGNUM, // IP
-    LLDB_INVALID_REGNUM, // FLAGS
-    LLDB_INVALID_REGNUM, // EIP
-    LLDB_INVALID_REGNUM, // EFLAGS
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, // TEMP
-    LLDB_INVALID_REGNUM, // TEMPH
-    LLDB_INVALID_REGNUM, // QUOTE
-    LLDB_INVALID_REGNUM, // PCDR3
-    LLDB_INVALID_REGNUM, // PCDR4
-    LLDB_INVALID_REGNUM, // PCDR5
-    LLDB_INVALID_REGNUM, // PCDR6
-    LLDB_INVALID_REGNUM, // PCDR7
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, // CR0
-    LLDB_INVALID_REGNUM, // CR1
-    LLDB_INVALID_REGNUM, // CR2
-    LLDB_INVALID_REGNUM, // CR3
-    LLDB_INVALID_REGNUM, // CR4
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    lldb_dr0_x86_64, // DR0
-    lldb_dr1_x86_64, // DR1
-    lldb_dr2_x86_64, // DR2
-    lldb_dr3_x86_64, // DR3
-    lldb_dr4_x86_64, // DR4
-    lldb_dr5_x86_64, // DR5
-    lldb_dr6_x86_64, // DR6
-    lldb_dr7_x86_64, // DR7
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, // GDTR
-    LLDB_INVALID_REGNUM, // GDTL
-    LLDB_INVALID_REGNUM, // IDTR
-    LLDB_INVALID_REGNUM, // IDTL
-    LLDB_INVALID_REGNUM, // LDTR
-    LLDB_INVALID_REGNUM, // TR
-    LLDB_INVALID_REGNUM, // PSEUDO1
-    LLDB_INVALID_REGNUM, // PSEUDO2
-    LLDB_INVALID_REGNUM, // PSEUDO3
-    LLDB_INVALID_REGNUM, // PSEUDO4
-    LLDB_INVALID_REGNUM, // PSEUDO5
-    LLDB_INVALID_REGNUM, // PSEUDO6
-    LLDB_INVALID_REGNUM, // PSEUDO7
-    LLDB_INVALID_REGNUM, // PSEUDO8
-    LLDB_INVALID_REGNUM, // PSEUDO9
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    lldb_st0_x86_64,     // ST0
-    lldb_st1_x86_64,     // ST1
-    lldb_st2_x86_64,     // ST2
-    lldb_st3_x86_64,     // ST3
-    lldb_st4_x86_64,     // ST4
-    lldb_st5_x86_64,     // ST5
-    lldb_st6_x86_64,     // ST6
-    lldb_st7_x86_64,     // ST7
-    LLDB_INVALID_REGNUM, // CTRL
-    LLDB_INVALID_REGNUM, // STAT
-    LLDB_INVALID_REGNUM, // TAG
-    LLDB_INVALID_REGNUM, // FPIP
-    LLDB_INVALID_REGNUM, // FPCS
-    LLDB_INVALID_REGNUM, // FPDO
-    LLDB_INVALID_REGNUM, // FPDS
-    LLDB_INVALID_REGNUM, // ISEM
-    LLDB_INVALID_REGNUM, // FPEIP
-    LLDB_INVALID_REGNUM, // FPEDO
-    lldb_mm0_x86_64,     // MM0
-    lldb_mm1_x86_64,     // MM1
-    lldb_mm2_x86_64,     // MM2
-    lldb_mm3_x86_64,     // MM3
-    lldb_mm4_x86_64,     // MM4
-    lldb_mm5_x86_64,     // MM5
-    lldb_mm6_x86_64,     // MM6
-    lldb_mm7_x86_64,     // MM7
-    lldb_xmm0_x86_64,    // XMM0
-    lldb_xmm1_x86_64,    // XMM1
-    lldb_xmm2_x86_64,    // XMM2
-    lldb_xmm3_x86_64,    // XMM3
-    lldb_xmm4_x86_64,    // XMM4
-    lldb_xmm5_x86_64,    // XMM5
-    lldb_xmm6_x86_64,    // XMM6
-    lldb_xmm7_x86_64,    // XMM7
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM,
-    lldb_mxcsr_x86_64,   // MXCSR
-    LLDB_INVALID_REGNUM, // EDXEAX
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, // EMM0L
-    LLDB_INVALID_REGNUM, // EMM1L
-    LLDB_INVALID_REGNUM, // EMM2L
-    LLDB_INVALID_REGNUM, // EMM3L
-    LLDB_INVALID_REGNUM, // EMM4L
-    LLDB_INVALID_REGNUM, // EMM5L
-    LLDB_INVALID_REGNUM, // EMM6L
-    LLDB_INVALID_REGNUM, // EMM7L
-    LLDB_INVALID_REGNUM, // EMM0H
-    LLDB_INVALID_REGNUM, // EMM1H
-    LLDB_INVALID_REGNUM, // EMM2H
-    LLDB_INVALID_REGNUM, // EMM3H
-    LLDB_INVALID_REGNUM, // EMM4H
-    LLDB_INVALID_REGNUM, // EMM5H
-    LLDB_INVALID_REGNUM, // EMM6H
-    LLDB_INVALID_REGNUM, // EMM7H
-    LLDB_INVALID_REGNUM, // MM00
-    LLDB_INVALID_REGNUM, // MM01
-    LLDB_INVALID_REGNUM, // MM10
-    LLDB_INVALID_REGNUM, // MM11
-    LLDB_INVALID_REGNUM, // MM20
-    LLDB_INVALID_REGNUM, // MM21
-    LLDB_INVALID_REGNUM, // MM30
-    LLDB_INVALID_REGNUM, // MM31
-    LLDB_INVALID_REGNUM, // MM40
-    LLDB_INVALID_REGNUM, // MM41
-    LLDB_INVALID_REGNUM, // MM50
-    LLDB_INVALID_REGNUM, // MM51
-    LLDB_INVALID_REGNUM, // MM60
-    LLDB_INVALID_REGNUM, // MM61
-    LLDB_INVALID_REGNUM, // MM70
-    LLDB_INVALID_REGNUM, // MM71
-    lldb_xmm8_x86_64,    // XMM8
-    lldb_xmm9_x86_64,    // XMM9
-    lldb_xmm10_x86_64,   // XMM10
-    lldb_xmm11_x86_64,   // XMM11
-    lldb_xmm12_x86_64,   // XMM12
-    lldb_xmm13_x86_64,   // XMM13
-    lldb_xmm14_x86_64,   // XMM14
-    lldb_xmm15_x86_64,   // XMM15
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM,
-    lldb_sil_x86_64,   // SIL
-    lldb_dil_x86_64,   // DIL
-    lldb_bpl_x86_64,   // BPL
-    lldb_spl_x86_64,   // SPL
-    lldb_rax_x86_64,   // RAX
-    lldb_rbx_x86_64,   // RBX
-    lldb_rcx_x86_64,   // RCX
-    lldb_rdx_x86_64,   // RDX
-    lldb_rsi_x86_64,   // RSI
-    lldb_rdi_x86_64,   // RDI
-    lldb_rbp_x86_64,   // RBP
-    lldb_rsp_x86_64,   // RSP
-    lldb_r8_x86_64,    // R8
-    lldb_r9_x86_64,    // R9
-    lldb_r10_x86_64,   // R10
-    lldb_r11_x86_64,   // R11
-    lldb_r12_x86_64,   // R12
-    lldb_r13_x86_64,   // R13
-    lldb_r14_x86_64,   // R14
-    lldb_r15_x86_64,   // R15
-    lldb_r8l_x86_64,   // R8B
-    lldb_r9l_x86_64,   // R9B
-    lldb_r10l_x86_64,  // R10B
-    lldb_r11l_x86_64,  // R11B
-    lldb_r12l_x86_64,  // R12B
-    lldb_r13l_x86_64,  // R13B
-    lldb_r14l_x86_64,  // R14B
-    lldb_r15l_x86_64,  // R15B
-    lldb_r8w_x86_64,   // R8W
-    lldb_r9w_x86_64,   // R9W
-    lldb_r10w_x86_64,  // R10W
-    lldb_r11w_x86_64,  // R11W
-    lldb_r12w_x86_64,  // R12W
-    lldb_r13w_x86_64,  // R13W
-    lldb_r14w_x86_64,  // R14W
-    lldb_r15w_x86_64,  // R15W
-    lldb_r8d_x86_64,   // R8D
-    lldb_r9d_x86_64,   // R9D
-    lldb_r10d_x86_64,  // R10D
-    lldb_r11d_x86_64,  // R11D
-    lldb_r12d_x86_64,  // R12D
-    lldb_r13d_x86_64,  // R13D
-    lldb_r14d_x86_64,  // R14D
-    lldb_r15d_x86_64,  // R15D
-    lldb_ymm0_x86_64,  // AMD64_YMM0
-    lldb_ymm1_x86_64,  // AMD64_YMM1
-    lldb_ymm2_x86_64,  // AMD64_YMM2
-    lldb_ymm3_x86_64,  // AMD64_YMM3
-    lldb_ymm4_x86_64,  // AMD64_YMM4
-    lldb_ymm5_x86_64,  // AMD64_YMM5
-    lldb_ymm6_x86_64,  // AMD64_YMM6
-    lldb_ymm7_x86_64,  // AMD64_YMM7
-    lldb_ymm8_x86_64,  // AMD64_YMM8
-    lldb_ymm9_x86_64,  // AMD64_YMM9
-    lldb_ymm10_x86_64, // AMD64_YMM10
-    lldb_ymm11_x86_64, // AMD64_YMM11
-    lldb_ymm12_x86_64, // AMD64_YMM12
-    lldb_ymm13_x86_64, // AMD64_YMM13
-    lldb_ymm14_x86_64, // AMD64_YMM14
-    lldb_ymm15_x86_64, // AMD64_YMM15
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
-    lldb_bnd0_x86_64, // BND0
-    lldb_bnd1_x86_64, // BND1
-    lldb_bnd2_x86_64  // BND2
-};
-
-uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
-                               llvm::codeview::RegisterId register_id) {
-  switch (arch_type) {
-  case llvm::Triple::x86:
-    if (static_cast<uint16_t>(register_id) <
-        sizeof(g_code_view_to_lldb_registers_x86) /
-            sizeof(g_code_view_to_lldb_registers_x86[0]))
-      return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>(
-          register_id)];
-
-    switch (register_id) {
-    case llvm::codeview::RegisterId::MXCSR:
-      return lldb_mxcsr_i386;
-    case llvm::codeview::RegisterId::BND0:
-      return lldb_bnd0_i386;
-    case llvm::codeview::RegisterId::BND1:
-      return lldb_bnd1_i386;
-    case llvm::codeview::RegisterId::BND2:
-      return lldb_bnd2_i386;
-    default:
-      return LLDB_INVALID_REGNUM;
+static std::unique_ptr<IPDBFrameData>
+GetCorrespondingFrameData(const IPDBSession &session,
+                          const Variable::RangeList &ranges) {
+  auto enumFrameData = session.getFrameData();
+  if (!enumFrameData)
+    return nullptr;
+
+  std::unique_ptr<IPDBFrameData> found;
+  while (auto fd = enumFrameData->getNext()) {
+    Range<lldb::addr_t, lldb::addr_t> fdRange(fd->getVirtualAddress(),
+                                              fd->getLengthBlock());
+
+    for (size_t i = 0; i < ranges.GetSize(); i++) {
+      auto range = ranges.GetEntryAtIndex(i);
+      if (!range)
+        continue;
+
+      if (!range->DoesIntersect(fdRange))
+        continue;
+
+      found = std::move(fd);
+
+      break;
     }
-  case llvm::Triple::x86_64:
-    if (static_cast<uint16_t>(register_id) <
-        sizeof(g_code_view_to_lldb_registers_x86_64) /
-            sizeof(g_code_view_to_lldb_registers_x86_64[0]))
-      return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>(
-          register_id)];
-
-    return LLDB_INVALID_REGNUM;
-  default:
-    return LLDB_INVALID_REGNUM;
   }
-}
-
-uint32_t GetGenericRegisterNumber(llvm::codeview::RegisterId register_id) {
-  if (register_id == llvm::codeview::RegisterId::VFRAME)
-    return LLDB_REGNUM_GENERIC_FP;
 
-  return LLDB_INVALID_REGNUM;
+  return found;
 }
 
-uint32_t GetRegisterNumber(llvm::Triple::ArchType arch_type,
-                           llvm::codeview::RegisterId register_id,
-                           RegisterKind &register_kind) {
-  register_kind = eRegisterKindLLDB;
-  uint32_t reg_num = GetLLDBRegisterNumber(arch_type, register_id);
-  if (reg_num != LLDB_INVALID_REGNUM)
-    return reg_num;
-
-  register_kind = eRegisterKindGeneric;
-  return GetGenericRegisterNumber(register_id);
+static bool EmitVFrameEvaluationDWARFExpression(
+    llvm::StringRef program, llvm::Triple::ArchType arch_type, Stream &stream) {
+  // VFrame value always stored in $TO pseudo-register
+  return TranslateFPOProgramToDWARFExpression(program, "$T0", arch_type,
+                                              stream);
 }
-} // namespace
 
-DWARFExpression ConvertPDBLocationToDWARFExpression(ModuleSP module,
-                                                    const PDBSymbolData &symbol,
-                                                    bool &is_constant) {
+DWARFExpression ConvertPDBLocationToDWARFExpression(
+    ModuleSP module, const PDBSymbolData &symbol,
+    const Variable::RangeList &ranges, bool &is_constant) {
   is_constant = true;
 
   if (!module)
@@ -531,10 +106,32 @@
     break;
   }
   case PDB_LocType::RegRel: {
-    uint32_t reg_num =
-        GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind);
-    if (reg_num == LLDB_INVALID_REGNUM)
-      return DWARFExpression(nullptr);
+    uint32_t reg_num;
+    auto reg_id = symbol.getRegisterId();
+    if (reg_id == llvm::codeview::RegisterId::VFRAME) {
+      if (auto fd = GetCorrespondingFrameData(symbol.getSession(), ranges)) {
+        if (EmitVFrameEvaluationDWARFExpression(fd->getProgram(), arch_type,
+                                                stream)) {
+          int32_t offset = symbol.getOffset();
+          stream.PutHex8(DW_OP_consts);
+          stream.PutSLEB128(offset);
+          stream.PutHex8(DW_OP_plus);
+
+          register_kind = eRegisterKindLLDB;
+
+          is_constant = false;
+          break;
+        }
+      }
+
+      register_kind = eRegisterKindGeneric;
+      reg_num = LLDB_REGNUM_GENERIC_FP;
+    } else {
+      register_kind = eRegisterKindLLDB;
+      reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
+      if (reg_num == LLDB_INVALID_REGNUM)
+        return DWARFExpression(nullptr);
+    }
 
     if (reg_num > 31) {
       stream.PutHex8(DW_OP_bregx);
@@ -550,8 +147,8 @@
     break;
   }
   case PDB_LocType::Enregistered: {
-    uint32_t reg_num =
-        GetRegisterNumber(arch_type, symbol.getRegisterId(), register_kind);
+    register_kind = eRegisterKindLLDB;
+    uint32_t reg_num = GetLLDBRegisterNumber(arch_type, symbol.getRegisterId());
     if (reg_num == LLDB_INVALID_REGNUM)
       return DWARFExpression(nullptr);
 
Index: source/Plugins/SymbolFile/PDB/PDBFPOProgramToDWARFExpression.h
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/PDB/PDBFPOProgramToDWARFExpression.h
@@ -0,0 +1,25 @@
+//===-- PDBFPOProgramToDWARFExpression.h ------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Plugins_SymbolFile_PDB_PDBFPOProgramToDWARFExpression_h_
+#define lldb_Plugins_SymbolFile_PDB_PDBFPOProgramToDWARFExpression_h_
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+
+namespace lldb_private {
+class Stream;
+}
+
+bool TranslateFPOProgramToDWARFExpression(llvm::StringRef program,
+                                          llvm::StringRef register_name,
+                                          llvm::Triple::ArchType arch_type,
+                                          lldb_private::Stream &stream);
+
+#endif
Index: source/Plugins/SymbolFile/PDB/PDBFPOProgramToDWARFExpression.cpp
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/PDB/PDBFPOProgramToDWARFExpression.cpp
@@ -0,0 +1,524 @@
+//===-- PDBFPOProgramToDWARFExpression.cpp ----------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "PDBFPOProgramToDWARFExpression.h"
+#include "CodeViewRegisterMapping.h"
+
+#include "lldb/Core/StreamBuffer.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Utility/LLDBAssert.h"
+#include "lldb/Utility/Stream.h"
+#include "llvm/ADT/DenseMap.h"
+
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+namespace {
+
+class FPOProgramNode;
+class FPOProgramASTVisitor;
+
+class FPOProgramNode {
+public:
+  enum Kind {
+    Register,
+    IntegerLiteral,
+    BinaryOp,
+    UnaryOp,
+  };
+
+protected:
+  FPOProgramNode(Kind kind) : m_token_kind(kind) {}
+
+public:
+  virtual ~FPOProgramNode() = default;
+  virtual void Accept(FPOProgramASTVisitor *visitor) = 0;
+
+  Kind GetKind() const { return m_token_kind; }
+
+private:
+  Kind m_token_kind;
+};
+
+class FPOProgramNodeRegisterRef : public FPOProgramNode {
+public:
+  FPOProgramNodeRegisterRef(llvm::StringRef name)
+      : FPOProgramNode(Register), m_name(name) {}
+
+  void Accept(FPOProgramASTVisitor *visitor) override;
+
+  llvm::StringRef GetName() const { return m_name; }
+  uint32_t GetLLDBRegNum() const { return m_lldb_reg_num; }
+
+  bool ResolveLLDBRegisterNum(llvm::Triple::ArchType arch_type);
+
+private:
+  llvm::StringRef m_name;
+  uint32_t m_lldb_reg_num = LLDB_INVALID_REGNUM;
+};
+
+bool FPOProgramNodeRegisterRef::ResolveLLDBRegisterNum(
+    llvm::Triple::ArchType arch_type) {
+
+  llvm::StringRef reg_name = m_name.slice(1, m_name.size());
+
+  // lookup register name to get lldb register number
+  llvm::ArrayRef<llvm::EnumEntry<uint16_t>> register_names =
+      llvm::codeview::getRegisterNames();
+  auto it = llvm::find_if(
+      register_names,
+      [&reg_name](const llvm::EnumEntry<uint16_t> &register_entry) {
+        return reg_name.compare_lower(register_entry.Name) == 0;
+      });
+
+  if (it == register_names.end()) {
+    return false;
+  }
+
+  auto reg_id = static_cast<llvm::codeview::RegisterId>(it->Value);
+  m_lldb_reg_num = GetLLDBRegisterNumber(arch_type, reg_id);
+
+  return m_lldb_reg_num != LLDB_INVALID_REGNUM;
+}
+
+class FPOProgramNodeIntegerLiteral : public FPOProgramNode {
+public:
+  FPOProgramNodeIntegerLiteral(uint32_t value)
+      : FPOProgramNode(IntegerLiteral), m_value(value) {}
+
+  void Accept(FPOProgramASTVisitor *visitor) override;
+
+  uint32_t GetValue() const { return m_value; }
+
+private:
+  uint32_t m_value;
+};
+
+class FPOProgramNodeBinaryOp : public FPOProgramNode {
+public:
+  enum OpType {
+    Plus,
+    Minus,
+    Align,
+  };
+
+  FPOProgramNodeBinaryOp(OpType op_type, FPOProgramNode *left,
+                         FPOProgramNode *right)
+      : FPOProgramNode(BinaryOp), m_op_type(op_type), m_left(left),
+        m_right(right) {}
+
+  void Accept(FPOProgramASTVisitor *visitor) override;
+
+  OpType GetOpType() const { return m_op_type; }
+
+  const FPOProgramNode *Left() const { return m_left; }
+  FPOProgramNode *&Left() { return m_left; }
+
+  const FPOProgramNode *Right() const { return m_right; }
+  FPOProgramNode *&Right() { return m_right; }
+
+private:
+  OpType m_op_type;
+  FPOProgramNode *m_left;
+  FPOProgramNode *m_right;
+};
+
+class FPOProgramNodeUnaryOp : public FPOProgramNode {
+public:
+  enum OpType {
+    Deref,
+  };
+
+  FPOProgramNodeUnaryOp(OpType op_type, FPOProgramNode *operand)
+      : FPOProgramNode(UnaryOp), m_op_type(op_type), m_operand(operand) {}
+
+  void Accept(FPOProgramASTVisitor *visitor) override;
+
+  OpType GetOpType() const { return m_op_type; }
+
+  const FPOProgramNode *Operand() const { return m_operand; }
+  FPOProgramNode *&Operand() { return m_operand; }
+
+private:
+  OpType m_op_type;
+  FPOProgramNode *m_operand;
+};
+
+class FPOProgramASTVisitor {
+public:
+  virtual ~FPOProgramASTVisitor() = default;
+
+  virtual void Visit(FPOProgramNodeRegisterRef *node) {}
+  virtual void Visit(FPOProgramNodeIntegerLiteral *node) {}
+  virtual void Visit(FPOProgramNodeBinaryOp *node) {}
+  virtual void Visit(FPOProgramNodeUnaryOp *node) {}
+};
+
+void FPOProgramNodeRegisterRef::Accept(FPOProgramASTVisitor *visitor) {
+  visitor->Visit(this);
+}
+
+void FPOProgramNodeIntegerLiteral::Accept(FPOProgramASTVisitor *visitor) {
+  visitor->Visit(this);
+}
+
+void FPOProgramNodeBinaryOp::Accept(FPOProgramASTVisitor *visitor) {
+  visitor->Visit(this);
+}
+
+void FPOProgramNodeUnaryOp::Accept(FPOProgramASTVisitor *visitor) {
+  visitor->Visit(this);
+}
+
+class FPOProgramASTVisitorMergeDependent : public FPOProgramASTVisitor {
+public:
+  FPOProgramASTVisitorMergeDependent(
+      const llvm::DenseMap<llvm::StringRef, FPOProgramNode *>
+          &dependent_programs)
+      : m_dependent_programs(dependent_programs) {}
+
+  void Merge(FPOProgramNode *&node_ref);
+
+private:
+  void Visit(FPOProgramNodeRegisterRef *node) override {}
+  void Visit(FPOProgramNodeIntegerLiteral *node) override {}
+  void Visit(FPOProgramNodeBinaryOp *node) override;
+  void Visit(FPOProgramNodeUnaryOp *node) override;
+
+  void TryReplace(FPOProgramNode *&node_ref) const;
+
+private:
+  const llvm::DenseMap<llvm::StringRef, FPOProgramNode *> &m_dependent_programs;
+};
+
+void FPOProgramASTVisitorMergeDependent::Merge(FPOProgramNode *&node_ref) {
+  TryReplace(node_ref);
+  node_ref->Accept(this);
+}
+
+void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeBinaryOp *node) {
+  Merge(node->Left());
+  Merge(node->Right());
+}
+void FPOProgramASTVisitorMergeDependent::Visit(FPOProgramNodeUnaryOp *node) {
+  Merge(node->Operand());
+}
+
+void FPOProgramASTVisitorMergeDependent::TryReplace(
+    FPOProgramNode *&node_ref) const {
+  if (node_ref->GetKind() != FPOProgramNode::Register) {
+    return;
+  }
+
+  auto *node_register_ref = static_cast<FPOProgramNodeRegisterRef *>(node_ref);
+
+  auto it = m_dependent_programs.find(node_register_ref->GetName());
+  if (it == m_dependent_programs.end()) {
+    return;
+  }
+
+  node_ref = it->second;
+}
+
+class FPOProgramASTVisitorResolveRegisterRefs : public FPOProgramASTVisitor {
+public:
+  FPOProgramASTVisitorResolveRegisterRefs(llvm::Triple::ArchType arch_type)
+      : m_arch_type(arch_type) {}
+
+  bool Resolve(FPOProgramNode *program);
+
+private:
+  void Visit(FPOProgramNodeRegisterRef *node) override;
+  void Visit(FPOProgramNodeIntegerLiteral *node) override {}
+  void Visit(FPOProgramNodeBinaryOp *node) override;
+  void Visit(FPOProgramNodeUnaryOp *node) override;
+
+private:
+  llvm::Triple::ArchType m_arch_type;
+  bool m_no_error_flag = true;
+};
+
+bool FPOProgramASTVisitorResolveRegisterRefs::Resolve(FPOProgramNode *program) {
+  program->Accept(this);
+  return m_no_error_flag;
+}
+
+void FPOProgramASTVisitorResolveRegisterRefs::Visit(
+    FPOProgramNodeRegisterRef *node) {
+  m_no_error_flag = node->ResolveLLDBRegisterNum(m_arch_type);
+}
+
+void FPOProgramASTVisitorResolveRegisterRefs::Visit(
+    FPOProgramNodeBinaryOp *node) {
+  m_no_error_flag = Resolve(node->Left()) && Resolve(node->Right());
+}
+
+void FPOProgramASTVisitorResolveRegisterRefs::Visit(
+    FPOProgramNodeUnaryOp *node) {
+  m_no_error_flag = Resolve(node->Operand());
+}
+
+class FPOProgramASTVisitorDWARFCodegen : public FPOProgramASTVisitor {
+public:
+  FPOProgramASTVisitorDWARFCodegen(Stream &stream) : m_out_stream(stream) {}
+
+  void Emit(FPOProgramNode *program);
+
+private:
+  void Visit(FPOProgramNodeRegisterRef *node) override;
+  void Visit(FPOProgramNodeIntegerLiteral *node) override;
+  void Visit(FPOProgramNodeBinaryOp *node) override;
+  void Visit(FPOProgramNodeUnaryOp *node) override;
+
+private:
+  Stream &m_out_stream;
+};
+
+void FPOProgramASTVisitorDWARFCodegen::Emit(FPOProgramNode *program) {
+  program->Accept(this);
+}
+
+void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeRegisterRef *node) {
+
+  uint32_t reg_num = node->GetLLDBRegNum();
+  lldbassert(reg_num != LLDB_INVALID_REGNUM);
+
+  if (reg_num > 31) {
+    m_out_stream.PutHex8(DW_OP_bregx);
+    m_out_stream.PutULEB128(reg_num);
+  } else
+    m_out_stream.PutHex8(DW_OP_breg0 + reg_num);
+
+  m_out_stream.PutSLEB128(0);
+}
+
+void FPOProgramASTVisitorDWARFCodegen::Visit(
+    FPOProgramNodeIntegerLiteral *node) {
+  uint32_t value = node->GetValue();
+  m_out_stream.PutHex8(DW_OP_constu);
+  m_out_stream.PutULEB128(value);
+}
+
+void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeBinaryOp *node) {
+
+  Emit(node->Left());
+  Emit(node->Right());
+
+  switch (node->GetOpType()) {
+  case FPOProgramNodeBinaryOp::Plus:
+    m_out_stream.PutHex8(DW_OP_plus);
+    // NOTE: can be optimized by using DW_OP_plus_uconst opcpode
+    //       if right child node is constant value
+    break;
+  case FPOProgramNodeBinaryOp::Minus:
+    m_out_stream.PutHex8(DW_OP_minus);
+    break;
+  case FPOProgramNodeBinaryOp::Align:
+    // emit align operator a @ b as
+    // a & ~(b - 1)
+    // NOTE: implicitly assuming that b is power of 2
+    m_out_stream.PutHex8(DW_OP_lit1);
+    m_out_stream.PutHex8(DW_OP_minus);
+    m_out_stream.PutHex8(DW_OP_not);
+
+    m_out_stream.PutHex8(DW_OP_and);
+    break;
+  default:
+    llvm_unreachable("Invalid binary operation");
+  }
+}
+
+void FPOProgramASTVisitorDWARFCodegen::Visit(FPOProgramNodeUnaryOp *node) {
+  Emit(node->Operand());
+
+  switch (node->GetOpType()) {
+  case FPOProgramNodeUnaryOp::Deref:
+    m_out_stream.PutHex8(DW_OP_deref);
+    break;
+  default:
+    llvm_unreachable("Invalid unary operation");
+  }
+}
+
+class NodeAllocator {
+public:
+  template <typename T, typename... Args> T *makeNode(Args &&... args) {
+    void *new_node_mem = m_alloc.Allocate(sizeof(T), alignof(T));
+    return new (new_node_mem) T(std::forward<Args>(args)...);
+  }
+
+private:
+  llvm::BumpPtrAllocator m_alloc;
+};
+
+} // namespace
+
+static bool ParseFPOSingleAssignmentProgram(llvm::StringRef program,
+                                            NodeAllocator &alloc,
+                                            llvm::StringRef &register_name,
+                                            FPOProgramNode *&ast) {
+  llvm::SmallVector<llvm::StringRef, 16> tokens;
+  llvm::SplitString(program, tokens, " ");
+
+  if (tokens.empty())
+    return false;
+
+  llvm::SmallVector<FPOProgramNode *, 4> eval_stack;
+
+  llvm::DenseMap<llvm::StringRef, FPOProgramNodeBinaryOp::OpType> ops_binary = {
+      {"+", FPOProgramNodeBinaryOp::Plus},
+      {"-", FPOProgramNodeBinaryOp::Minus},
+      {"@", FPOProgramNodeBinaryOp::Align},
+  };
+
+  llvm::DenseMap<llvm::StringRef, FPOProgramNodeUnaryOp::OpType> ops_unary = {
+      {"^", FPOProgramNodeUnaryOp::Deref},
+  };
+
+  constexpr llvm::StringLiteral ra_search_keyword = ".raSearch";
+
+  // lvalue of assignment is always first token
+  // rvalue program goes next
+  for (size_t i = 1; i < tokens.size(); ++i) {
+    llvm::StringRef cur = tokens[i];
+
+    auto ops_binary_it = ops_binary.find(cur);
+    if (ops_binary_it != ops_binary.end()) {
+      // token is binary operator
+      if (eval_stack.size() < 2) {
+        return false;
+      }
+      FPOProgramNode *right = eval_stack.pop_back_val();
+      FPOProgramNode *left = eval_stack.pop_back_val();
+      FPOProgramNode *node = alloc.makeNode<FPOProgramNodeBinaryOp>(
+          ops_binary_it->second, left, right);
+      eval_stack.push_back(node);
+      continue;
+    }
+
+    auto ops_unary_it = ops_unary.find(cur);
+    if (ops_unary_it != ops_unary.end()) {
+      // token is unary operator
+      if (eval_stack.empty()) {
+        return false;
+      }
+      FPOProgramNode *operand = eval_stack.pop_back_val();
+      FPOProgramNode *node =
+          alloc.makeNode<FPOProgramNodeUnaryOp>(ops_unary_it->second, operand);
+      eval_stack.push_back(node);
+      continue;
+    }
+
+    if (cur.startswith("$")) {
+      // token is register ref
+      eval_stack.push_back(alloc.makeNode<FPOProgramNodeRegisterRef>(cur));
+      continue;
+    }
+
+    if (cur == ra_search_keyword) {
+      // TODO: .raSearch is unsupported
+      return false;
+    }
+
+    uint32_t value;
+    if (!cur.getAsInteger(10, value)) {
+      // token is integer literal
+      eval_stack.push_back(alloc.makeNode<FPOProgramNodeIntegerLiteral>(value));
+      continue;
+    }
+
+    // unexpected token
+    return false;
+  }
+
+  if (eval_stack.size() != 1) {
+    return false;
+  }
+
+  register_name = tokens[0];
+  ast = eval_stack.pop_back_val();
+
+  return true;
+}
+
+static FPOProgramNode *ParseFPOProgram(llvm::StringRef program,
+                                       llvm::StringRef register_name,
+                                       NodeAllocator &alloc) {
+  FPOProgramNode *result = nullptr;
+
+  llvm::DenseMap<llvm::StringRef, FPOProgramNode *> dependent_programs;
+
+  size_t cur = 0;
+  while (true) {
+    size_t assign_index = program.find('=', cur);
+    if (assign_index == llvm::StringRef::npos) {
+      llvm::StringRef tail = program.slice(cur, llvm::StringRef::npos);
+      if (!tail.trim().empty()) {
+        // missing assign operator
+        return result;
+      }
+      break;
+    }
+    llvm::StringRef assignment_program = program.slice(cur, assign_index);
+
+    llvm::StringRef lvalue_name;
+    FPOProgramNode *rvalue_ast = nullptr;
+    if (!ParseFPOSingleAssignmentProgram(assignment_program, alloc, lvalue_name,
+                                         rvalue_ast)) {
+      return result;
+    }
+
+    lldbassert(rvalue_ast);
+
+    if (lvalue_name == register_name) {
+      // found target assignment program - no need to parse further
+      result = rvalue_ast;
+      break;
+    }
+
+    dependent_programs[lvalue_name] = rvalue_ast;
+    cur = assign_index + 1;
+  }
+
+  if (result == nullptr) {
+    // target register assignment wasn't found
+    return result;
+  }
+
+  // emplace dependent subtrees into target program
+  FPOProgramASTVisitorMergeDependent merger(dependent_programs);
+  merger.Merge(result);
+
+  return result;
+}
+
+bool TranslateFPOProgramToDWARFExpression(llvm::StringRef program,
+                                          llvm::StringRef register_name,
+                                          llvm::Triple::ArchType arch_type,
+                                          Stream &stream) {
+  NodeAllocator node_alloc;
+  FPOProgramNode *target_program =
+      ParseFPOProgram(program, register_name, node_alloc);
+  if (target_program == nullptr) {
+    return false;
+  }
+
+  FPOProgramASTVisitorResolveRegisterRefs resolver(arch_type);
+  if (!resolver.Resolve(target_program)) {
+    return false;
+  }
+
+  FPOProgramASTVisitorDWARFCodegen codegen(stream);
+  codegen.Emit(target_program);
+  return true;
+}
Index: source/Plugins/SymbolFile/PDB/CodeViewRegisterMapping.h
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/PDB/CodeViewRegisterMapping.h
@@ -0,0 +1,19 @@
+//===-- CodeViewRegisterMapping.h -------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_Plugins_SymbolFile_PDB_CodeViewRegisterMapping_h_
+#define lldb_Plugins_SymbolFile_PDB_CodeViewRegisterMapping_h_
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+
+uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
+                               llvm::codeview::RegisterId register_id);
+
+#endif
Index: source/Plugins/SymbolFile/PDB/CodeViewRegisterMapping.cpp
===================================================================
--- /dev/null
+++ source/Plugins/SymbolFile/PDB/CodeViewRegisterMapping.cpp
@@ -0,0 +1,458 @@
+//===-- CodeViewRegisterMapping.cpp -----------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "CodeViewRegisterMapping.h"
+
+#include "lldb/lldb-defines.h"
+
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+using namespace lldb_private;
+
+static const uint32_t g_code_view_to_lldb_registers_x86[] = {
+    LLDB_INVALID_REGNUM, // NONE
+    lldb_al_i386,        // AL
+    lldb_cl_i386,        // CL
+    lldb_dl_i386,        // DL
+    lldb_bl_i386,        // BL
+    lldb_ah_i386,        // AH
+    lldb_ch_i386,        // CH
+    lldb_dh_i386,        // DH
+    lldb_bh_i386,        // BH
+    lldb_ax_i386,        // AX
+    lldb_cx_i386,        // CX
+    lldb_dx_i386,        // DX
+    lldb_bx_i386,        // BX
+    lldb_sp_i386,        // SP
+    lldb_bp_i386,        // BP
+    lldb_si_i386,        // SI
+    lldb_di_i386,        // DI
+    lldb_eax_i386,       // EAX
+    lldb_ecx_i386,       // ECX
+    lldb_edx_i386,       // EDX
+    lldb_ebx_i386,       // EBX
+    lldb_esp_i386,       // ESP
+    lldb_ebp_i386,       // EBP
+    lldb_esi_i386,       // ESI
+    lldb_edi_i386,       // EDI
+    lldb_es_i386,        // ES
+    lldb_cs_i386,        // CS
+    lldb_ss_i386,        // SS
+    lldb_ds_i386,        // DS
+    lldb_fs_i386,        // FS
+    lldb_gs_i386,        // GS
+    LLDB_INVALID_REGNUM, // IP
+    LLDB_INVALID_REGNUM, // FLAGS
+    lldb_eip_i386,       // EIP
+    lldb_eflags_i386,    // EFLAGS
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, // TEMP
+    LLDB_INVALID_REGNUM, // TEMPH
+    LLDB_INVALID_REGNUM, // QUOTE
+    LLDB_INVALID_REGNUM, // PCDR3
+    LLDB_INVALID_REGNUM, // PCDR4
+    LLDB_INVALID_REGNUM, // PCDR5
+    LLDB_INVALID_REGNUM, // PCDR6
+    LLDB_INVALID_REGNUM, // PCDR7
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, // CR0
+    LLDB_INVALID_REGNUM, // CR1
+    LLDB_INVALID_REGNUM, // CR2
+    LLDB_INVALID_REGNUM, // CR3
+    LLDB_INVALID_REGNUM, // CR4
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    lldb_dr0_i386, // DR0
+    lldb_dr1_i386, // DR1
+    lldb_dr2_i386, // DR2
+    lldb_dr3_i386, // DR3
+    lldb_dr4_i386, // DR4
+    lldb_dr5_i386, // DR5
+    lldb_dr6_i386, // DR6
+    lldb_dr7_i386, // DR7
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, // GDTR
+    LLDB_INVALID_REGNUM, // GDTL
+    LLDB_INVALID_REGNUM, // IDTR
+    LLDB_INVALID_REGNUM, // IDTL
+    LLDB_INVALID_REGNUM, // LDTR
+    LLDB_INVALID_REGNUM, // TR
+    LLDB_INVALID_REGNUM, // PSEUDO1
+    LLDB_INVALID_REGNUM, // PSEUDO2
+    LLDB_INVALID_REGNUM, // PSEUDO3
+    LLDB_INVALID_REGNUM, // PSEUDO4
+    LLDB_INVALID_REGNUM, // PSEUDO5
+    LLDB_INVALID_REGNUM, // PSEUDO6
+    LLDB_INVALID_REGNUM, // PSEUDO7
+    LLDB_INVALID_REGNUM, // PSEUDO8
+    LLDB_INVALID_REGNUM, // PSEUDO9
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    lldb_st0_i386,       // ST0
+    lldb_st1_i386,       // ST1
+    lldb_st2_i386,       // ST2
+    lldb_st3_i386,       // ST3
+    lldb_st4_i386,       // ST4
+    lldb_st5_i386,       // ST5
+    lldb_st6_i386,       // ST6
+    lldb_st7_i386,       // ST7
+    LLDB_INVALID_REGNUM, // CTRL
+    LLDB_INVALID_REGNUM, // STAT
+    LLDB_INVALID_REGNUM, // TAG
+    LLDB_INVALID_REGNUM, // FPIP
+    LLDB_INVALID_REGNUM, // FPCS
+    LLDB_INVALID_REGNUM, // FPDO
+    LLDB_INVALID_REGNUM, // FPDS
+    LLDB_INVALID_REGNUM, // ISEM
+    LLDB_INVALID_REGNUM, // FPEIP
+    LLDB_INVALID_REGNUM, // FPEDO
+    lldb_mm0_i386,       // MM0
+    lldb_mm1_i386,       // MM1
+    lldb_mm2_i386,       // MM2
+    lldb_mm3_i386,       // MM3
+    lldb_mm4_i386,       // MM4
+    lldb_mm5_i386,       // MM5
+    lldb_mm6_i386,       // MM6
+    lldb_mm7_i386,       // MM7
+    lldb_xmm0_i386,      // XMM0
+    lldb_xmm1_i386,      // XMM1
+    lldb_xmm2_i386,      // XMM2
+    lldb_xmm3_i386,      // XMM3
+    lldb_xmm4_i386,      // XMM4
+    lldb_xmm5_i386,      // XMM5
+    lldb_xmm6_i386,      // XMM6
+    lldb_xmm7_i386       // XMM7
+};
+
+static const uint32_t g_code_view_to_lldb_registers_x86_64[] = {
+    LLDB_INVALID_REGNUM, // NONE
+    lldb_al_x86_64,      // AL
+    lldb_cl_x86_64,      // CL
+    lldb_dl_x86_64,      // DL
+    lldb_bl_x86_64,      // BL
+    lldb_ah_x86_64,      // AH
+    lldb_ch_x86_64,      // CH
+    lldb_dh_x86_64,      // DH
+    lldb_bh_x86_64,      // BH
+    lldb_ax_x86_64,      // AX
+    lldb_cx_x86_64,      // CX
+    lldb_dx_x86_64,      // DX
+    lldb_bx_x86_64,      // BX
+    lldb_sp_x86_64,      // SP
+    lldb_bp_x86_64,      // BP
+    lldb_si_x86_64,      // SI
+    lldb_di_x86_64,      // DI
+    lldb_eax_x86_64,     // EAX
+    lldb_ecx_x86_64,     // ECX
+    lldb_edx_x86_64,     // EDX
+    lldb_ebx_x86_64,     // EBX
+    lldb_esp_x86_64,     // ESP
+    lldb_ebp_x86_64,     // EBP
+    lldb_esi_x86_64,     // ESI
+    lldb_edi_x86_64,     // EDI
+    lldb_es_x86_64,      // ES
+    lldb_cs_x86_64,      // CS
+    lldb_ss_x86_64,      // SS
+    lldb_ds_x86_64,      // DS
+    lldb_fs_x86_64,      // FS
+    lldb_gs_x86_64,      // GS
+    LLDB_INVALID_REGNUM, // IP
+    LLDB_INVALID_REGNUM, // FLAGS
+    LLDB_INVALID_REGNUM, // EIP
+    LLDB_INVALID_REGNUM, // EFLAGS
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, // TEMP
+    LLDB_INVALID_REGNUM, // TEMPH
+    LLDB_INVALID_REGNUM, // QUOTE
+    LLDB_INVALID_REGNUM, // PCDR3
+    LLDB_INVALID_REGNUM, // PCDR4
+    LLDB_INVALID_REGNUM, // PCDR5
+    LLDB_INVALID_REGNUM, // PCDR6
+    LLDB_INVALID_REGNUM, // PCDR7
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, // CR0
+    LLDB_INVALID_REGNUM, // CR1
+    LLDB_INVALID_REGNUM, // CR2
+    LLDB_INVALID_REGNUM, // CR3
+    LLDB_INVALID_REGNUM, // CR4
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    lldb_dr0_x86_64, // DR0
+    lldb_dr1_x86_64, // DR1
+    lldb_dr2_x86_64, // DR2
+    lldb_dr3_x86_64, // DR3
+    lldb_dr4_x86_64, // DR4
+    lldb_dr5_x86_64, // DR5
+    lldb_dr6_x86_64, // DR6
+    lldb_dr7_x86_64, // DR7
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, // GDTR
+    LLDB_INVALID_REGNUM, // GDTL
+    LLDB_INVALID_REGNUM, // IDTR
+    LLDB_INVALID_REGNUM, // IDTL
+    LLDB_INVALID_REGNUM, // LDTR
+    LLDB_INVALID_REGNUM, // TR
+    LLDB_INVALID_REGNUM, // PSEUDO1
+    LLDB_INVALID_REGNUM, // PSEUDO2
+    LLDB_INVALID_REGNUM, // PSEUDO3
+    LLDB_INVALID_REGNUM, // PSEUDO4
+    LLDB_INVALID_REGNUM, // PSEUDO5
+    LLDB_INVALID_REGNUM, // PSEUDO6
+    LLDB_INVALID_REGNUM, // PSEUDO7
+    LLDB_INVALID_REGNUM, // PSEUDO8
+    LLDB_INVALID_REGNUM, // PSEUDO9
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    lldb_st0_x86_64,     // ST0
+    lldb_st1_x86_64,     // ST1
+    lldb_st2_x86_64,     // ST2
+    lldb_st3_x86_64,     // ST3
+    lldb_st4_x86_64,     // ST4
+    lldb_st5_x86_64,     // ST5
+    lldb_st6_x86_64,     // ST6
+    lldb_st7_x86_64,     // ST7
+    LLDB_INVALID_REGNUM, // CTRL
+    LLDB_INVALID_REGNUM, // STAT
+    LLDB_INVALID_REGNUM, // TAG
+    LLDB_INVALID_REGNUM, // FPIP
+    LLDB_INVALID_REGNUM, // FPCS
+    LLDB_INVALID_REGNUM, // FPDO
+    LLDB_INVALID_REGNUM, // FPDS
+    LLDB_INVALID_REGNUM, // ISEM
+    LLDB_INVALID_REGNUM, // FPEIP
+    LLDB_INVALID_REGNUM, // FPEDO
+    lldb_mm0_x86_64,     // MM0
+    lldb_mm1_x86_64,     // MM1
+    lldb_mm2_x86_64,     // MM2
+    lldb_mm3_x86_64,     // MM3
+    lldb_mm4_x86_64,     // MM4
+    lldb_mm5_x86_64,     // MM5
+    lldb_mm6_x86_64,     // MM6
+    lldb_mm7_x86_64,     // MM7
+    lldb_xmm0_x86_64,    // XMM0
+    lldb_xmm1_x86_64,    // XMM1
+    lldb_xmm2_x86_64,    // XMM2
+    lldb_xmm3_x86_64,    // XMM3
+    lldb_xmm4_x86_64,    // XMM4
+    lldb_xmm5_x86_64,    // XMM5
+    lldb_xmm6_x86_64,    // XMM6
+    lldb_xmm7_x86_64,    // XMM7
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM,
+    lldb_mxcsr_x86_64,   // MXCSR
+    LLDB_INVALID_REGNUM, // EDXEAX
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, // EMM0L
+    LLDB_INVALID_REGNUM, // EMM1L
+    LLDB_INVALID_REGNUM, // EMM2L
+    LLDB_INVALID_REGNUM, // EMM3L
+    LLDB_INVALID_REGNUM, // EMM4L
+    LLDB_INVALID_REGNUM, // EMM5L
+    LLDB_INVALID_REGNUM, // EMM6L
+    LLDB_INVALID_REGNUM, // EMM7L
+    LLDB_INVALID_REGNUM, // EMM0H
+    LLDB_INVALID_REGNUM, // EMM1H
+    LLDB_INVALID_REGNUM, // EMM2H
+    LLDB_INVALID_REGNUM, // EMM3H
+    LLDB_INVALID_REGNUM, // EMM4H
+    LLDB_INVALID_REGNUM, // EMM5H
+    LLDB_INVALID_REGNUM, // EMM6H
+    LLDB_INVALID_REGNUM, // EMM7H
+    LLDB_INVALID_REGNUM, // MM00
+    LLDB_INVALID_REGNUM, // MM01
+    LLDB_INVALID_REGNUM, // MM10
+    LLDB_INVALID_REGNUM, // MM11
+    LLDB_INVALID_REGNUM, // MM20
+    LLDB_INVALID_REGNUM, // MM21
+    LLDB_INVALID_REGNUM, // MM30
+    LLDB_INVALID_REGNUM, // MM31
+    LLDB_INVALID_REGNUM, // MM40
+    LLDB_INVALID_REGNUM, // MM41
+    LLDB_INVALID_REGNUM, // MM50
+    LLDB_INVALID_REGNUM, // MM51
+    LLDB_INVALID_REGNUM, // MM60
+    LLDB_INVALID_REGNUM, // MM61
+    LLDB_INVALID_REGNUM, // MM70
+    LLDB_INVALID_REGNUM, // MM71
+    lldb_xmm8_x86_64,    // XMM8
+    lldb_xmm9_x86_64,    // XMM9
+    lldb_xmm10_x86_64,   // XMM10
+    lldb_xmm11_x86_64,   // XMM11
+    lldb_xmm12_x86_64,   // XMM12
+    lldb_xmm13_x86_64,   // XMM13
+    lldb_xmm14_x86_64,   // XMM14
+    lldb_xmm15_x86_64,   // XMM15
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM,
+    lldb_sil_x86_64,   // SIL
+    lldb_dil_x86_64,   // DIL
+    lldb_bpl_x86_64,   // BPL
+    lldb_spl_x86_64,   // SPL
+    lldb_rax_x86_64,   // RAX
+    lldb_rbx_x86_64,   // RBX
+    lldb_rcx_x86_64,   // RCX
+    lldb_rdx_x86_64,   // RDX
+    lldb_rsi_x86_64,   // RSI
+    lldb_rdi_x86_64,   // RDI
+    lldb_rbp_x86_64,   // RBP
+    lldb_rsp_x86_64,   // RSP
+    lldb_r8_x86_64,    // R8
+    lldb_r9_x86_64,    // R9
+    lldb_r10_x86_64,   // R10
+    lldb_r11_x86_64,   // R11
+    lldb_r12_x86_64,   // R12
+    lldb_r13_x86_64,   // R13
+    lldb_r14_x86_64,   // R14
+    lldb_r15_x86_64,   // R15
+    lldb_r8l_x86_64,   // R8B
+    lldb_r9l_x86_64,   // R9B
+    lldb_r10l_x86_64,  // R10B
+    lldb_r11l_x86_64,  // R11B
+    lldb_r12l_x86_64,  // R12B
+    lldb_r13l_x86_64,  // R13B
+    lldb_r14l_x86_64,  // R14B
+    lldb_r15l_x86_64,  // R15B
+    lldb_r8w_x86_64,   // R8W
+    lldb_r9w_x86_64,   // R9W
+    lldb_r10w_x86_64,  // R10W
+    lldb_r11w_x86_64,  // R11W
+    lldb_r12w_x86_64,  // R12W
+    lldb_r13w_x86_64,  // R13W
+    lldb_r14w_x86_64,  // R14W
+    lldb_r15w_x86_64,  // R15W
+    lldb_r8d_x86_64,   // R8D
+    lldb_r9d_x86_64,   // R9D
+    lldb_r10d_x86_64,  // R10D
+    lldb_r11d_x86_64,  // R11D
+    lldb_r12d_x86_64,  // R12D
+    lldb_r13d_x86_64,  // R13D
+    lldb_r14d_x86_64,  // R14D
+    lldb_r15d_x86_64,  // R15D
+    lldb_ymm0_x86_64,  // AMD64_YMM0
+    lldb_ymm1_x86_64,  // AMD64_YMM1
+    lldb_ymm2_x86_64,  // AMD64_YMM2
+    lldb_ymm3_x86_64,  // AMD64_YMM3
+    lldb_ymm4_x86_64,  // AMD64_YMM4
+    lldb_ymm5_x86_64,  // AMD64_YMM5
+    lldb_ymm6_x86_64,  // AMD64_YMM6
+    lldb_ymm7_x86_64,  // AMD64_YMM7
+    lldb_ymm8_x86_64,  // AMD64_YMM8
+    lldb_ymm9_x86_64,  // AMD64_YMM9
+    lldb_ymm10_x86_64, // AMD64_YMM10
+    lldb_ymm11_x86_64, // AMD64_YMM11
+    lldb_ymm12_x86_64, // AMD64_YMM12
+    lldb_ymm13_x86_64, // AMD64_YMM13
+    lldb_ymm14_x86_64, // AMD64_YMM14
+    lldb_ymm15_x86_64, // AMD64_YMM15
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+    lldb_bnd0_x86_64, // BND0
+    lldb_bnd1_x86_64, // BND1
+    lldb_bnd2_x86_64  // BND2
+};
+
+uint32_t GetLLDBRegisterNumber(llvm::Triple::ArchType arch_type,
+                               llvm::codeview::RegisterId register_id) {
+  switch (arch_type) {
+  case llvm::Triple::x86:
+    if (static_cast<uint16_t>(register_id) <
+        sizeof(g_code_view_to_lldb_registers_x86) /
+            sizeof(g_code_view_to_lldb_registers_x86[0]))
+      return g_code_view_to_lldb_registers_x86[static_cast<uint16_t>(
+          register_id)];
+
+    switch (register_id) {
+    case llvm::codeview::RegisterId::MXCSR:
+      return lldb_mxcsr_i386;
+    case llvm::codeview::RegisterId::BND0:
+      return lldb_bnd0_i386;
+    case llvm::codeview::RegisterId::BND1:
+      return lldb_bnd1_i386;
+    case llvm::codeview::RegisterId::BND2:
+      return lldb_bnd2_i386;
+    default:
+      return LLDB_INVALID_REGNUM;
+    }
+  case llvm::Triple::x86_64:
+    if (static_cast<uint16_t>(register_id) <
+        sizeof(g_code_view_to_lldb_registers_x86_64) /
+            sizeof(g_code_view_to_lldb_registers_x86_64[0]))
+      return g_code_view_to_lldb_registers_x86_64[static_cast<uint16_t>(
+          register_id)];
+
+    return LLDB_INVALID_REGNUM;
+  default:
+    return LLDB_INVALID_REGNUM;
+  }
+}
Index: source/Plugins/SymbolFile/PDB/CMakeLists.txt
===================================================================
--- source/Plugins/SymbolFile/PDB/CMakeLists.txt
+++ source/Plugins/SymbolFile/PDB/CMakeLists.txt
@@ -1,7 +1,9 @@
 add_lldb_library(lldbPluginSymbolFilePDB PLUGIN
   PDBASTParser.cpp
   PDBLocationToDWARFExpression.cpp
+  PDBFPOProgramToDWARFExpression.cpp
   SymbolFilePDB.cpp
+  CodeViewRegisterMapping.cpp
 
   LINK_LIBS
     clangAST
Index: source/Expression/DWARFExpression.cpp
===================================================================
--- source/Expression/DWARFExpression.cpp
+++ source/Expression/DWARFExpression.cpp
@@ -3250,7 +3250,7 @@
     break;
   }
 
-  return false;
+  return true;
 }
 
 bool DWARFExpression::PrintDWARFExpression(Stream &s, const DataExtractor &data,
Index: lit/SymbolFile/PDB/variables-locations.test
===================================================================
--- lit/SymbolFile/PDB/variables-locations.test
+++ lit/SymbolFile/PDB/variables-locations.test
@@ -13,3 +13,8 @@
 
 CHECK: loc_0 = true
 CHECK: loc_1 = 3333
+
+CHECK: arg_0 = 22
+
+CHECK: loc_0 = (a = 1234)
+CHECK: loc_1 = 5678
Index: lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.script
===================================================================
--- lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.script
+++ lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.script
@@ -1,4 +1,5 @@
 breakpoint set --file VariablesLocationsTest.cpp --line 6
+breakpoint set --file VariablesLocationsTest.cpp --line 15
 
 run
 
@@ -14,3 +15,11 @@
 
 frame variable loc_0
 frame variable loc_1
+
+continue
+
+frame variable arg_0
+
+frame variable loc_0
+frame variable loc_1
+
Index: lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.cpp
===================================================================
--- lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.cpp
+++ lit/SymbolFile/PDB/Inputs/VariablesLocationsTest.cpp
@@ -5,11 +5,22 @@
   double loc_1 = 0.5678;
 }
 
+__declspec(align(128)) struct S {
+  int a = 1234;
+};
+
+void bar(int arg_0) {
+ S loc_0;
+ int loc_1 = 5678;
+}
+
+
 int main(int argc, char *argv[]) {
   bool loc_0 = true;
   int loc_1 = 3333;
 
   foo(1111, 0.1234);
+  bar(22);
 
   return 0;
 }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to