Index: llvm/include/llvm/BinaryFormat/Dwarf.h
===================================================================
--- llvm/include/llvm/BinaryFormat/Dwarf.h
+++ llvm/include/llvm/BinaryFormat/Dwarf.h
@@ -59,7 +59,8 @@
   DWARF_VENDOR_GNU = 3,
   DWARF_VENDOR_GOOGLE = 4,
   DWARF_VENDOR_LLVM = 5,
-  DWARF_VENDOR_MIPS = 6
+  DWARF_VENDOR_MIPS = 6,
+  DWARF_VENDOR_WASM = 7
 };
 
 /// Constants that define the DWARF format as 32 or 64 bit.
Index: llvm/include/llvm/BinaryFormat/Dwarf.def
===================================================================
--- llvm/include/llvm/BinaryFormat/Dwarf.def
+++ llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -627,6 +627,8 @@
 // Vendor extensions:
 // Extensions for GNU-style thread-local storage.
 HANDLE_DW_OP(0xe0, GNU_push_tls_address, 0, GNU)
+// Extensions for WebAssembly.
+HANDLE_DW_OP(0xed, WASM_location, 0, WASM)
 // Extensions for Fission proposal.
 HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU)
 HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU)
Index: llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -895,6 +895,10 @@
     OS << MI->getOperand(0).getImm();
   } else if (MI->getOperand(0).isCImm()) {
     MI->getOperand(0).getCImm()->getValue().print(OS, false /*isSigned*/);
+  } else if (MI->getOperand(0).isTargetIndex()) {
+    auto Op = MI->getOperand(0);
+    OS << "!target-index(" << Op.getIndex() << "," << Op.getOffset() << ")";
+    return true;
   } else {
     unsigned Reg;
     if (MI->getOperand(0).isReg()) {
Index: llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
+++ llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
@@ -21,6 +21,19 @@
 namespace llvm {
 class AsmPrinter;
 
+struct TargetIndexLocation {
+  int Index;
+  int Offset;
+
+  TargetIndexLocation() = default;
+  TargetIndexLocation(unsigned Idx, int64_t Offset)
+      : Index(Idx), Offset(Offset) {}
+
+  bool operator==(const TargetIndexLocation &Other) const {
+    return Index == Other.Index && Offset == Other.Offset;
+  }
+};
+
 /// This struct describes location entries emitted in the .debug_loc
 /// section.
 class DebugLocEntry {
@@ -47,12 +60,20 @@
         : Expression(Expr), EntryKind(E_Location), Loc(Loc) {
       assert(cast<DIExpression>(Expr)->isValid());
     }
+    Value(const DIExpression *Expr, TargetIndexLocation Loc)
+        : Expression(Expr), EntryKind(E_TargetIndexLocation), TIL(Loc) {}
 
     /// Any complex address location expression for this Value.
     const DIExpression *Expression;
 
     /// Type of entry that this represents.
-    enum EntryType { E_Location, E_Integer, E_ConstantFP, E_ConstantInt };
+    enum EntryType {
+      E_Location,
+      E_Integer,
+      E_ConstantFP,
+      E_ConstantInt,
+      E_TargetIndexLocation
+    };
     enum EntryType EntryKind;
 
     /// Either a constant,
@@ -62,10 +83,17 @@
       const ConstantInt *CIP;
     } Constant;
 
-    // Or a location in the machine frame.
-    MachineLocation Loc;
+    union {
+      // Or a location in the machine frame.
+      MachineLocation Loc;
+      // Or a location from target specific location.
+      TargetIndexLocation TIL;
+    };
 
     bool isLocation() const { return EntryKind == E_Location; }
+    bool isTargetIndexLocation() const {
+      return EntryKind == E_TargetIndexLocation;
+    }
     bool isInt() const { return EntryKind == E_Integer; }
     bool isConstantFP() const { return EntryKind == E_ConstantFP; }
     bool isConstantInt() const { return EntryKind == E_ConstantInt; }
@@ -73,6 +101,7 @@
     const ConstantFP *getConstantFP() const { return Constant.CFP; }
     const ConstantInt *getConstantInt() const { return Constant.CIP; }
     MachineLocation getLoc() const { return Loc; }
+    TargetIndexLocation getTargetIndexLocation() const { return TIL; }
     bool isFragment() const { return getExpression()->isFragment(); }
     const DIExpression *getExpression() const { return Expression; }
     friend bool operator==(const Value &, const Value &);
@@ -165,6 +194,8 @@
   switch (A.EntryKind) {
   case DebugLocEntry::Value::E_Location:
     return A.Loc == B.Loc;
+  case DebugLocEntry::Value::E_TargetIndexLocation:
+    return A.TIL == B.TIL;
   case DebugLocEntry::Value::E_Integer:
     return A.Constant.Int == B.Constant.Int;
   case DebugLocEntry::Value::E_ConstantFP:
Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
+++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.h
@@ -248,6 +248,10 @@
   /// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to
   /// the fragment described by \c Expr.
   void addFragmentOffset(const DIExpression *Expr);
+
+  /// Emit location information expressed via target's index + offset
+  /// It is an extension for WebAssembly locals, globals and operand stack.
+  void addTargetIndexLocation(unsigned Index, int64_t Offset);
 };
 
 /// DwarfExpression implementation for .debug_loc entries.
Index: llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
===================================================================
--- llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
+++ llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
@@ -437,3 +437,11 @@
     addOpPiece(FragmentOffset - OffsetInBits);
   OffsetInBits = FragmentOffset;
 }
+
+void DwarfExpression::addTargetIndexLocation(unsigned Index, int64_t Offset) {
+  assert(LocationKind == Implicit || LocationKind == Unknown);
+  LocationKind = Implicit;
+  emitOp(dwarf::DW_OP_WASM_location);
+  emitUnsigned(Index);
+  emitSigned(Offset);
+}
Index: llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
===================================================================
--- llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -93,6 +93,8 @@
   Descriptions[DW_OP_implicit_value] =
       Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
   Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
+  Descriptions[DW_OP_WASM_location] =
+      Desc(Op::Dwarf4, Op::SizeLEB, Op::SignedSizeLEB);
   Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
   Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
Index: llvm/lib/Target/WebAssembly/WebAssembly.h
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssembly.h
+++ llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -82,6 +82,10 @@
 void initializeWebAssemblyPeepholePass(PassRegistry &);
 void initializeWebAssemblyCallIndirectFixupPass(PassRegistry &);
 
+namespace WebAssembly {
+enum TargetIndex { TI_LOCAL_START, TI_GLOBAL_START, TI_OPERAND_STACK_START };
+} // end namespace WebAssembly
+
 } // end namespace llvm
 
 #endif
Index: llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
+++ llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
@@ -164,6 +164,45 @@
   llvm_unreachable("unrecognized register class");
 }
 
+static void fixupFollowingDebugValues(DenseMap<unsigned, unsigned> &Reg2Local,
+                                      MachineRegisterInfo &MRI,
+                                      MachineBasicBlock::iterator B,
+                                      MachineBasicBlock::iterator E) {
+  // Scan DBG_VALUE and modify virtual registers with known locals.
+  // Stop at first non-DBG_VALUE instruction.
+  for (auto I = B; I != E && I->isDebugInstr();) {
+    MachineInstr &MI = *I++;
+    for (MachineOperand &MO : reverse(MI.uses())) {
+      if (!MO.isReg())
+        continue;
+
+      unsigned OldReg = MO.getReg();
+      auto I = Reg2Local.find(OldReg);
+      if (I == Reg2Local.end())
+        continue;
+
+      unsigned LocalId = I->second;
+      MO.ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL_START, LocalId);
+    }
+  }
+}
+
+static void fixupFollowingDebugValues(unsigned Reg, unsigned LocalId,
+                                      MachineRegisterInfo &MRI,
+                                      MachineBasicBlock::iterator B,
+                                      MachineBasicBlock::iterator E) {
+  // Scan DBG_VALUE and modify the specified virtual registers with the local.
+  // Stop at first non-DBG_VALUE instruction.
+  for (auto I = B; I != E && I->isDebugInstr();) {
+    MachineInstr &MI = *I++;
+    for (MachineOperand &MO : reverse(MI.uses())) {
+      if (!MO.isReg() || MO.getReg() != Reg)
+        continue;
+      MO.ChangeToTargetIndex(llvm::WebAssembly::TI_LOCAL_START, LocalId);
+    }
+  }
+}
+
 /// Given a MachineOperand of a stackified vreg, return the instruction at the
 /// start of the expression tree.
 static MachineInstr *findStartOfTree(MachineOperand &MO,
@@ -262,6 +301,11 @@
             .addImm(LocalId)
             .addReg(MI.getOperand(2).getReg());
 
+        auto Next = std::next(MachineBasicBlock::iterator(&MI));
+        fixupFollowingDebugValues(Reg2Local, MRI, Next, MBB.end());
+        fixupFollowingDebugValues(MI.getOperand(0).getReg(), LocalId, MRI, Next,
+                                  MBB.end());
+
         MI.eraseFromParent();
         Changed = true;
         continue;
@@ -294,6 +338,8 @@
             BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
                 .addImm(LocalId)
                 .addReg(NewReg);
+            fixupFollowingDebugValues(NewReg, LocalId, MRI, InsertPt,
+                                      MBB.end());
           }
           MI.getOperand(0).setReg(NewReg);
           // This register operand of the original instruction is now being used
@@ -302,6 +348,9 @@
           MI.getOperand(0).setIsDead(false);
           MFI.stackifyVReg(NewReg);
           Changed = true;
+
+          fixupFollowingDebugValues(Reg2Local, MRI, InsertPt, MBB.end());
+
         }
       }
 
@@ -354,6 +403,8 @@
         MO.setReg(NewReg);
         MFI.stackifyVReg(NewReg);
         Changed = true;
+
+        fixupFollowingDebugValues(OldReg, LocalId, MRI, InsertPt, MBB.end());
       }
 
       // Coalesce and eliminate COPY instructions.
Index: llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h
+++ llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.h
@@ -16,7 +16,9 @@
 #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYINSTRINFO_H
 #define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYINSTRINFO_H
 
+#include "WebAssembly.h"
 #include "WebAssemblyRegisterInfo.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/CodeGen/TargetInstrInfo.h"
 
 #define GET_INSTRINFO_HEADER
@@ -56,6 +58,9 @@
                         int *BytesAdded = nullptr) const override;
   bool
   reverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override;
+
+  ArrayRef<std::pair<int, const char *>>
+  getSerializableTargetIndices() const override;
 };
 
 } // end namespace llvm
Index: llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
===================================================================
--- llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
+++ llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp
@@ -198,3 +198,12 @@
   Cond.front() = MachineOperand::CreateImm(!Cond.front().getImm());
   return false;
 }
+
+ArrayRef<std::pair<int, const char *>>
+WebAssemblyInstrInfo::getSerializableTargetIndices() const {
+  static const std::pair<int, const char *> TargetIndices[] = {
+      {WebAssembly::TI_LOCAL_START, "wasm-local-start"},
+      {WebAssembly::TI_GLOBAL_START, "wasm-global-start"},
+      {WebAssembly::TI_OPERAND_STACK_START, "wasm-operator-stack-start"}};
+  return makeArrayRef(TargetIndices);
+}