[Mlir-commits] [mlir] [mlir] Add support for DIGlobalVariable and DIGlobalVariableExpression (PR #73367)

Justin Wilson llvmlistbot at llvm.org
Fri Nov 24 19:50:00 PST 2023


https://github.com/waj334 updated https://github.com/llvm/llvm-project/pull/73367

>From 8db80b6d8e9f22f693cc5734f73c2ec3e29eed33 Mon Sep 17 00:00:00 2001
From: "Justin A. Wilson" <justin.wilson at omibyte.io>
Date: Fri, 24 Nov 2023 14:22:34 -0600
Subject: [PATCH] [mlir] Add support for DIGlobalVariable,
 DIGlobalVariableExpression and DIExpression

Introduces DIGlobalVariableAttr, DIGlobalVariableExpressionAttr and DIExpressionAttr so that ModuleTranslation can emit the required metadata needed for debug information about global variable. The translator implementation for debug metadata needed to be refactored in order to allow translation of nodes based on MDNode (DIGlobalVariableExpressionAttr and DIExpression) in addition to DINode-based nodes.

A DIGlobalVariableExpressionAttr can now be passed to the GlobalOp operation directly and ModuleTranslation will create the respective DIGlobalVariable and DIGlobalVariableExpression nodes. The compile unit that DIGlobalVariable is expected to be configured with will be updated with the created DIGlobalVariableExpression.
---
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       |  45 +++-
 mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h  |  13 +-
 .../mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td   |   7 +-
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   |   4 +-
 .../mlir/Target/LLVMIR/ModuleTranslation.h    |   1 +
 .../Conversion/LLVMCommon/TypeConverter.cpp   |  10 +-
 mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp      | 249 +++++++++++++++++-
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    |   7 +-
 mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp |  14 +-
 mlir/lib/Target/LLVMIR/DebugImporter.cpp      |  37 ++-
 mlir/lib/Target/LLVMIR/DebugImporter.h        |  19 +-
 mlir/lib/Target/LLVMIR/DebugTranslation.cpp   |  40 ++-
 mlir/lib/Target/LLVMIR/DebugTranslation.h     |  13 +-
 mlir/lib/Target/LLVMIR/ModuleTranslation.cpp  |  16 ++
 mlir/test/Target/LLVMIR/llvmir-debug.mlir     |  14 +-
 15 files changed, 442 insertions(+), 47 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 9e35bf1ba977725..90d2038747ea483 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -11,6 +11,7 @@
 
 include "mlir/Dialect/LLVMIR/LLVMDialect.td"
 include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/CommonAttrConstraints.td"
 
 // All of the attributes will extend this class.
 class LLVM_Attr<string name, string attrMnemonic,
@@ -265,11 +266,13 @@ def LLVM_DITagParameter : LLVM_DIParameter<
 // DIExpressionAttr
 //===----------------------------------------------------------------------===//
 
-// TODO: Implement custom printer/parser for elements so that operators are
-// dumped in textual form.
-def LLVM_DIExpressionAttr : ArrayOfAttr<LLVM_Dialect, "DIExpression",
-                                        "di_expr", "uint64_t"> {
-  let assemblyFormat = "`<` `[` (`]` `>`) : ($value^ `]` `>`)?";
+def LLVM_DIExpressionAttr : LLVM_Attr<"DIExpression", "di_expression",
+                                          /*traits=*/[], "MDNodeAttr"> {
+  let parameters = (ins
+    ArrayRefParameter<"uint64_t">:$operations
+  );
+  //let assemblyFormat = "`<` struct(params) `>`";
+  let hasCustomAssemblyFormat = 1;
 }
 
 //===----------------------------------------------------------------------===//
@@ -447,6 +450,38 @@ def LLVM_DILocalVariableAttr : LLVM_Attr<"DILocalVariable", "di_local_variable",
   let assemblyFormat = "`<` struct(params) `>`";
 }
 
+//===----------------------------------------------------------------------===//
+// DIGlobalVariableExpressionAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DIGlobalVariableExpressionAttr : LLVM_Attr<"DIGlobalVariableExpression", "di_global_variable_expression",
+                                          /*traits=*/[], "MDNodeAttr"> {
+  let parameters = (ins
+    "DIGlobalVariableAttr":$var,
+    OptionalParameter<"DIExpressionAttr">:$expr
+  );
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
+//===----------------------------------------------------------------------===//
+// DIGlobalVariableAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DIGlobalVariable : LLVM_Attr<"DIGlobalVariable", "di_global_variable",
+                                      /*traits=*/[], "DINodeAttr"> {
+  let parameters = (ins
+    "DIScopeAttr":$scope,
+    OptionalParameter<"StringAttr">:$name,
+    OptionalParameter<"StringAttr">:$linkageName,
+    OptionalParameter<"DIFileAttr">:$file,
+    OptionalParameter<"unsigned">:$line,
+    OptionalParameter<"DITypeAttr">:$type,
+    OptionalParameter<"bool">:$isLocalToUnit,
+    OptionalParameter<"bool">:$isDefined,
+    OptionalParameter<"unsigned">:$alignInBits);
+  let assemblyFormat = "`<` struct(params) `>`";
+}
+
 //===----------------------------------------------------------------------===//
 // DISubprogramAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
index c370bfa2b733d65..e49b40e2d487dc8 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrs.h
@@ -23,8 +23,8 @@
 namespace mlir {
 namespace LLVM {
 
-/// This class represents the base attribute for all debug info attributes.
-class DINodeAttr : public Attribute {
+/// This class represents the base attribute for all metadata attributes.
+class MDNodeAttr : public Attribute {
 public:
   using Attribute::Attribute;
 
@@ -32,6 +32,15 @@ class DINodeAttr : public Attribute {
   static bool classof(Attribute attr);
 };
 
+/// This class represents the base attribute for all debug info attributes.
+class DINodeAttr : public MDNodeAttr {
+public:
+  using MDNodeAttr::MDNodeAttr;
+
+  // Support LLVM type casting.
+  static bool classof(Attribute attr);
+};
+
 /// This class represents a LLVM attribute that describes a debug info scope.
 class DIScopeAttr : public DINodeAttr {
 public:
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
index fc088eacfc49744..865bb3217beaf42 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMIntrinsicOps.td
@@ -434,7 +434,8 @@ class LLVM_DbgIntrOp<string name, string argName, list<Trait> traits = []>
         llvm::MetadataAsValue::get(ctx,
             llvm::ValueAsMetadata::get(moduleTranslation.lookupValue(opInst.getOperand(0)))),
         llvm::MetadataAsValue::get(ctx, moduleTranslation.translateDebugInfo($varInfo)),
-        llvm::MetadataAsValue::get(ctx, llvm::DIExpression::get(ctx, $locationExpr)),
+        llvm::MetadataAsValue::get(ctx, llvm::DIExpression::get(ctx, $locationExpr ?
+                                                                (*$locationExpr).getOperations() : ArrayRef<uint64_t>({}))),
       });
   }];
   let mlirBuilder = [{
@@ -455,7 +456,7 @@ def LLVM_DbgDeclareOp : LLVM_DbgIntrOp<"dbg.declare", "addr",
   let arguments = (ins
     LLVM_AnyPointer:$addr,
     LLVM_DILocalVariableAttr:$varInfo,
-    DefaultValuedAttr<LLVM_DIExpressionAttr, "std::nullopt">:$locationExpr
+    OptionalAttr<LLVM_DIExpressionAttr>:$locationExpr
   );
 }
 
@@ -465,7 +466,7 @@ def LLVM_DbgValueOp : LLVM_DbgIntrOp<"dbg.value", "value",
   let arguments = (ins
     LLVM_Type:$value,
     LLVM_DILocalVariableAttr:$varInfo,
-    DefaultValuedAttr<LLVM_DIExpressionAttr, "std::nullopt">:$locationExpr
+    OptionalAttr<LLVM_DIExpressionAttr>:$locationExpr
   );
 }
 
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 88f4f81735372b9..ecfdced641299fe 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -1087,6 +1087,7 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
     OptionalAttr<UnnamedAddr>:$unnamed_addr,
     OptionalAttr<StrAttr>:$section,
     OptionalAttr<SymbolRefAttr>:$comdat,
+    OptionalAttr<LLVM_DIGlobalVariableExpressionAttr>:$dbg_expr,
     DefaultValuedAttr<Visibility, "mlir::LLVM::Visibility::Default">:$visibility_
   );
   let summary = "LLVM dialect global.";
@@ -1196,7 +1197,8 @@ def LLVM_GlobalOp : LLVM_Op<"mlir.global",
       CArg<"bool", "false">:$dsoLocal,
       CArg<"bool", "false">:$thread_local_,
       CArg<"SymbolRefAttr", "{}">:$comdat,
-      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs)>
+      CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs,
+      CArg<"DIGlobalVariableExpressionAttr", "{}">:$dbgExpr)>
   ];
 
   let extraClassDeclaration = [{
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 4820e826d0ca357..a94596cc9583b1f 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -46,6 +46,7 @@ class LoopAnnotationTranslation;
 
 class AliasScopeAttr;
 class AliasScopeDomainAttr;
+class MDNodeAttr;
 class DINodeAttr;
 class LLVMFuncOp;
 class ComdatSelectorOp;
diff --git a/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp b/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp
index 3a01795ce3f53e5..a306007953d5b7b 100644
--- a/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp
+++ b/mlir/lib/Conversion/LLVMCommon/TypeConverter.cpp
@@ -86,7 +86,15 @@ LLVMTypeConverter::LLVMTypeConverter(MLIRContext *ctx,
 
     if (type.isIdentified()) {
       auto convertedType = LLVM::LLVMStructType::getIdentified(
-          type.getContext(), ("_Converted." + type.getName()).str());
+          type.getContext(), ("_Converted_" + type.getName()).str());
+      unsigned counter = 1;
+      while (convertedType.isInitialized()) {
+        assert(counter != UINT_MAX &&
+               "about to overflow struct renaming counter in conversion");
+        convertedType = LLVM::LLVMStructType::getIdentified(
+            type.getContext(),
+            ("_Converted_" + std::to_string(counter) + type.getName()).str());
+      }
 
       SmallVectorImpl<Type> &recursiveStack = getCurrentThreadRecursiveStack();
       if (llvm::count(recursiveStack, type)) {
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
index 3d45ab8fac4d705..cf1e5980a859728 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMAttrs.cpp
@@ -34,17 +34,27 @@ void LLVMDialect::registerAttributes() {
   addAttributes<
 #define GET_ATTRDEF_LIST
 #include "mlir/Dialect/LLVMIR/LLVMOpsAttrDefs.cpp.inc"
+
       >();
 }
 
+//===----------------------------------------------------------------------===//
+// MDNodeAttr
+//===----------------------------------------------------------------------===//
+
+bool MDNodeAttr::classof(Attribute attr) {
+  return llvm::isa<DINodeAttr, DIExpressionAttr,
+                   DIGlobalVariableExpressionAttr>(attr);
+}
+
 //===----------------------------------------------------------------------===//
 // DINodeAttr
 //===----------------------------------------------------------------------===//
 
 bool DINodeAttr::classof(Attribute attr) {
   return llvm::isa<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
-                   DIDerivedTypeAttr, DIFileAttr, DILabelAttr,
-                   DILexicalBlockAttr, DILexicalBlockFileAttr,
+                   DIDerivedTypeAttr, DIFileAttr, DIGlobalVariableAttr,
+                   DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr,
                    DILocalVariableAttr, DIModuleAttr, DINamespaceAttr,
                    DINullTypeAttr, DISubprogramAttr, DISubrangeAttr,
                    DISubroutineTypeAttr>(attr);
@@ -109,3 +119,238 @@ bool MemoryEffectsAttr::isReadWrite() {
     return false;
   return true;
 }
+
+//===----------------------------------------------------------------------===//
+// DIExpression
+//===----------------------------------------------------------------------===//
+
+#define _FORMAT_DW_OP(x) #x
+#define FORMAT_DW_OP(NAME, VENDOR) _FORMAT_DW_OP(DW_OP_##VENDOR##_##NAME)
+
+size_t queryNumOpParams(llvm::dwarf::LocationAtom op) {
+  switch (op) {
+  case llvm::dwarf::DW_OP_addr:
+  case llvm::dwarf::DW_OP_const1u:
+  case llvm::dwarf::DW_OP_const1s:
+  case llvm::dwarf::DW_OP_const2u:
+  case llvm::dwarf::DW_OP_const2s:
+  case llvm::dwarf::DW_OP_const4u:
+  case llvm::dwarf::DW_OP_const4s:
+  case llvm::dwarf::DW_OP_const8u:
+  case llvm::dwarf::DW_OP_const8s:
+  case llvm::dwarf::DW_OP_constu:
+  case llvm::dwarf::DW_OP_consts:
+  case llvm::dwarf::DW_OP_pick:
+  case llvm::dwarf::DW_OP_plus_uconst:
+  case llvm::dwarf::DW_OP_bra:
+  case llvm::dwarf::DW_OP_skip:
+  case llvm::dwarf::DW_OP_breg0:
+  case llvm::dwarf::DW_OP_breg1:
+  case llvm::dwarf::DW_OP_breg2:
+  case llvm::dwarf::DW_OP_breg3:
+  case llvm::dwarf::DW_OP_breg4:
+  case llvm::dwarf::DW_OP_breg5:
+  case llvm::dwarf::DW_OP_breg6:
+  case llvm::dwarf::DW_OP_breg7:
+  case llvm::dwarf::DW_OP_breg8:
+  case llvm::dwarf::DW_OP_breg9:
+  case llvm::dwarf::DW_OP_breg10:
+  case llvm::dwarf::DW_OP_breg11:
+  case llvm::dwarf::DW_OP_breg12:
+  case llvm::dwarf::DW_OP_breg13:
+  case llvm::dwarf::DW_OP_breg14:
+  case llvm::dwarf::DW_OP_breg15:
+  case llvm::dwarf::DW_OP_breg16:
+  case llvm::dwarf::DW_OP_breg17:
+  case llvm::dwarf::DW_OP_breg18:
+  case llvm::dwarf::DW_OP_breg19:
+  case llvm::dwarf::DW_OP_breg20:
+  case llvm::dwarf::DW_OP_breg21:
+  case llvm::dwarf::DW_OP_breg22:
+  case llvm::dwarf::DW_OP_breg23:
+  case llvm::dwarf::DW_OP_breg24:
+  case llvm::dwarf::DW_OP_breg25:
+  case llvm::dwarf::DW_OP_breg26:
+  case llvm::dwarf::DW_OP_breg27:
+  case llvm::dwarf::DW_OP_breg28:
+  case llvm::dwarf::DW_OP_breg29:
+  case llvm::dwarf::DW_OP_breg30:
+  case llvm::dwarf::DW_OP_breg31:
+  case llvm::dwarf::DW_OP_regx:
+  case llvm::dwarf::DW_OP_fbreg:
+  case llvm::dwarf::DW_OP_piece:
+  case llvm::dwarf::DW_OP_deref_size:
+  case llvm::dwarf::DW_OP_xderef_size:
+  case llvm::dwarf::DW_OP_call2:
+  case llvm::dwarf::DW_OP_call4:
+  case llvm::dwarf::DW_OP_call_ref:
+  case llvm::dwarf::DW_OP_addrx:
+  case llvm::dwarf::DW_OP_constx:
+  case llvm::dwarf::DW_OP_convert:
+  case llvm::dwarf::DW_OP_reinterpret:
+    return 1;
+  case llvm::dwarf::DW_OP_bregx:
+  case llvm::dwarf::DW_OP_bit_piece:
+  case llvm::dwarf::DW_OP_implicit_value:
+  case llvm::dwarf::DW_OP_implicit_pointer:
+  case llvm::dwarf::DW_OP_entry_value:
+  case llvm::dwarf::DW_OP_regval_type:
+  case llvm::dwarf::DW_OP_deref_type:
+  case llvm::dwarf::DW_OP_xderef_type:
+    return 2;
+  case llvm::dwarf::DW_OP_const_type:
+    return 3;
+  default:
+    return 0;
+  }
+}
+
+::mlir::Attribute DIExpressionAttr::parse(AsmParser &parser, Type type) {
+  SmallVector<uint64_t, 1> operations;
+
+  // Begin parsing the attribute
+  if (parser.parseLess()) {
+    parser.emitError(parser.getNameLoc()) << "expected `<`";
+    return {};
+  }
+
+  if (parser.parseLSquare()) {
+    parser.emitError(parser.getNameLoc()) << "expected `[`";
+    return {};
+  }
+
+  // Begin parsing the operations list.
+  while (true) {
+    uint64_t op = 0;
+
+    // Attempt to parse the operation as an integer first.
+    if (OptionalParseResult parsedInteger = parser.parseOptionalInteger(op);
+        parsedInteger.has_value() && !failed(*parsedInteger)) {
+      operations.push_back(op);
+    } else {
+      // Fallback to parsing an operation in its textual form
+      StringRef opName;
+      if (OptionalParseResult parsedName = parser.parseOptionalKeyword(&opName);
+          parsedName.has_value() && !failed(*parsedName)) {
+        // Translate the string into the respective operation integer value.
+        op = StringSwitch<uint64_t>(opName)
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR)                                \
+  .Case(FORMAT_DW_OP(NAME, VENDOR), ID)
+#include "llvm/BinaryFormat/Dwarf.def"
+
+                 .Default(0);
+      }
+
+      // Was the resulting operation valid?
+      if (op == 0) {
+        parser.emitError(parser.getNameLoc())
+            << "expected valid expression operator, got \"" << opName << "\"";
+        return {};
+      }
+    }
+
+    // Was an operation value parsed?
+    if (op == 0) {
+      parser.emitError(parser.getNameLoc())
+          << "expected valid expression operator, got " << op;
+      return {};
+    }
+
+    // Parse the operation operands
+    const auto numArgs =
+        queryNumOpParams(static_cast<llvm::dwarf::LocationAtom>(op));
+    if (numArgs > 0) {
+      if (parser.parseLParen()) {
+        parser.emitError(parser.getNameLoc()) << "expected `(` before operands";
+        return {};
+      }
+
+      for (size_t i = 0; i < numArgs; i++) {
+        // Parse the arg
+        uint64_t arg;
+        if (parser.parseInteger(arg)) {
+          parser.emitError(parser.getNameLoc())
+              << "expected value for operand #" << i;
+          return {};
+        }
+
+        // Append the operand to the operations list following the operation.
+        operations.push_back(arg);
+
+        if (i + 1 != numArgs) {
+          // operands must be comma-separated
+          if (parser.parseComma()) {
+            parser.emitError(parser.getNameLoc())
+                << "expected `,` following operand #" << i;
+            return {};
+          }
+        }
+      }
+
+      if (parser.parseRParen()) {
+        parser.emitError(parser.getNameLoc())
+            << "expected `)` following operands";
+        return {};
+      }
+    }
+
+    // operations are expected to comma-separated.
+    if (succeeded(parser.parseOptionalComma())) {
+      // Begin parsing the next operation.
+      continue;
+    }
+
+    // If no comma is parsed, then `]` is expected to end the operations list.
+    if (failed(parser.parseOptionalRSquare())) {
+      parser.emitError(parser.getNameLoc()) << "expected `]`";
+      return {};
+    }
+
+    // Stop parsing the operation list.
+    break;
+  }
+
+  // Finish parsing the attribute.
+  if (parser.parseGreater()) {
+    parser.emitError(parser.getNameLoc()) << "expected `>`";
+    return {};
+  }
+  return DIExpressionAttr::get(parser.getContext(), operations);
+}
+
+void DIExpressionAttr::print(AsmPrinter &printer) const {
+  const auto operations = getOperations();
+  printer << "<[";
+  for (size_t i = 0; i < operations.size(); i++) {
+    const auto op = operations[i];
+    switch (op) {
+#define HANDLE_DW_OP(ID, NAME, VERSION, VENDOR)                                \
+  case ID:                                                                     \
+    printer << FORMAT_DW_OP(NAME, VENDOR);                                     \
+    break;
+#include "llvm/BinaryFormat/Dwarf.def"
+
+    default:
+      assert(false && "unhandled expression operation");
+    }
+
+    // Print the operands as integers for this operation if any
+    const auto numArgs =
+        queryNumOpParams(static_cast<llvm::dwarf::LocationAtom>(op));
+    if (numArgs > 0) {
+      printer << "(";
+      for (size_t i = 0; i < numArgs; i++) {
+        printer << operations[i];
+        if (i + 1 != numArgs) {
+          printer << ", ";
+        }
+      }
+      printer << ")";
+    }
+
+    if (i + 1 != operations.size()) {
+      printer << ", ";
+    }
+  }
+  printer << "]>";
+}
\ No newline at end of file
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index f6c8f388732c3da..2ae1d2ad8249e2f 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -1781,7 +1781,8 @@ void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type,
                      bool isConstant, Linkage linkage, StringRef name,
                      Attribute value, uint64_t alignment, unsigned addrSpace,
                      bool dsoLocal, bool threadLocal, SymbolRefAttr comdat,
-                     ArrayRef<NamedAttribute> attrs) {
+                     ArrayRef<NamedAttribute> attrs,
+                     DIGlobalVariableExpressionAttr dbgExpr) {
   result.addAttribute(getSymNameAttrName(result.name),
                       builder.getStringAttr(name));
   result.addAttribute(getGlobalTypeAttrName(result.name), TypeAttr::get(type));
@@ -1812,6 +1813,10 @@ void GlobalOp::build(OpBuilder &builder, OperationState &result, Type type,
     result.addAttribute(getAddrSpaceAttrName(result.name),
                         builder.getI32IntegerAttr(addrSpace));
   result.attributes.append(attrs.begin(), attrs.end());
+
+  if (dbgExpr)
+    result.addAttribute(getDbgExprAttrName(result.name), dbgExpr);
+
   result.addRegion();
 }
 
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp
index 43349a26ad11276..4b318fc4f4d7a60 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMMemorySlot.cpp
@@ -45,9 +45,10 @@ void LLVM::AllocaOp::handleBlockArgument(const MemorySlot &slot,
                                          RewriterBase &rewriter) {
   for (Operation *user : getOperation()->getUsers())
     if (auto declareOp = llvm::dyn_cast<LLVM::DbgDeclareOp>(user))
-      rewriter.create<LLVM::DbgValueOp>(declareOp.getLoc(), argument,
-                                        declareOp.getVarInfo(),
-                                        declareOp.getLocationExpr());
+      rewriter.create<LLVM::DbgValueOp>(
+          declareOp.getLoc(), argument, declareOp.getVarInfo(),
+          declareOp.getLocationExpr() ? *declareOp.getLocationExpr()
+                                      : DIExpressionAttr());
 }
 
 void LLVM::AllocaOp::handlePromotionComplete(const MemorySlot &slot,
@@ -174,9 +175,10 @@ DeletionKind LLVM::StoreOp::removeBlockingUses(
   // pointer.
   for (Operation *user : slot.ptr.getUsers())
     if (auto declareOp = dyn_cast<LLVM::DbgDeclareOp>(user))
-      rewriter.create<LLVM::DbgValueOp>(declareOp->getLoc(), getValue(),
-                                        declareOp.getVarInfo(),
-                                        declareOp.getLocationExpr());
+      rewriter.create<LLVM::DbgValueOp>(
+          declareOp->getLoc(), getValue(), declareOp.getVarInfo(),
+          declareOp.getLocationExpr() ? *declareOp.getLocationExpr()
+                                      : DIExpressionAttr());
   return DeletionKind::Delete;
 }
 
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
index 36a03ec71c0c6c6..ae221bd1779eeeb 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -61,7 +61,7 @@ DICompositeTypeAttr DebugImporter::translateImpl(llvm::DICompositeType *node) {
   SmallVector<DINodeAttr> elements;
   for (llvm::DINode *element : node->getElements()) {
     assert(element && "expected a non-null element type");
-    elements.push_back(translate(element));
+    elements.push_back(cast<DINodeAttr>(translate(element)));
   }
   // Drop the elements parameter if a cyclic dependency is detected. We
   // currently cannot model these cycles and thus drop the parameter if
@@ -116,6 +116,27 @@ DebugImporter::translateImpl(llvm::DILexicalBlockFile *node) {
                                      node->getDiscriminator());
 }
 
+DIExpressionAttr DebugImporter::translateImpl(llvm::DIExpression *node) {
+  return DIExpressionAttr::get(context, node->getElements());
+}
+
+DIGlobalVariableExpressionAttr
+DebugImporter::translateImpl(llvm::DIGlobalVariableExpression *node) {
+  return DIGlobalVariableExpressionAttr::get(context,
+                                             translate(node->getVariable()),
+                                             translate(node->getExpression()));
+}
+
+DIGlobalVariableAttr
+DebugImporter::translateImpl(llvm::DIGlobalVariable *node) {
+  return DIGlobalVariableAttr::get(
+      context, translate(node->getScope()),
+      StringAttr::get(context, node->getName()),
+      StringAttr::get(context, node->getLinkageName()),
+      translate(node->getFile()), node->getLine(), translate(node->getType()),
+      node->isLocalToUnit(), node->isDefinition(), node->getAlignInBits());
+}
+
 DILocalVariableAttr DebugImporter::translateImpl(llvm::DILocalVariable *node) {
   return DILocalVariableAttr::get(context, translate(node->getScope()),
                                   getStringAttrOrNull(node->getRawName()),
@@ -204,12 +225,12 @@ DITypeAttr DebugImporter::translateImpl(llvm::DIType *node) {
   return cast<DITypeAttr>(translate(static_cast<llvm::DINode *>(node)));
 }
 
-DINodeAttr DebugImporter::translate(llvm::DINode *node) {
+MDNodeAttr DebugImporter::translate(llvm::MDNode *node) {
   if (!node)
     return nullptr;
 
   // Check for a cached instance.
-  if (DINodeAttr attr = nodeToAttr.lookup(node))
+  if (MDNodeAttr attr = nodeToAttr.lookup(node))
     return attr;
 
   // Return nullptr if a cyclic dependency is detected since the same node is
@@ -220,7 +241,7 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
   auto guard = llvm::make_scope_exit([&]() { translationStack.pop_back(); });
 
   // Convert the debug metadata if possible.
-  auto translateNode = [this](llvm::DINode *node) -> DINodeAttr {
+  auto translateNode = [this](llvm::MDNode *node) -> MDNodeAttr {
     if (auto *casted = dyn_cast<llvm::DIBasicType>(node))
       return translateImpl(casted);
     if (auto *casted = dyn_cast<llvm::DICompileUnit>(node))
@@ -231,6 +252,12 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
       return translateImpl(casted);
     if (auto *casted = dyn_cast<llvm::DIFile>(node))
       return translateImpl(casted);
+    if (auto *casted = dyn_cast<llvm::DIExpression>(node))
+      return translateImpl(casted);
+    if (auto *casted = dyn_cast<llvm::DIGlobalVariableExpression>(node))
+      return translateImpl(casted);
+    if (auto *casted = dyn_cast<llvm::DIGlobalVariable>(node))
+      return translateImpl(casted);
     if (auto *casted = dyn_cast<llvm::DILabel>(node))
       return translateImpl(casted);
     if (auto *casted = dyn_cast<llvm::DILexicalBlock>(node))
@@ -251,7 +278,7 @@ DINodeAttr DebugImporter::translate(llvm::DINode *node) {
       return translateImpl(casted);
     return nullptr;
   };
-  if (DINodeAttr attr = translateNode(node)) {
+  if (MDNodeAttr attr = translateNode(node)) {
     nodeToAttr.insert({node, attr});
     return attr;
   }
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.h b/mlir/lib/Target/LLVMIR/DebugImporter.h
index 5c07ec82d0191bc..977465250b1699a 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.h
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.h
@@ -40,15 +40,18 @@ class DebugImporter {
   Location translateFuncLocation(llvm::Function *func);
 
   /// Translates the given LLVM debug metadata to MLIR.
-  DINodeAttr translate(llvm::DINode *node);
+  MDNodeAttr translate(llvm::MDNode *node);
+  MDNodeAttr translate(llvm::DINode *node) {
+    return translate(cast<llvm::MDNode>(node));
+  }
 
   /// Infers the metadata type and translates it to MLIR.
-  template <typename DINodeT>
-  auto translate(DINodeT *node) {
+  template <typename MDNodeT>
+  auto translate(MDNodeT *node) {
     // Infer the MLIR type from the LLVM metadata type.
     using MLIRTypeT = decltype(translateImpl(node));
     return cast_or_null<MLIRTypeT>(
-        translate(static_cast<llvm::DINode *>(node)));
+        translate(static_cast<llvm::MDNode *>(node)));
   }
 
 private:
@@ -61,6 +64,10 @@ class DebugImporter {
   DILabelAttr translateImpl(llvm::DILabel *node);
   DILexicalBlockAttr translateImpl(llvm::DILexicalBlock *node);
   DILexicalBlockFileAttr translateImpl(llvm::DILexicalBlockFile *node);
+  DIExpressionAttr translateImpl(llvm::DIExpression *node);
+  DIGlobalVariableExpressionAttr
+  translateImpl(llvm::DIGlobalVariableExpression *node);
+  DIGlobalVariableAttr translateImpl(llvm::DIGlobalVariable *node);
   DILocalVariableAttr translateImpl(llvm::DILocalVariable *node);
   DIModuleAttr translateImpl(llvm::DIModule *node);
   DINamespaceAttr translateImpl(llvm::DINamespace *node);
@@ -75,11 +82,11 @@ class DebugImporter {
   StringAttr getStringAttrOrNull(llvm::MDString *stringNode);
 
   /// A mapping between LLVM debug metadata and the corresponding attribute.
-  DenseMap<llvm::DINode *, DINodeAttr> nodeToAttr;
+  DenseMap<llvm::MDNode *, MDNodeAttr> nodeToAttr;
 
   /// A stack that stores the metadata nodes that are being traversed. The stack
   /// is used to detect cyclic dependencies during the metadata translation.
-  SetVector<llvm::DINode *> translationStack;
+  SetVector<llvm::MDNode *> translationStack;
 
   MLIRContext *context;
   ModuleOp mlirModule;
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index a15ffb40065a08b..655d575f958ad98 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -189,6 +189,28 @@ DebugTranslation::translateImpl(DILocalVariableAttr attr) {
       /*Annotations=*/nullptr);
 }
 
+llvm::DIExpression *DebugTranslation::translateImpl(DIExpressionAttr attr) {
+  if (attr) {
+    return llvm::DIExpression::get(llvmCtx, attr.getOperations());
+  }
+  return llvm::DIExpression::get(llvmCtx, {});
+}
+
+llvm::DIGlobalVariableExpression *
+DebugTranslation::translateImpl(DIGlobalVariableExpressionAttr attr) {
+  return llvm::DIGlobalVariableExpression::get(
+      llvmCtx, translate(attr.getVar()), translate(attr.getExpr()));
+}
+
+llvm::DIGlobalVariable *
+DebugTranslation::translateImpl(DIGlobalVariableAttr attr) {
+  return llvm::DIGlobalVariable::getDistinct(
+      llvmCtx, translate(attr.getScope()), getMDStringOrNull(attr.getName()),
+      getMDStringOrNull(attr.getLinkageName()), translate(attr.getFile()),
+      attr.getLine(), translate(attr.getType()), attr.getIsLocalToUnit(),
+      attr.getIsDefined(), nullptr, nullptr, attr.getAlignInBits(), nullptr);
+}
+
 llvm::DIScope *DebugTranslation::translateImpl(DIScopeAttr attr) {
   return cast<llvm::DIScope>(translate(DINodeAttr(attr)));
 }
@@ -250,20 +272,22 @@ llvm::DIType *DebugTranslation::translateImpl(DITypeAttr attr) {
   return cast<llvm::DIType>(translate(DINodeAttr(attr)));
 }
 
-llvm::DINode *DebugTranslation::translate(DINodeAttr attr) {
+llvm::MDNode *DebugTranslation::translate(MDNodeAttr attr) {
   if (!attr)
     return nullptr;
   // Check for a cached instance.
-  if (llvm::DINode *node = attrToNode.lookup(attr))
+  if (llvm::MDNode *node = attrToNode.lookup(attr))
     return node;
 
-  llvm::DINode *node =
-      TypeSwitch<DINodeAttr, llvm::DINode *>(attr)
+  llvm::MDNode *node =
+      TypeSwitch<MDNodeAttr, llvm::MDNode *>(attr)
           .Case<DIBasicTypeAttr, DICompileUnitAttr, DICompositeTypeAttr,
-                DIDerivedTypeAttr, DIFileAttr, DILabelAttr, DILexicalBlockAttr,
-                DILexicalBlockFileAttr, DILocalVariableAttr, DIModuleAttr,
-                DINamespaceAttr, DINullTypeAttr, DISubprogramAttr,
-                DISubrangeAttr, DISubroutineTypeAttr>(
+                DIDerivedTypeAttr, DIExpressionAttr, DIFileAttr,
+                DIGlobalVariableAttr, DIGlobalVariableExpressionAttr,
+                DILabelAttr, DILexicalBlockAttr, DILexicalBlockFileAttr,
+                DILocalVariableAttr, DIModuleAttr, DINamespaceAttr,
+                DINullTypeAttr, DISubprogramAttr, DISubrangeAttr,
+                DISubroutineTypeAttr>(
               [&](auto attr) { return translateImpl(attr); });
   attrToNode.insert({attr, node});
   return node;
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.h b/mlir/lib/Target/LLVMIR/DebugTranslation.h
index d22c3d80dafd5f9..a9b5adf9bdf2c59 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.h
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.h
@@ -41,14 +41,17 @@ class DebugTranslation {
   void translate(LLVMFuncOp func, llvm::Function &llvmFunc);
 
   /// Translate the given LLVM debug metadata to LLVM.
-  llvm::DINode *translate(DINodeAttr attr);
+  llvm::MDNode *translate(MDNodeAttr attr);
+  llvm::MDNode *translate(DINodeAttr attr) {
+    return translate(cast<MDNodeAttr>(attr));
+  }
 
   /// Translate the given derived LLVM debug metadata to LLVM.
   template <typename DIAttrT>
   auto translate(DIAttrT attr) {
     // Infer the LLVM type from the attribute type.
     using LLVMTypeT = std::remove_pointer_t<decltype(translateImpl(attr))>;
-    return cast_or_null<LLVMTypeT>(translate(DINodeAttr(attr)));
+    return cast_or_null<LLVMTypeT>(translate(MDNodeAttr(attr)));
   }
 
 private:
@@ -72,6 +75,10 @@ class DebugTranslation {
   llvm::DILexicalBlockFile *translateImpl(DILexicalBlockFileAttr attr);
   llvm::DILocalScope *translateImpl(DILocalScopeAttr attr);
   llvm::DILocalVariable *translateImpl(DILocalVariableAttr attr);
+  llvm::DIExpression *translateImpl(DIExpressionAttr attr);
+  llvm::DIGlobalVariableExpression *
+  translateImpl(DIGlobalVariableExpressionAttr attr);
+  llvm::DIGlobalVariable *translateImpl(DIGlobalVariableAttr attr);
   llvm::DIModule *translateImpl(DIModuleAttr attr);
   llvm::DINamespace *translateImpl(DINamespaceAttr attr);
   llvm::DIScope *translateImpl(DIScopeAttr attr);
@@ -92,7 +99,7 @@ class DebugTranslation {
 
   /// A mapping between debug attribute and the corresponding llvm debug
   /// metadata.
-  DenseMap<Attribute, llvm::DINode *> attrToNode;
+  DenseMap<Attribute, llvm::MDNode *> attrToNode;
 
   /// A mapping between filename and llvm debug file.
   /// TODO: Change this to DenseMap<Identifier, ...> when we can
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 322843e65627603..249be60135c4320 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -782,6 +782,22 @@ LogicalResult ModuleTranslation::convertGlobals() {
     var->setVisibility(convertVisibilityToLLVM(op.getVisibility_()));
 
     globalsMapping.try_emplace(op, var);
+
+    // Add debug information if present
+    if (op.getDbgExpr().has_value()) {
+      const auto globalExpr = debugTranslation->translate(*op.getDbgExpr());
+      auto globalVar = globalExpr->getVariable();
+      var->addDebugInfo(globalExpr);
+
+      // Get the compile unit (scope) of the the global variable
+      if (const auto compileUnit =
+              cast<llvm::DICompileUnit>(globalVar->getScope());
+          compileUnit) {
+        // Update the compile unit with this incoming global variable
+        compileUnit->replaceGlobalVariables(
+            llvm::MDTuple::get(getLLVMContext(), {globalExpr}));
+      }
+    }
   }
 
   // Convert global variable bodies. This is done after all global variables
diff --git a/mlir/test/Target/LLVMIR/llvmir-debug.mlir b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
index e088374ec0eb8e1..38360b89c2a13ec 100644
--- a/mlir/test/Target/LLVMIR/llvmir-debug.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir-debug.mlir
@@ -91,11 +91,17 @@ llvm.func @func_with_debug(%arg: i64) {
   %allocCount = llvm.mlir.constant(1 : i32) : i32
   %alloc = llvm.alloca %allocCount x i64 : (i32) -> !llvm.ptr
 
-  // CHECK: call void @llvm.dbg.value(metadata i64 %[[ARG]], metadata ![[VAR_LOC:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_fragment, 8, 8))
-  // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOC]], metadata ![[ADDR_LOC:[0-9]+]], metadata !DIExpression(DW_OP_LLVM_fragment, 0, 8))
+  // CHECK: call void @llvm.dbg.value(metadata i64 %[[ARG]], metadata ![[VAR_LOC:[0-9]+]], metadata !DIExpression(DW_OP_DWARF_addr, 4 DW_OP_DWARF_const1u, 8))
+  // CHECK: call void @llvm.dbg.value(metadata i64 %[[ARG]], metadata ![[VAR_LOC:[0-9]+]], metadata !DIExpression(DW_OP_DWARF_addr, 4, DW_OP_DWARF_deref))
+  // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOC]], metadata ![[ADDR_LOC:[0-9]+]], metadata !DIExpression(DW_OP_DWARF_addr, 4 DW_OP_DWARF_const1u, 8))
+  // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOC]], metadata ![[ADDR_LOC:[0-9]+]], metadata !DIExpression(DW_OP_DWARF_addr, 4, DW_OP_DWARF_deref))
+  // CHECK: call void @llvm.dbg.declare(metadata ptr %[[ALLOC]], metadata ![[ADDR_LOC:[0-9]+]], metadata !DIExpression(DW_OP_DWARF_addr, 4, DW_OP_DWARF_deref))
   // CHECK: call void @llvm.dbg.value(metadata i64 %[[ARG]], metadata ![[NO_NAME_VAR:[0-9]+]], metadata !DIExpression())
-  llvm.intr.dbg.value #variable #llvm.di_expr<[4096, 8, 8]> = %arg : i64
-  llvm.intr.dbg.declare #variableAddr #llvm.di_expr<[4096, 0, 8]> = %alloc : !llvm.ptr
+  llvm.intr.dbg.value #variable #llvm.di_expression<[3(4), 8(1)]> = %arg : i64
+  llvm.intr.dbg.value #variable #llvm.di_expression<[DW_OP_DWARF_addr(4), DW_OP_DWARF_deref]> = %arg : i64
+  llvm.intr.dbg.declare #variableAddr #llvm.di_expression<[3(4), 8(1)]> = %alloc : !llvm.ptr
+  llvm.intr.dbg.declare #variableAddr #llvm.di_expression<[DW_OP_DWARF_addr(4), DW_OP_DWARF_deref]> = %alloc : !llvm.ptr
+  llvm.intr.dbg.declare #variableAddr #llvm.di_expression<[DW_OP_DWARF_addr(4), 6]> = %alloc : !llvm.ptr
   llvm.intr.dbg.value #noNameVariable = %arg : i64
 
   // CHECK: call void @func_no_debug(), !dbg ![[CALLSITE_LOC:[0-9]+]]



More information about the Mlir-commits mailing list