https://github.com/slinder1 created 
https://github.com/llvm/llvm-project/pull/153883

These are defined in the user range until standard versions of them get adopted 
into dwarf, which is expected in DWARF6.

Some of these amount to reservations currently as no code to use them is 
included. It would be very helpful to get them committed to avoid conflicts 
necessitating encoding changes while we are in the process of upstreaming.

>From 5182ae0c6a37825778c05b5402d86d357d2b2e01 Mon Sep 17 00:00:00 2001
From: Scott Linder <scott.lin...@amd.com>
Date: Fri, 15 Aug 2025 21:35:36 +0000
Subject: [PATCH] [Dwarf] Support heterogeneous DW_{OP,AT}s needed for AMDGPU
 CFI

These are defined in the user range until standard versions of them get
adopted into dwarf, which is expected in DWARF6.

Some of these amount to reservations currently as no code to use them is
included. It would be very helpful to get them committed to avoid
conflicts necessitating encoding changes while we are in the process of
upstreaming.

Co-authored-by: Juan Martinez Fernandez <juama...@amd.com>
Co-authored-by: Emma Pilkington <emma.pilking...@amd.com>
---
 clang/lib/Basic/Targets/AMDGPU.h              | 13 ++--
 ...amdgpu-debug-info-pointer-address-space.cl | 65 ++++++++++---------
 .../amdgpu-debug-info-variable-expression.cl  | 36 +++++-----
 llvm/include/llvm/BinaryFormat/Dwarf.def      | 41 +++++++++++-
 llvm/include/llvm/BinaryFormat/Dwarf.h        |  8 +++
 llvm/include/llvm/Support/AMDGPUAddrSpace.h   | 40 ++++++++++++
 llvm/lib/BinaryFormat/Dwarf.cpp               | 21 ++++++
 .../DWARF/DWARFExpressionPrinter.cpp          | 30 ++++++---
 .../DWARF/LowLevel/DWARFExpression.cpp        | 19 ++++++
 .../X86/heterogeneous-user-ops.s              | 31 +++++++++
 10 files changed, 237 insertions(+), 67 deletions(-)
 create mode 100644 llvm/test/tools/llvm-dwarfdump/X86/heterogeneous-user-ops.s

diff --git a/clang/lib/Basic/Targets/AMDGPU.h b/clang/lib/Basic/Targets/AMDGPU.h
index 8b7fab3d439e0..552698a680d3e 100644
--- a/clang/lib/Basic/Targets/AMDGPU.h
+++ b/clang/lib/Basic/Targets/AMDGPU.h
@@ -400,15 +400,12 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : 
public TargetInfo {
   /// in the DWARF.
   std::optional<unsigned>
   getDWARFAddressSpace(unsigned AddressSpace) const override {
-    const unsigned DWARF_Private = 1;
-    const unsigned DWARF_Local = 2;
-    if (AddressSpace == llvm::AMDGPUAS::PRIVATE_ADDRESS) {
-      return DWARF_Private;
-    } else if (AddressSpace == llvm::AMDGPUAS::LOCAL_ADDRESS) {
-      return DWARF_Local;
-    } else {
+    int DWARFAS = llvm::AMDGPU::mapToDWARFAddrSpace(AddressSpace);
+    // If there is no corresponding address space identifier, or it would be
+    // the default, then don't emit the attribute.
+    if (DWARFAS == -1 || DWARFAS == llvm::AMDGPU::DWARFAS::DEFAULT)
       return std::nullopt;
-    }
+    return DWARFAS;
   }
 
   CallingConvCheckResult checkCallingConvention(CallingConv CC) const override 
{
diff --git 
a/clang/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl 
b/clang/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
index ab625f3154b20..e6a783fff4bc5 100644
--- a/clang/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
+++ b/clang/test/CodeGenOpenCL/amdgpu-debug-info-pointer-address-space.cl
@@ -2,122 +2,123 @@
 // RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -nogpulib -target 
amdgcn-amd-amdhsa -mcpu=fiji -o - %s | FileCheck %s
 // RUN: %clang -cl-std=CL2.0 -emit-llvm -g -O0 -S -nogpulib -target 
amdgcn-amd-amdhsa-opencl -mcpu=fiji -o - %s | FileCheck %s
 
-// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_NONE:[0-9]+]] = !DIDerivedType(tag: 
DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}})
-// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_LOCAL:[0-9]+]] = !DIDerivedType(tag: 
DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}}, 
dwarfAddressSpace: 2)
-// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_PRIVATE:[0-9]+]] = !DIDerivedType(tag: 
DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}}, 
dwarfAddressSpace: 1)
+// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_GLOBAL:[0-9]+]] = !DIDerivedType(tag: 
DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}})
+// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_LOCAL:[0-9]+]] = !DIDerivedType(tag: 
DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}}, 
dwarfAddressSpace: 3)
+// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_PRIVATE:[0-9]+]] = !DIDerivedType(tag: 
DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}}, 
dwarfAddressSpace: 5)
+// CHECK-DAG: ![[DWARF_ADDRESS_SPACE_GENERIC:[0-9]+]] = !DIDerivedType(tag: 
DW_TAG_pointer_type, baseType: !{{[0-9]+}}, size: {{[0-9]+}}, 
dwarfAddressSpace: 1)
 
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar0", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], 
isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar0", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]], 
isLocal: false, isDefinition: true)
 global int *FileVar0;
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar1", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], 
isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar1", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]], 
isLocal: false, isDefinition: true)
 constant int *FileVar1;
 // CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar2", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], 
isLocal: false, isDefinition: true)
 local int *FileVar2;
 // CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar3", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], 
isLocal: false, isDefinition: true)
 private int *FileVar3;
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar4", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], 
isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar4", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GENERIC]], 
isLocal: false, isDefinition: true)
 int *FileVar4;
 
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar5", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], 
isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar5", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]], 
isLocal: false, isDefinition: true)
 global int *global FileVar5;
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar6", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], 
isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar6", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]], 
isLocal: false, isDefinition: true)
 constant int *global FileVar6;
 // CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar7", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]], 
isLocal: false, isDefinition: true)
 local int *global FileVar7;
 // CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar8", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]], 
isLocal: false, isDefinition: true)
 private int *global FileVar8;
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar9", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]], 
isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar9", scope: !{{[0-9]+}}, 
file: !{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GENERIC]], 
isLocal: false, isDefinition: true)
 int *global FileVar9;
 
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar10", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar10", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], isLocal: false, isDefinition: true)
 global int *constant FileVar10 = 0;
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar11", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar11", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], isLocal: false, isDefinition: true)
 constant int *constant FileVar11 = 0;
 // CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar12", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: false, isDefinition: true)
 local int *constant FileVar12 = 0;
 // CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar13", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: false, isDefinition: true)
 private int *constant FileVar13 = 0;
-// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar14", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: false, isDefinition: true)
+// CHECK-DAG: distinct !DIGlobalVariable(name: "FileVar14", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GENERIC]], isLocal: false, isDefinition: true)
 int *constant FileVar14 = 0;
 
 kernel void kernel1(
-    // CHECK-DAG: !DILocalVariable(name: "KernelArg0", arg: {{[0-9]+}}, scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]])
+    // CHECK-DAG: !DILocalVariable(name: "KernelArg0", arg: {{[0-9]+}}, scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]])
     global int *KernelArg0,
-    // CHECK-DAG: !DILocalVariable(name: "KernelArg1", arg: {{[0-9]+}}, scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]])
+    // CHECK-DAG: !DILocalVariable(name: "KernelArg1", arg: {{[0-9]+}}, scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]])
     constant int *KernelArg1,
     // CHECK-DAG: !DILocalVariable(name: "KernelArg2", arg: {{[0-9]+}}, scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_LOCAL]])
     local int *KernelArg2) {
   private int *Tmp0;
   int *Tmp1;
 
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar0", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+  // CHECK-DAG: !DILocalVariable(name: "FuncVar0", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]])
   global int *FuncVar0 = KernelArg0;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar1", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+  // CHECK-DAG: !DILocalVariable(name: "FuncVar1", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]])
   constant int *FuncVar1 = KernelArg1;
   // CHECK-DAG: !DILocalVariable(name: "FuncVar2", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]])
   local int *FuncVar2 = KernelArg2;
   // CHECK-DAG: !DILocalVariable(name: "FuncVar3", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]])
   private int *FuncVar3 = Tmp0;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar4", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+  // CHECK-DAG: !DILocalVariable(name: "FuncVar4", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GENERIC]])
   int *FuncVar4 = Tmp1;
 
-  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar5", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar5", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], isLocal: true, isDefinition: true)
   global int *constant FuncVar5 = 0;
-  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar6", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar6", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], isLocal: true, isDefinition: true)
   constant int *constant FuncVar6 = 0;
   // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar7", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: true, isDefinition: true)
   local int *constant FuncVar7 = 0;
   // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar8", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: true, isDefinition: true)
   private int *constant FuncVar8 = 0;
-  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar9", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar9", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GENERIC]], isLocal: true, isDefinition: true)
   int *constant FuncVar9 = 0;
 
-  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar10", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar10", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], isLocal: true, isDefinition: true)
   global int *local FuncVar10; FuncVar10 = KernelArg0;
-  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar11", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar11", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], isLocal: true, isDefinition: true)
   constant int *local FuncVar11; FuncVar11 = KernelArg1;
   // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar12", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_LOCAL]], isLocal: true, isDefinition: true)
   local int *local FuncVar12; FuncVar12 = KernelArg2;
   // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar13", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_PRIVATE]], isLocal: true, isDefinition: true)
   private int *local FuncVar13; FuncVar13 = Tmp0;
-  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar14", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_NONE]], isLocal: true, isDefinition: true)
+  // CHECK-DAG: distinct !DIGlobalVariable(name: "FuncVar14", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
![[DWARF_ADDRESS_SPACE_GENERIC]], isLocal: true, isDefinition: true)
   int *local FuncVar14; FuncVar14 = Tmp1;
 
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar15", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+  // CHECK-DAG: !DILocalVariable(name: "FuncVar15", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]])
   global int *private FuncVar15 = KernelArg0;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar16", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+  // CHECK-DAG: !DILocalVariable(name: "FuncVar16", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GLOBAL]])
   constant int *private FuncVar16 = KernelArg1;
   // CHECK-DAG: !DILocalVariable(name: "FuncVar17", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_LOCAL]])
   local int *private FuncVar17 = KernelArg2;
   // CHECK-DAG: !DILocalVariable(name: "FuncVar18", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_PRIVATE]])
   private int *private FuncVar18 = Tmp0;
-  // CHECK-DAG: !DILocalVariable(name: "FuncVar19", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_NONE]])
+  // CHECK-DAG: !DILocalVariable(name: "FuncVar19", scope: !{{[0-9]+}}, file: 
!{{[0-9]+}}, line: {{[0-9]+}}, type: ![[DWARF_ADDRESS_SPACE_GENERIC]])
   int *private FuncVar19 = Tmp1;
 }
 
 struct FileStruct0 {
-  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem0", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem0", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], size: {{[0-9]+}})
   global int *StructMem0;
-  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem1", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}}, offset: {{[0-9]+}})
+  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem1", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], size: {{[0-9]+}}, offset: {{[0-9]+}})
   constant int *StructMem1;
   // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem2", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_LOCAL]], size: {{[0-9]+}}, offset: {{[0-9]+}})
   local int *StructMem2;
   // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem3", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_PRIVATE]], size: {{[0-9]+}}, offset: {{[0-9]+}})
   private int *StructMem3;
-  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem4", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}}, offset: {{[0-9]+}})
+  // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "StructMem4", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_GENERIC]], size: {{[0-9]+}}, offset: {{[0-9]+}})
   int *StructMem4;
 };
 
 struct FileStruct1 {
   union {
-    // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem0", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+    // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem0", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], size: {{[0-9]+}})
     global int *UnionMem0;
-    // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem1", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+    // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem1", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_GLOBAL]], size: {{[0-9]+}})
     constant int *UnionMem1;
     // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem2", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_LOCAL]], size: {{[0-9]+}})
     local int *UnionMem2;
     // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem3", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_PRIVATE]], size: {{[0-9]+}})
     private int *UnionMem3;
-    // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem4", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_NONE]], size: {{[0-9]+}})
+    // CHECK-DAG: !DIDerivedType(tag: DW_TAG_member, name: "UnionMem4", scope: 
!{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, baseType: 
![[DWARF_ADDRESS_SPACE_GENERIC]], size: {{[0-9]+}})
     int *UnionMem4;
   };
   long StructMem0;
diff --git a/clang/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl 
b/clang/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
index 479e893000942..4d5f1019378af 100644
--- a/clang/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
+++ b/clang/test/CodeGenOpenCL/amdgpu-debug-info-variable-expression.cl
@@ -52,31 +52,31 @@ int *constant FileVar14 = 0;
 
 kernel void kernel1(
     // CHECK-DAG: ![[KERNELARG0:[0-9]+]] = !DILocalVariable(name: 
"KernelArg0", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 
{{[0-9]+}}, type: !{{[0-9]+}})
-    // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[KERNELARG0]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+    // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[KERNELARG0]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
     global int *KernelArg0,
     // CHECK-DAG: ![[KERNELARG1:[0-9]+]] = !DILocalVariable(name: 
"KernelArg1", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 
{{[0-9]+}}, type: !{{[0-9]+}})
-    // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[KERNELARG1]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+    // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[KERNELARG1]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
     constant int *KernelArg1,
     // CHECK-DAG: ![[KERNELARG2:[0-9]+]] = !DILocalVariable(name: 
"KernelArg2", arg: {{[0-9]+}}, scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: 
{{[0-9]+}}, type: !{{[0-9]+}})
-    // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[KERNELARG2]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+    // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[KERNELARG2]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
     local int *KernelArg2) {
   private int *Tmp0;
   int *Tmp1;
 
   // CHECK-DAG: ![[FUNCVAR0:[0-9]+]] = !DILocalVariable(name: "FuncVar0", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR0]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR0]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   global int *FuncVar0 = KernelArg0;
   // CHECK-DAG: ![[FUNCVAR1:[0-9]+]] = !DILocalVariable(name: "FuncVar1", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR1]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR1]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   constant int *FuncVar1 = KernelArg1;
   // CHECK-DAG: ![[FUNCVAR2:[0-9]+]] = !DILocalVariable(name: "FuncVar2", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR2]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR2]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   local int *FuncVar2 = KernelArg2;
   // CHECK-DAG: ![[FUNCVAR3:[0-9]+]] = !DILocalVariable(name: "FuncVar3", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR3]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR3]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   private int *FuncVar3 = Tmp0;
   // CHECK-DAG: ![[FUNCVAR4:[0-9]+]] = !DILocalVariable(name: "FuncVar4", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR4]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR4]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   int *FuncVar4 = Tmp1;
 
   // CHECK-DAG: ![[FUNCVAR5:[0-9]+]] = distinct !DIGlobalVariable(name: 
"FuncVar5", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
!{{[0-9]+}}, isLocal: true, isDefinition: true)
@@ -96,34 +96,34 @@ kernel void kernel1(
   int *constant FuncVar9 = 0;
 
   // CHECK-DAG: ![[FUNCVAR10:[0-9]+]] = distinct !DIGlobalVariable(name: 
"FuncVar10", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
!{{[0-9]+}}, isLocal: true, isDefinition: true)
-  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR10]], expr: 
!DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR10]], expr: 
!DIExpression(DW_OP_constu, 3, DW_OP_swap, DW_OP_xderef))
   global int *local FuncVar10; FuncVar10 = KernelArg0;
   // CHECK-DAG: ![[FUNCVAR11:[0-9]+]] = distinct !DIGlobalVariable(name: 
"FuncVar11", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
!{{[0-9]+}}, isLocal: true, isDefinition: true)
-  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR11]], expr: 
!DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR11]], expr: 
!DIExpression(DW_OP_constu, 3, DW_OP_swap, DW_OP_xderef))
   constant int *local FuncVar11; FuncVar11 = KernelArg1;
   // CHECK-DAG: ![[FUNCVAR12:[0-9]+]] = distinct !DIGlobalVariable(name: 
"FuncVar12", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
!{{[0-9]+}}, isLocal: true, isDefinition: true)
-  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR12]], expr: 
!DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR12]], expr: 
!DIExpression(DW_OP_constu, 3, DW_OP_swap, DW_OP_xderef))
   local int *local FuncVar12; FuncVar12 = KernelArg2;
   // CHECK-DAG: ![[FUNCVAR13:[0-9]+]] = distinct !DIGlobalVariable(name: 
"FuncVar13", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
!{{[0-9]+}}, isLocal: true, isDefinition: true)
-  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR13]], expr: 
!DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR13]], expr: 
!DIExpression(DW_OP_constu, 3, DW_OP_swap, DW_OP_xderef))
   private int *local FuncVar13; FuncVar13 = Tmp0;
   // CHECK-DAG: ![[FUNCVAR14:[0-9]+]] = distinct !DIGlobalVariable(name: 
"FuncVar14", scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: 
!{{[0-9]+}}, isLocal: true, isDefinition: true)
-  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR14]], expr: 
!DIExpression(DW_OP_constu, 2, DW_OP_swap, DW_OP_xderef))
+  // CHECK-DAG: !DIGlobalVariableExpression(var: ![[FUNCVAR14]], expr: 
!DIExpression(DW_OP_constu, 3, DW_OP_swap, DW_OP_xderef))
   int *local FuncVar14; FuncVar14 = Tmp1;
 
   // CHECK-DAG: ![[FUNCVAR15:[0-9]+]] = !DILocalVariable(name: "FuncVar15", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR15]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR15]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   global int *private FuncVar15 = KernelArg0;
   // CHECK-DAG: ![[FUNCVAR16:[0-9]+]] = !DILocalVariable(name: "FuncVar16", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR16]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR16]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   constant int *private FuncVar16 = KernelArg1;
   // CHECK-DAG: ![[FUNCVAR17:[0-9]+]] = !DILocalVariable(name: "FuncVar17", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR17]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR17]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   local int *private FuncVar17 = KernelArg2;
   // CHECK-DAG: ![[FUNCVAR18:[0-9]+]] = !DILocalVariable(name: "FuncVar18", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR18]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR18]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   private int *private FuncVar18 = Tmp0;
   // CHECK-DAG: ![[FUNCVAR19:[0-9]+]] = !DILocalVariable(name: "FuncVar19", 
scope: !{{[0-9]+}}, file: !{{[0-9]+}}, line: {{[0-9]+}}, type: !{{[0-9]+}})
-  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR19]], 
!DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
+  // CHECK-DAG: #dbg_declare(ptr addrspace(5) {{.*}}, ![[FUNCVAR19]], 
!DIExpression(DW_OP_constu, 5, DW_OP_swap, DW_OP_xderef), !{{[0-9]+}}
   int *private FuncVar19 = Tmp1;
 }
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def 
b/llvm/include/llvm/BinaryFormat/Dwarf.def
index b561125fe37a4..2c9a3c0f6fb04 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.def
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.def
@@ -25,7 +25,8 @@
       defined HANDLE_DW_APPLE_PROPERTY || defined HANDLE_DW_UT ||              
\
       defined HANDLE_DWARF_SECTION || defined HANDLE_DW_IDX ||                 
\
       defined HANDLE_DW_END || defined HANDLE_DW_SECT ||                       
\
-      defined HANDLE_DW_APPLE_ENUM_KIND)
+      defined HANDLE_DW_APPLE_ENUM_KIND ||                                     
\
+      ( defined HANDLE_DW_ASPACE && defined HANDLE_DW_ASPACE_PRED) )
 #error "Missing macro definition of HANDLE_DW*"
 #endif
 
@@ -151,6 +152,14 @@
 #define HANDLE_DW_APPLE_ENUM_KIND(ID, NAME)
 #endif
 
+#ifndef HANDLE_DW_ASPACE
+#define HANDLE_DW_ASPACE(ID, NAME)
+#endif
+
+#ifndef HANDLE_DW_ASPACE_PRED
+#define HANDLE_DW_ASPACE_PRED(ID, NAME, PRED)
+#endif
+
 HANDLE_DW_TAG(0x0000, null, 2, DWARF, DW_KIND_NONE)
 HANDLE_DW_TAG(0x0001, array_type, 2, DWARF, DW_KIND_TYPE)
 HANDLE_DW_TAG(0x0002, class_type, 2, DWARF, DW_KIND_TYPE)
@@ -628,6 +637,21 @@ HANDLE_DW_AT(0x3e0d, LLVM_coro_suspend_idx, 0, LLVM)
 // The DWARF v6 working draft defines DW_AT_alloc_type; use this LLVM-private 
ID
 // until that is released as an official standard.
 HANDLE_DW_AT(0x3e0e, LLVM_alloc_type, 0, LLVM)
+// Heterogeneous Debugging Extension defined at
+// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html.
+HANDLE_DW_AT(0x3e0f, LLVM_memory_space, 0, LLVM)
+HANDLE_DW_AT(0x3e10, LLVM_address_space, 0, LLVM)
+HANDLE_DW_AT(0x3e11, LLVM_lanes, 0, LLVM)
+HANDLE_DW_AT(0x3e12, LLVM_lane_pc, 0, LLVM)
+HANDLE_DW_AT(0x3e13, LLVM_vector_size, 0, LLVM)
+
+// https://llvm.org/docs/AMDGPUUsage.html#address-space-identifier
+HANDLE_DW_ASPACE(0x0, none)
+HANDLE_DW_ASPACE_PRED(AMDGPU::DWARFAS::GENERIC, AMDGPU_generic, SELECT_AMDGPU)
+HANDLE_DW_ASPACE_PRED(AMDGPU::DWARFAS::REGION, AMDGPU_region, SELECT_AMDGPU)
+HANDLE_DW_ASPACE_PRED(AMDGPU::DWARFAS::LOCAL, AMDGPU_local, SELECT_AMDGPU)
+HANDLE_DW_ASPACE_PRED(AMDGPU::DWARFAS::PRIVATE_LANE, AMDGPU_private_lane, 
SELECT_AMDGPU)
+HANDLE_DW_ASPACE_PRED(AMDGPU::DWARFAS::PRIVATE_WAVE, AMDGPU_private_wave, 
SELECT_AMDGPU)
 
 // Apple extensions.
 
@@ -916,6 +940,19 @@ HANDLE_DW_OP(0xe9, LLVM_user, -1, -1, 0, LLVM)
 // location stack or any of its values. It is defined as a placeholder for
 // testing purposes.
 HANDLE_DW_OP_LLVM_USEROP(0x0001, nop)
+// Heterogeneous Debugging Extension defined at
+// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html.
+HANDLE_DW_OP_LLVM_USEROP(0x0002, form_aspace_address)
+HANDLE_DW_OP_LLVM_USEROP(0x0003, push_lane)
+HANDLE_DW_OP_LLVM_USEROP(0x0004, offset)
+HANDLE_DW_OP_LLVM_USEROP(0x0005, offset_uconst)
+HANDLE_DW_OP_LLVM_USEROP(0x0006, bit_offset)
+HANDLE_DW_OP_LLVM_USEROP(0x0007, call_frame_entry_reg)
+HANDLE_DW_OP_LLVM_USEROP(0x0008, undefined)
+HANDLE_DW_OP_LLVM_USEROP(0x0009, aspace_bregx)
+HANDLE_DW_OP_LLVM_USEROP(0x000a, piece_end)
+HANDLE_DW_OP_LLVM_USEROP(0x000b, extend)
+HANDLE_DW_OP_LLVM_USEROP(0x000c, select_bit_piece)
 
 // DWARF languages.
 HANDLE_DW_LANG(0x0001, C89, 0, 2, DWARF)
@@ -1385,3 +1422,5 @@ HANDLE_DW_SECT(8, RNGLISTS)
 #undef HANDLE_DW_END
 #undef HANDLE_DW_SECT
 #undef HANDLE_DW_APPLE_ENUM_KIND
+#undef HANDLE_DW_ASPACE
+#undef HANDLE_DW_ASPACE_PRED
diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.h 
b/llvm/include/llvm/BinaryFormat/Dwarf.h
index 231b7ac17d75f..35c22858f0b27 100644
--- a/llvm/include/llvm/BinaryFormat/Dwarf.h
+++ b/llvm/include/llvm/BinaryFormat/Dwarf.h
@@ -19,6 +19,7 @@
 #ifndef LLVM_BINARYFORMAT_DWARF_H
 #define LLVM_BINARYFORMAT_DWARF_H
 
+#include "llvm/Support/AMDGPUAddrSpace.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/DataTypes.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -757,6 +758,12 @@ enum CallingConvention {
   DW_CC_hi_user = 0xff
 };
 
+enum AddressSpace {
+#define HANDLE_DW_ASPACE(ID, NAME) DW_ASPACE_LLVM_##NAME = ID,
+#define HANDLE_DW_ASPACE_PRED(ID, NAME, PRED) DW_ASPACE_LLVM_##NAME = ID,
+#include "llvm/BinaryFormat/Dwarf.def"
+};
+
 enum InlineAttribute {
   // Inline codes
   DW_INL_not_inlined = 0x00,
@@ -1011,6 +1018,7 @@ LLVM_ABI StringRef IndexString(unsigned Idx);
 LLVM_ABI StringRef FormatString(DwarfFormat Format);
 LLVM_ABI StringRef FormatString(bool IsDWARF64);
 LLVM_ABI StringRef RLEString(unsigned RLE);
+LLVM_ABI StringRef AddressSpaceString(unsigned AS, llvm::Triple TT);
 /// @}
 
 /// \defgroup DwarfConstantsParsing Dwarf constants parsing functions
diff --git a/llvm/include/llvm/Support/AMDGPUAddrSpace.h 
b/llvm/include/llvm/Support/AMDGPUAddrSpace.h
index b1b1dd49a2c4a..173de872b60a7 100644
--- a/llvm/include/llvm/Support/AMDGPUAddrSpace.h
+++ b/llvm/include/llvm/Support/AMDGPUAddrSpace.h
@@ -120,6 +120,46 @@ inline bool isConstantAddressSpace(unsigned AS) {
     return false;
   }
 }
+
+namespace DWARFAS {
+enum : unsigned {
+  GLOBAL = 0,
+  GENERIC = 1,
+  REGION = 2,
+  LOCAL = 3,
+  PRIVATE_LANE = 5,
+  PRIVATE_WAVE = 6,
+  DEFAULT = GLOBAL,
+};
+} // namespace DWARFAS
+
+/// If @p LLVMAddressSpace has a corresponding DWARF encoding,
+/// return it; otherwise return the sentinel value -1 to indicate
+/// no such mapping exists.
+///
+/// This maps private/scratch to the focused lane view.
+///
+/// These mappings must be kept in sync with llvm/docs/AMDGPUUsage.rst
+/// table "AMDGPU DWARF Address Space Mapping".
+///
+/// Note: This could return std::optional<int> but that would require
+/// an extra #include.
+inline int mapToDWARFAddrSpace(unsigned LLVMAddrSpace) {
+  static constexpr unsigned LLVMToDWARFAddrSpaceMapping[] = {
+      DWARFAS::GENERIC,     //< AMDGPUAS::FLAT_ADDRESS
+      DWARFAS::GLOBAL,      //< AMDGPUAS::GLOBAL_ADDRESS
+      DWARFAS::REGION,      //< AMDGPUAS::REGION_ADDRESS
+      DWARFAS::LOCAL,       //< AMDGPUAS::LOCAL_ADDRESS
+      DWARFAS::GLOBAL,      //< AMDGPUAS::CONSTANT_ADDRESS
+      DWARFAS::PRIVATE_LANE //< AMDGPUAS::PRIVATE_ADDRESS
+  };
+  static constexpr unsigned SizeOfLLVMToDWARFAddrSpaceMapping =
+      sizeof(LLVMToDWARFAddrSpaceMapping) /
+      sizeof(LLVMToDWARFAddrSpaceMapping[0]);
+  if (LLVMAddrSpace < SizeOfLLVMToDWARFAddrSpaceMapping)
+    return LLVMToDWARFAddrSpaceMapping[LLVMAddrSpace];
+  return -1;
+}
 } // end namespace AMDGPU
 
 } // end namespace llvm
diff --git a/llvm/lib/BinaryFormat/Dwarf.cpp b/llvm/lib/BinaryFormat/Dwarf.cpp
index 0d17dc175fed9..69e28c2716170 100644
--- a/llvm/lib/BinaryFormat/Dwarf.cpp
+++ b/llvm/lib/BinaryFormat/Dwarf.cpp
@@ -911,6 +911,27 @@ StringRef llvm::dwarf::RLEString(unsigned RLE) {
   }
 }
 
+StringRef llvm::dwarf::AddressSpaceString(unsigned AS, llvm::Triple TT) {
+  switch (AS) {
+#define HANDLE_DW_ASPACE(ID, NAME)                                             
\
+  case DW_ASPACE_LLVM_##NAME:                                                  
\
+    return "DW_ASPACE_LLVM_" #NAME;
+#define HANDLE_DW_ASPACE_PRED(ID, NAME, PRED)
+#include "llvm/BinaryFormat/Dwarf.def"
+  default:
+    break;
+  }
+
+  bool SELECT_AMDGPU = TT.isAMDGPU();
+#define HANDLE_DW_ASPACE(ID, NAME)
+#define HANDLE_DW_ASPACE_PRED(ID, NAME, PRED)                                  
\
+  if (DW_ASPACE_LLVM_##NAME == AS && PRED)                                     
\
+    return "DW_ASPACE_LLVM_" #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+
+  return "";
+}
+
 StringRef (*const llvm::dwarf::EnumTraits<Tag>::StringFn)(unsigned) = 
TagString;
 StringRef (*const llvm::dwarf::EnumTraits<Attribute>::StringFn)(unsigned) =
     AttributeString;
diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp 
b/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
index ebcd4dda50488..10b747f06c2e4 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFExpressionPrinter.cpp
@@ -56,10 +56,19 @@ static bool printOp(const DWARFExpression::Operation *Op, 
raw_ostream &OS,
   assert(!Name.empty() && "DW_OP has no name!");
   OS << Name;
 
+  std::optional<unsigned> SubOpcode = Op->getSubCode();
+  if (SubOpcode) {
+    StringRef SubName = SubOperationEncodingString(Op->getCode(), *SubOpcode);
+    assert(!SubName.empty() && "DW_OP SubOp has no name!");
+    OS << " " << SubName;
+  }
+
   if ((Op->getCode() >= DW_OP_breg0 && Op->getCode() <= DW_OP_breg31) ||
       (Op->getCode() >= DW_OP_reg0 && Op->getCode() <= DW_OP_reg31) ||
       Op->getCode() == DW_OP_bregx || Op->getCode() == DW_OP_regx ||
-      Op->getCode() == DW_OP_regval_type)
+      Op->getCode() == DW_OP_regval_type ||
+      (SubOpcode && (*SubOpcode == DW_OP_LLVM_call_frame_entry_reg ||
+                     *SubOpcode == DW_OP_LLVM_aspace_bregx)))
     if (prettyPrintRegisterOp(U, OS, DumpOpts, Op->getCode(),
                               Op->getRawOperands()))
       return true;
@@ -70,10 +79,8 @@ static bool printOp(const DWARFExpression::Operation *Op, 
raw_ostream &OS,
     unsigned Signed = Size & DWARFExpression::Operation::SignBit;
 
     if (Size == DWARFExpression::Operation::SizeSubOpLEB) {
-      StringRef SubName =
-          SubOperationEncodingString(Op->getCode(), 
Op->getRawOperand(Operand));
-      assert(!SubName.empty() && "DW_OP SubOp has no name!");
-      OS << " " << SubName;
+      assert(Operand == 0);
+      assert(SubOpcode);
     } else if (Size == DWARFExpression::Operation::BaseTypeRef && U) {
       // For DW_OP_convert the operand may be 0 to indicate that conversion to
       // the generic type should be done. The same holds for DW_OP_reinterpret,
@@ -219,7 +226,7 @@ static bool printCompactDWARFExpr(
       break;
     }
     case dwarf::DW_OP_LLVM_user: {
-      assert(Op.getSubCode() == dwarf::DW_OP_LLVM_nop);
+      assert(Op.getSubCode());
       break;
     }
     default:
@@ -283,8 +290,14 @@ bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
   uint64_t DwarfRegNum;
   unsigned OpNum = 0;
 
+  std::optional<unsigned> SubOpcode;
+  if (Opcode == DW_OP_LLVM_user)
+    SubOpcode = Operands[OpNum++];
+
   if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
-      Opcode == DW_OP_regval_type)
+      Opcode == DW_OP_regval_type ||
+      (SubOpcode && (*SubOpcode == DW_OP_LLVM_aspace_bregx ||
+                     *SubOpcode == 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;
@@ -294,7 +307,8 @@ bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
   auto RegName = DumpOpts.GetNameForDWARFReg(DwarfRegNum, DumpOpts.IsEH);
   if (!RegName.empty()) {
     if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
-        Opcode == DW_OP_bregx)
+        Opcode == DW_OP_bregx ||
+        (SubOpcode && *SubOpcode == DW_OP_LLVM_aspace_bregx))
       OS << ' ' << RegName << format("%+" PRId64, Operands[OpNum]);
     else
       OS << ' ' << RegName.data();
diff --git a/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp 
b/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
index 9a7f7d1ca2a67..61bd6fcb65bfa 100644
--- a/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
+++ b/llvm/lib/DebugInfo/DWARF/LowLevel/DWARFExpression.cpp
@@ -130,6 +130,23 @@ static std::vector<Desc> getSubOpDescriptions() {
   std::vector<Desc> Descriptions;
   Descriptions.resize(LlvmUserDescriptionsSize);
   Descriptions[DW_OP_LLVM_nop] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
+  Descriptions[DW_OP_LLVM_form_aspace_address] =
+      Desc(Op::Dwarf5, Op::SizeSubOpLEB);
+  Descriptions[DW_OP_LLVM_push_lane] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
+  Descriptions[DW_OP_LLVM_offset] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
+  Descriptions[DW_OP_LLVM_offset_uconst] =
+      Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_bit_offset] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
+  Descriptions[DW_OP_LLVM_call_frame_entry_reg] =
+      Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_undefined] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
+  Descriptions[DW_OP_LLVM_aspace_bregx] =
+      Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_piece_end] = Desc(Op::Dwarf5, Op::SizeSubOpLEB);
+  Descriptions[DW_OP_LLVM_extend] =
+      Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB, Op::SizeLEB);
+  Descriptions[DW_OP_LLVM_select_bit_piece] =
+      Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB, Op::SizeLEB);
   return Descriptions;
 }
 
@@ -164,6 +181,8 @@ bool DWARFExpression::Operation::extract(DataExtractor Data,
         return false;
       assert(Desc.Op[Operand] == Operation::SizeSubOpLEB &&
              "SizeSubOpLEB Description must begin with SizeSubOpLEB operand");
+      Operands.resize(Desc.Op.size());
+      OperandEndOffsets.resize(Desc.Op.size());
       break;
     case Operation::Size1:
       Operands[Operand] = Data.getU8(&Offset);
diff --git a/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous-user-ops.s 
b/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous-user-ops.s
new file mode 100644
index 0000000000000..ef90f31d92a8a
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous-user-ops.s
@@ -0,0 +1,31 @@
+# RUN: llvm-mc %s -filetype=obj -triple=i686-pc-linux -o - | llvm-dwarfdump 
--debug-frame - | FileCheck %s
+
+# CHECK:      .eh_frame contents:
+# CHECK:      FDE
+# CHECK-NEXT: Format: DWARF32
+
+foo:
+ .cfi_startproc
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user 
DW_OP_LLVM_form_aspace_address
+ .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x02
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_push_lane
+ .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x03
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_offset
+ .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x04
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_offset_uconst 
0x0
+ .cfi_escape 0x10, 0x00, 0x03, 0xe9, 0x05, 0x00
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_bit_offset
+ .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x06
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user 
DW_OP_LLVM_call_frame_entry_reg EAX
+ .cfi_escape 0x10, 0x00, 0x03, 0xe9, 0x07, 0x00
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_undefined
+ .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x08
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_aspace_bregx 
EAX+2
+ .cfi_escape 0x10, 0x00, 0x04, 0xe9, 0x09, 0x00, 0x02
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_piece_end
+ .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x0a
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_extend 0x0 0x0
+ .cfi_escape 0x10, 0x00, 0x04, 0xe9, 0x0b, 0x00, 0x00
+ # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user 
DW_OP_LLVM_select_bit_piece 0x0 0x0
+ .cfi_escape 0x10, 0x00, 0x04, 0xe9, 0x0c, 0x00, 0x00
+ .cfi_endproc

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to