diff --git a/llvm/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.rst b/llvm/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.rst
--- a/llvm/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.rst
+++ b/llvm/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.rst
@@ -3575,15 +3575,15 @@
 .. table:: Attribute encodings
    :name: amdgpu-dwarf-attribute-encodings-table
 
-   ================================== ===== ====================================
-   Attribute Name                     Value Classes
-   ================================== ===== ====================================
-   DW_AT_LLVM_active_lane             *TBD* exprloc, loclist
-   DW_AT_LLVM_augmentation            *TBD* string
-   DW_AT_LLVM_lanes                   *TBD* constant
-   DW_AT_LLVM_lane_pc                 *TBD* exprloc, loclist
-   DW_AT_LLVM_vector_size             *TBD* constant
-   ================================== ===== ====================================
+   ================================== ====== ===================================
+   Attribute Name                     Value  Classes
+   ================================== ====== ===================================
+   DW_AT_LLVM_active_lane             0x3e08 exprloc, loclist
+   DW_AT_LLVM_augmentation            0x3e09 string
+   DW_AT_LLVM_lanes                   0x3e0a constant
+   DW_AT_LLVM_lane_pc                 0x3e0b exprloc, loclist
+   DW_AT_LLVM_vector_size             0x3e0c constant
+   ================================== ====== ===================================
 
 DWARF Expressions
 ~~~~~~~~~~~~~~~~~
@@ -3814,4 +3814,4 @@
 
     .. _amdgpu-dwarf-SEMVER:
 
-15. [SEMVER] `Semantic Versioning `__
\ No newline at end of file
+15. [SEMVER] `Semantic Versioning `__
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -418,6 +418,13 @@
 HANDLE_DW_AT(0x3e03, LLVM_tag_offset, 0, LLVM)
 // The missing numbers here are reserved for ptrauth support.
 HANDLE_DW_AT(0x3e07, LLVM_apinotes, 0, APPLE)
+// Heterogeneous Debugging Extension defined at
+// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html.
+HANDLE_DW_AT(0x3e08, LLVM_active_lane, 0, LLVM)
+HANDLE_DW_AT(0x3e09, LLVM_augmentation, 0, LLVM)
+HANDLE_DW_AT(0x3e0a, LLVM_lanes, 0, LLVM)
+HANDLE_DW_AT(0x3e0b, LLVM_lane_pc, 0, LLVM)
+HANDLE_DW_AT(0x3e0c, LLVM_vector_size, 0, LLVM)
 
 // Apple extensions.
 
@@ -670,6 +677,23 @@
 // Extensions for Fission proposal.
 HANDLE_DW_OP(0xfb, GNU_addr_index, 0, GNU)
 HANDLE_DW_OP(0xfc, GNU_const_index, 0, GNU)
+// Heterogeneous Debugging Extension defined at
+// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html.
+// These collide with some HP and PGI vendor extensions, but this ambiguity is
+// resolved by ensuring CIE augmentation strings and compilation unit
+// DW_AT_LLVM_augmentation strings include "[llvm:v0.0]".
+HANDLE_DW_OP(0xe1, LLVM_form_aspace_address, 0, LLVM)
+HANDLE_DW_OP(0xe2, LLVM_push_lane, 0, LLVM)
+HANDLE_DW_OP(0xe3, LLVM_offset, 0, LLVM)
+HANDLE_DW_OP(0xe4, LLVM_offset_uconst, 0, LLVM)
+HANDLE_DW_OP(0xe5, LLVM_bit_offset, 0, LLVM)
+HANDLE_DW_OP(0xe6, LLVM_call_frame_entry_reg, 0, LLVM)
+HANDLE_DW_OP(0xe7, LLVM_undefined, 0, LLVM)
+HANDLE_DW_OP(0xe8, LLVM_aspace_bregx, 0, LLVM)
+HANDLE_DW_OP(0xe9, LLVM_aspace_implicit_pointer, 0, LLVM)
+HANDLE_DW_OP(0xea, LLVM_piece_end, 0, LLVM)
+HANDLE_DW_OP(0xeb, LLVM_extend, 0, LLVM)
+HANDLE_DW_OP(0xec, LLVM_select_bit_piece, 0, LLVM)
 
 // DWARF languages.
 HANDLE_DW_LANG(0x0001, C89, 0, 2, DWARF)
diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h
--- a/llvm/include/llvm/MC/MCAsmInfo.h
+++ b/llvm/include/llvm/MC/MCAsmInfo.h
@@ -384,6 +384,11 @@
   /// location is allowed.
   bool SupportsExtendedDwarfLocDirective = true;
 
+  /// True if the target supports the extensions defined at
+  /// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html.
+  /// Defaults to false.
+  bool SupportsHeterogeneousDebuggingExtensions = false;
+
   //===--- Prologue State ----------------------------------------------===//
 
   std::vector InitialFrameState;
@@ -652,6 +657,9 @@
   bool supportsExtendedDwarfLocDirective() const {
     return SupportsExtendedDwarfLocDirective;
   }
+  bool supportsHeterogeneousDebuggingExtensions() const {
+    return SupportsHeterogeneousDebuggingExtensions;
+  }
 
   void addInitialFrameState(const MCCFIInstruction &Inst);
 
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -377,6 +377,9 @@
   AccelTableKind TheAccelTableKind;
   bool HasAppleExtensionAttributes;
   bool HasSplitDwarf;
+  // Enables extensions defined at
+  // https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html
+  bool HasHeterogeneousExtensionAttributes;
 
   /// Whether to generate the DWARF v5 string offsets table.
   /// It consists of a series of contributions, each preceded by a header.
@@ -700,6 +703,13 @@
     return HasAppleExtensionAttributes;
   }
 
+  /// Returns whether extensions defined at
+  /// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html
+  /// are enabled.
+  bool useHeterogeneousExtensionAttributes() const {
+    return HasHeterogeneousExtensionAttributes;
+  }
+
   /// Returns whether or not to change the current debug info for the
   /// split dwarf proposal support.
   bool useSplitDwarf() const { return HasSplitDwarf; }
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -375,6 +375,8 @@
   UseLocSection = !TT.isNVPTX();
 
   HasAppleExtensionAttributes = tuneForLLDB();
+  HasHeterogeneousExtensionAttributes =
+      Asm->MAI->supportsHeterogeneousDebuggingExtensions();
 
   // Handle split DWARF.
   HasSplitDwarf = !Asm->TM.Options.MCOptions.SplitDwarfFile.empty();
@@ -972,6 +974,10 @@
                     dwarf::DW_FORM_data1, RVer);
   }
 
+  if (useHeterogeneousExtensionAttributes()) {
+    NewCU.addString(Die, dwarf::DW_AT_LLVM_augmentation, "[llvm:v0.0]");
+  }
+
   if (DIUnit->getDWOId()) {
     // This CU is either a clang module DWO or a skeleton CU.
     NewCU.addUInt(Die, dwarf::DW_AT_GNU_dwo_id, dwarf::DW_FORM_data8,
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -100,6 +100,21 @@
   Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
   Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_form_aspace_address] = Desc(Op::Dwarf4);
+  Descriptions[DW_OP_LLVM_push_lane] = Desc(Op::Dwarf4);
+  Descriptions[DW_OP_LLVM_offset] = Desc(Op::Dwarf4);
+  Descriptions[DW_OP_LLVM_offset_uconst] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_bit_offset] = Desc(Op::Dwarf4);
+  Descriptions[DW_OP_LLVM_call_frame_entry_reg] = Desc(Op::Dwarf4, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_undefined] = Desc(Op::Dwarf4);
+  Descriptions[DW_OP_LLVM_aspace_bregx] =
+      Desc(Op::Dwarf4, Op::SizeLEB, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_aspace_implicit_pointer] =
+      Desc(Op::Dwarf4, Op::SizeRefAddr, Op::SignedSizeLEB);
+  Descriptions[DW_OP_LLVM_piece_end] = Desc(Op::Dwarf4);
+  Descriptions[DW_OP_LLVM_extend] = Desc(Op::Dwarf4, Op::SizeLEB, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_select_bit_piece] =
+      Desc(Op::Dwarf4, Op::SizeLEB, Op::SizeLEB);
 
   Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
   Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
@@ -226,8 +241,10 @@
   unsigned OpNum = 0;
 
   if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
-      Opcode == DW_OP_regval_type)
+      Opcode == DW_OP_regval_type || Opcode == DW_OP_LLVM_aspace_bregx)
     DwarfRegNum = Operands[OpNum++];
+  else if (Opcode == DW_OP_LLVM_call_frame_entry_reg)
+    DwarfRegNum = Operands[OpNum];
   else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
     DwarfRegNum = Opcode - DW_OP_breg0;
   else
@@ -236,7 +253,7 @@
   if (Optional LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH)) {
     if (const char *RegName = MRI->getName(*LLVMRegNum)) {
       if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
-          Opcode == DW_OP_bregx)
+          Opcode == DW_OP_bregx || Opcode == DW_OP_LLVM_aspace_bregx)
         OS << format(" %s%+" PRId64, RegName, Operands[OpNum]);
       else
         OS << ' ' << RegName;
@@ -267,7 +284,9 @@
   if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
       (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) ||
       Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
-      Opcode == DW_OP_regval_type)
+      Opcode == DW_OP_regval_type ||
+      Opcode == DW_OP_LLVM_call_frame_entry_reg ||
+      Opcode == DW_OP_LLVM_aspace_bregx)
     if (prettyPrintRegisterOp(U, OS, Opcode, Operands, RegInfo, isEH))
       return true;
 
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1603,6 +1603,7 @@
   MCContext &context = Streamer.getContext();
   const MCRegisterInfo *MRI = context.getRegisterInfo();
   const MCObjectFileInfo *MOFI = context.getObjectFileInfo();
+  const MCAsmInfo *MAI = context.getAsmInfo();
 
   MCSymbol *sectionStart = context.createTempSymbol();
   Streamer.emitLabel(sectionStart);
@@ -1622,8 +1623,8 @@
   uint8_t CIEVersion = getCIEVersion(IsEH, context.getDwarfVersion());
   Streamer.emitInt8(CIEVersion);
 
+  SmallString<8> Augmentation;
   if (IsEH) {
-    SmallString<8> Augmentation;
     Augmentation += "z";
     if (Frame.Personality)
       Augmentation += "P";
@@ -1634,8 +1635,10 @@
       Augmentation += "S";
     if (Frame.IsBKeyFrame)
       Augmentation += "B";
-    Streamer.emitBytes(Augmentation);
   }
+  if (MAI->supportsHeterogeneousDebuggingExtensions())
+    Augmentation += "[llvm:v0.0]";
+  Streamer.emitBytes(Augmentation);
   Streamer.emitInt8(0);
 
   if (CIEVersion >= 4) {
@@ -1699,7 +1702,6 @@
 
   // Initial Instructions
 
-  const MCAsmInfo *MAI = context.getAsmInfo();
   if (!Frame.IsSimple) {
     const std::vector &Instructions =
         MAI->getInitialFrameState();
diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp
--- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp
+++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp
@@ -44,6 +44,7 @@
   //===--- Dwarf Emission Directives -----------------------------------===//
   SupportsDebugInformation = true;
   DwarfRegNumForCFI = true;
+  SupportsHeterogeneousDebuggingExtensions = true;
 
   UseIntegratedAssembler = false;
 }
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous_proposal.s b/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous_proposal.s
new file mode 100644
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous_proposal.s
@@ -0,0 +1,40 @@
+# RUN: llvm-mc %s -filetype=obj -triple=i686-pc-linux -o %t
+# RUN: llvm-dwarfdump -v %t | FileCheck %s
+
+# Check that we can decode new ops described at
+# llvm/docs/AMDGPUUsage.rst#expression-operation-encodings
+
+# FIXME: Is there a better approach than using `DW_CFA_expression reg0 `?
+
+# CHECK:      .eh_frame contents:
+# CHECK:      FDE
+
+foo:
+ .cfi_startproc
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_form_aspace_address
+ .cfi_escape 0x10, 0x00, 0x01, 0xe1
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_push_lane
+ .cfi_escape 0x10, 0x00, 0x01, 0xe2
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_offset
+ .cfi_escape 0x10, 0x00, 0x01, 0xe3
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_offset_uconst 0x0
+ .cfi_escape 0x10, 0x00, 0x02, 0xe4, 0x00
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_bit_offset
+ .cfi_escape 0x10, 0x00, 0x01, 0xe5
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_call_frame_entry_reg EAX
+ .cfi_escape 0x10, 0x00, 0x02, 0xe6, 0x00
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_undefined
+ .cfi_escape 0x10, 0x00, 0x01, 0xe7
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_aspace_bregx EAX+2
+ .cfi_escape 0x10, 0x00, 0x03, 0xe8, 0x0, 0x2
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_aspace_implicit_pointer 0x1 +2
+ .cfi_escape 0x10, 0x00, 0x06, 0xe9, 0x1, 0x0, 0x0, 0x0, 0x2
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_piece_end
+ .cfi_escape 0x10, 0x00, 0x01, 0xea
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_extend 0x0 0x0
+ .cfi_escape 0x10, 0x00, 0x03, 0xeb, 0x0, 0x0
+ # CHECK-NEXT: DW_CFA_expression: reg0 DW_OP_LLVM_select_bit_piece 0x0 0x0
+ .cfi_escape 0x10, 0x00, 0x03, 0xec, 0x0, 0x0
+ .cfi_endproc
+
+# CHECK-NEXT:     DW_CFA_nop: