[Mlir-commits] [mlir] [MLIR][LLVM] Add DILocAttr for debug locations (PR #186146)

Alexander Yermolovich llvmlistbot at llvm.org
Sun Mar 15 14:18:02 PDT 2026


https://github.com/ayermolo updated https://github.com/llvm/llvm-project/pull/186146

>From 8ad0cff8107c53c5bc9fd4aa80d7850aca75c491 Mon Sep 17 00:00:00 2001
From: Alexander Yermolovich <ayermolovich at nvidia.com>
Date: Thu, 12 Mar 2026 15:19:59 +0000
Subject: [PATCH 1/4] [MLIR][LLVM] Add DILocAttr for debug locations

Introduces DILocAttr, a new MLIR location attribute that pairs a
FileLineColLoc with a DIScopeAttr to carry debug scope information
directly on locations instead of encoding it as FusedLoc metadata.
Replaces FusedLoc-with-metadata patterns across the LLVM dialect
transforms.
---
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       | 27 +++++++
 .../Dialect/LLVMIR/LLVMDialectBytecode.td     | 10 +++
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    |  2 +
 .../Transforms/DIScopeForLLVMFuncOp.cpp       | 73 ++++++++++---------
 .../Transforms/InlinerInterfaceImpl.cpp       | 13 ++--
 mlir/lib/Target/LLVMIR/DebugImporter.cpp      | 37 ++++++----
 mlir/lib/Target/LLVMIR/DebugTranslation.cpp   | 27 +++++--
 .../LLVMIR/LLVMToLLVMIRTranslation.cpp        |  4 +
 .../Target/LLVMIR/LoopAnnotationImporter.cpp  | 20 ++++-
 .../LLVMIR/add-debuginfo-func-scope.mlir      |  6 +-
 mlir/test/Dialect/LLVMIR/diloc-attr.mlir      | 17 +++++
 .../Dialect/LLVMIR/invalid-call-location.mlir | 33 +++++++++
 mlir/test/Target/LLVMIR/Import/debug-info.ll  | 28 +++----
 13 files changed, 215 insertions(+), 82 deletions(-)
 create mode 100644 mlir/test/Dialect/LLVMIR/diloc-attr.mlir

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index 36acf244865eb..ccf7bef462786 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -642,6 +642,33 @@ def LLVM_DILexicalBlockFile : LLVM_Attr<"DILexicalBlockFile", "di_lexical_block_
   let genMnemonicAlias = 1;
 }
 
+//===----------------------------------------------------------------------===//
+// DILocAttr
+//===----------------------------------------------------------------------===//
+
+def LLVM_DILocAttr : LocationAttrDef<LLVM_Dialect, "DILoc"> {
+  let description = [{
+    Represents a debug location combining a source position and a debug info
+    scope. Replaces the convention-based FusedLoc encoding for instruction-level
+    and function-level debug locations.
+  }];
+  let mnemonic = "di_loc";
+
+  let parameters = (ins
+    "FileLineColLoc":$sourceLoc,
+    "DILocalScopeAttr":$scope
+  );
+  let assemblyFormat = "`<` $sourceLoc `in` $scope `>`";
+
+  let builders = [
+    AttrBuilderWithInferredContext<(ins
+      "FileLineColLoc":$sourceLoc, "DILocalScopeAttr":$scope
+    ), [{
+      return $_get(sourceLoc.getContext(), sourceLoc, scope);
+    }]>,
+  ];
+}
+
 //===----------------------------------------------------------------------===//
 // DILocalVariableAttr
 //===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
index 659c535c1b671..3da283778d1ff 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
@@ -275,6 +275,15 @@ def DILexicalBlockFileAttr : DialectAttribute<(attr
   VarInt:$discriminator
 )>;
 
+//===----------------------------------------------------------------------===//
+// DILocAttr
+//===----------------------------------------------------------------------===//
+
+def DILocAttr : DialectAttribute<(attr
+  Attr<"FileLineColLoc">:$sourceLoc,
+  Attr<"DILocalScopeAttr">:$scope
+)>;
+
 //===----------------------------------------------------------------------===//
 // DINamespaceAttr
 //===----------------------------------------------------------------------===//
@@ -338,6 +347,7 @@ def LLVMDialectAttributes : DialectAttributes<"LLVM"> {
     DILabelAttr,
     DILexicalBlockAttr,
     DILexicalBlockFileAttr,
+    DILocAttr,
     DILocalVariableAttr,
     DINamespaceAttr,
     DISubprogramAttr,
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index e5bafea345700..70709ea2f477c 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -1142,6 +1142,8 @@ static LogicalResult verifyCallOpDebugInfo(CallOp callOp, LLVMFuncOp callee) {
     return success();
 
   auto hasSubprogram = [](Operation *op) {
+    if (auto diLoc = op->getLoc()->findInstanceOf<LLVM::DILocAttr>())
+      return isa<LLVM::DISubprogramAttr>(diLoc.getScope());
     return op->getLoc()
                ->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>() !=
            nullptr;
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
index 36b31ffc3970e..cb4cb7cab52a4 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
@@ -25,6 +25,8 @@ using namespace mlir;
 static FileLineColLoc extractFileLoc(Location loc) {
   if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
     return fileLoc;
+  if (auto diLoc = dyn_cast<LLVM::DILocAttr>(loc))
+    return diLoc.getSourceLoc();
   if (auto nameLoc = dyn_cast<NameLoc>(loc))
     return extractFileLoc(nameLoc.getChildLoc());
   if (auto opaqueLoc = dyn_cast<OpaqueLoc>(loc))
@@ -47,6 +49,9 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
                                LLVM::DICompileUnitAttr compileUnitAttr) {
 
   Location loc = llvmFunc.getLoc();
+  if (auto diLoc = loc->findInstanceOf<LLVM::DILocAttr>())
+    if (isa<LLVM::DISubprogramAttr>(diLoc.getScope()))
+      return;
   if (loc->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>())
     return;
 
@@ -87,26 +92,30 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
       fileAttr,
       /*line=*/line, /*scopeLine=*/line, subprogramFlags, subroutineTypeAttr,
       /*retainedNodes=*/{}, /*annotations=*/{});
-  llvmFunc->setLoc(FusedLoc::get(context, {loc}, subprogramAttr));
+  FileLineColLoc fileLoc = extractFileLoc(loc);
+  if (!fileLoc)
+    fileLoc = FileLineColLoc::get(context, "<unknown>", line, /*column=*/0);
+  llvmFunc->setLoc(LLVM::DILocAttr::get(fileLoc, subprogramAttr));
 }
 
-// Get a nested loc for inlined functions.
+// Build a DILocAttr for an inlined callee. Each recursion level creates a
+// DILexicalBlockFileAttr whose scope chains back through the caller scopes
+// to the enclosing subprogram. The scope nesting is carried by the
+// DILexicalBlockFileAttr hierarchy, not by nesting locations.
 static Location getNestedLoc(Operation *op, LLVM::DIScopeAttr scopeAttr,
                              Location calleeLoc) {
-  auto calleeFileName = extractFileLoc(calleeLoc).getFilename();
+  FileLineColLoc calleeFileLoc = extractFileLoc(calleeLoc);
   auto *context = op->getContext();
+  StringAttr calleeFileName = calleeFileLoc.getFilename();
   LLVM::DIFileAttr calleeFileAttr =
       LLVM::DIFileAttr::get(context, llvm::sys::path::filename(calleeFileName),
                             llvm::sys::path::parent_path(calleeFileName));
   auto lexicalBlockFileAttr = LLVM::DILexicalBlockFileAttr::get(
       context, scopeAttr, calleeFileAttr, /*discriminator=*/0);
-  Location loc = calleeLoc;
   // Recurse if the callee location is again a call site.
-  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(calleeLoc)) {
-    auto nestedLoc = callSiteLoc.getCallee();
-    loc = getNestedLoc(op, lexicalBlockFileAttr, nestedLoc);
-  }
-  return FusedLoc::get(context, {loc}, lexicalBlockFileAttr);
+  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(calleeLoc))
+    return getNestedLoc(op, lexicalBlockFileAttr, callSiteLoc.getCallee());
+  return LLVM::DILocAttr::get(calleeFileLoc, lexicalBlockFileAttr);
 }
 
 /// Adds DILexicalBlockFileAttr for operations with CallSiteLoc and operations
@@ -114,27 +123,27 @@ static Location getNestedLoc(Operation *op, LLVM::DIScopeAttr scopeAttr,
 static void setLexicalBlockFileAttr(Operation *op) {
   Location opLoc = op->getLoc();
 
-  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(opLoc)) {
-    auto callerLoc = callSiteLoc.getCaller();
-    auto calleeLoc = callSiteLoc.getCallee();
-    LLVM::DIScopeAttr scopeAttr;
-    // We assemble the full inline stack so the parent of this loc must be a
-    // function
-    if (auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>()) {
-      if (auto funcOpLoc =
-              llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
-        scopeAttr = cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
-        op->setLoc(CallSiteLoc::get(getNestedLoc(op, scopeAttr, calleeLoc),
-                                    callerLoc));
-      }
-    }
-
+  auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
+  if (!funcOp)
     return;
+
+  // Extract the subprogram scope from the function's location.
+  LLVM::DISubprogramAttr scopeAttr;
+  if (auto diLoc = funcOp.getLoc()->findInstanceOf<LLVM::DILocAttr>()) {
+    scopeAttr = dyn_cast<LLVM::DISubprogramAttr>(diLoc.getScope());
+  } else if (auto funcOpLoc =
+                 llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
+    scopeAttr = dyn_cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
   }
+  if (!scopeAttr)
+    return;
 
-  auto funcOp = op->getParentOfType<LLVM::LLVMFuncOp>();
-  if (!funcOp)
+  if (auto callSiteLoc = dyn_cast<CallSiteLoc>(opLoc)) {
+    op->setLoc(CallSiteLoc::get(
+        getNestedLoc(op, scopeAttr, callSiteLoc.getCallee()),
+        callSiteLoc.getCaller()));
     return;
+  }
 
   FileLineColLoc opFileLoc = extractFileLoc(opLoc);
   if (!opFileLoc)
@@ -150,23 +159,15 @@ static void setLexicalBlockFileAttr(Operation *op) {
   // Handle cross-file operations: add DILexicalBlockFileAttr when the
   // operation's source file differs from its containing function.
   if (opFile != funcFile) {
-    auto funcOpLoc = llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc());
-    if (!funcOpLoc)
-      return;
-    auto scopeAttr = dyn_cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
-    if (!scopeAttr)
-      return;
-
     auto *context = op->getContext();
     LLVM::DIFileAttr opFileAttr =
         LLVM::DIFileAttr::get(context, llvm::sys::path::filename(opFile),
                               llvm::sys::path::parent_path(opFile));
 
-    LLVM::DILexicalBlockFileAttr lexicalBlockFileAttr =
+    auto lexicalBlockFileAttr =
         LLVM::DILexicalBlockFileAttr::get(context, scopeAttr, opFileAttr, 0);
 
-    Location newLoc = FusedLoc::get(context, {opLoc}, lexicalBlockFileAttr);
-    op->setLoc(newLoc);
+    op->setLoc(LLVM::DILocAttr::get(opFileLoc, lexicalBlockFileAttr));
   }
 }
 
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
index 680fafcc099f2..0b2dbc3a707f7 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
@@ -487,16 +487,15 @@ static void handleAccessGroups(Operation *call,
 static void
 handleLoopAnnotations(Operation *call,
                       iterator_range<Region::iterator> inlinedBlocks) {
-  // Attempt to extract a DISubprogram from the callee.
+  // Attempt to extract a DISubprogram from the caller.
   auto func = call->getParentOfType<FunctionOpInterface>();
   if (!func)
     return;
-  LocationAttr funcLoc = func->getLoc();
-  auto fusedLoc = dyn_cast_if_present<FusedLoc>(funcLoc);
-  if (!fusedLoc)
-    return;
-  auto scope =
-      dyn_cast_if_present<LLVM::DISubprogramAttr>(fusedLoc.getMetadata());
+  LLVM::DISubprogramAttr scope;
+  if (auto diLoc = func->getLoc()->findInstanceOf<LLVM::DILocAttr>())
+    scope = dyn_cast<LLVM::DISubprogramAttr>(diLoc.getScope());
+  else if (auto fusedLoc = dyn_cast_if_present<FusedLoc>(func->getLoc()))
+    scope = dyn_cast_if_present<LLVM::DISubprogramAttr>(fusedLoc.getMetadata());
   if (!scope)
     return;
 
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
index 37140e3a949c7..2fe5f8a0a2b5b 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -33,11 +33,20 @@ Location DebugImporter::translateFuncLocation(llvm::Function *func) {
   if (!subprogram)
     return UnknownLoc::get(context);
 
-  // Add a fused location to link the subprogram information.
   StringAttr fileName = StringAttr::get(context, subprogram->getFilename());
-  return FusedLocWith<DISubprogramAttr>::get(
-      {FileLineColLoc::get(fileName, subprogram->getLine(), /*column=*/0)},
-      translate(subprogram), context);
+  auto fileLoc =
+      FileLineColLoc::get(fileName, subprogram->getLine(), /*column=*/0);
+  auto scope =
+      dyn_cast_or_null<DILocalScopeAttr>(translate(subprogram));
+  // DILocAttr requires a non-null DILocalScopeAttr, but
+  // translateImpl(DISubprogram*) can return null when the subprogram's parent
+  // scope or subroutine type cannot be translated. Preserve the file location
+  // so diagnostics still have source info. This also matches the original
+  // FusedLocWith<DISubprogramAttr> behavior, where a null metadata caused the
+  // location to fail FusedLocWith<DISubprogramAttr> classof checks anyway.
+  if (!scope)
+    return fileLoc;
+  return DILocAttr::get(fileLoc, scope);
 }
 
 //===----------------------------------------------------------------------===//
@@ -465,19 +474,17 @@ Location DebugImporter::translateLoc(llvm::DILocation *loc) {
   if (!loc)
     return UnknownLoc::get(context);
 
-  // Get the file location of the instruction.
-  Location result = FileLineColLoc::get(context, loc->getFilename(),
-                                        loc->getLine(), loc->getColumn());
-
-  // Add scope information.
-  assert(loc->getScope() && "expected non-null scope");
-  result = FusedLocWith<DIScopeAttr>::get({result}, translate(loc->getScope()),
-                                          context);
-
-  // Add call site information, if available.
+  auto fileLoc = FileLineColLoc::get(context, loc->getFilename(),
+                                    loc->getLine(), loc->getColumn());
+  auto scope =
+      dyn_cast_or_null<DILocalScopeAttr>(translate(loc->getScope()));
+  // DILocAttr requires a non-null DILocalScopeAttr. When the scope cannot
+  // be translated, preserve the file location for diagnostics.
+  Location result = scope
+      ? Location(DILocAttr::get(fileLoc, scope))
+      : Location(fileLoc);
   if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
     result = CallSiteLoc::get(result, translateLoc(inlinedAt));
-
   return result;
 }
 
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index 08eee68c195db..52e322f2bf9e6 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -61,12 +61,18 @@ void DebugTranslation::translate(LLVMFuncOp func, llvm::Function &llvmFunc) {
   if (!debugEmissionIsEnabled)
     return;
 
-  // Look for a sub program attached to the function.
-  auto spLoc =
-      func.getLoc()->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>();
-  if (!spLoc)
+  // Look for a subprogram: check DILocAttr first, fall back to FusedLoc.
+  LLVM::DISubprogramAttr sp;
+  if (auto diLoc = func.getLoc()->findInstanceOf<LLVM::DILocAttr>()) {
+    sp = dyn_cast<LLVM::DISubprogramAttr>(diLoc.getScope());
+  } else if (auto spLoc =
+                 func.getLoc()
+                     ->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>()) {
+    sp = spLoc.getMetadata();
+  }
+  if (!sp)
     return;
-  llvmFunc.setSubprogram(translate(spLoc.getMetadata()));
+  llvmFunc.setSubprogram(translate(sp));
 }
 
 //===----------------------------------------------------------------------===//
@@ -543,6 +549,17 @@ llvm::DILocation *DebugTranslation::translateLoc(Location loc,
     if (!llvmLoc)
       llvmLoc = callerLoc;
 
+  } else if (auto diLoc = dyn_cast<LLVM::DILocAttr>(loc)) {
+    // Translate the scope from the DILocAttr.
+    llvm::DILocalScope *diScope = translate(diLoc.getScope());
+    if (!diScope)
+      return nullptr;
+
+    auto sourceLoc = diLoc.getSourceLoc();
+    llvmLoc = llvm::DILocation::get(
+        llvmCtx, sourceLoc.getLine(), sourceLoc.getColumn(), diScope,
+        const_cast<llvm::DILocation *>(inlinedAt));
+
   } else if (auto fileLoc = dyn_cast<FileLineColLoc>(loc)) {
     // A scope of a DILocation cannot be null.
     if (!scope)
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 21f7954fd338a..10d611dfee3a9 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -364,6 +364,10 @@ static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
 static llvm::DILocalScope *
 getLocalScopeFromLoc(llvm::IRBuilderBase &builder, Location loc,
                      LLVM::ModuleTranslation &moduleTranslation) {
+  if (auto diLoc = loc->findInstanceOf<LLVM::DILocAttr>())
+    if (auto *localScope = llvm::dyn_cast<llvm::DILocalScope>(
+            moduleTranslation.translateDebugInfo(diLoc.getScope())))
+      return localScope;
   if (auto scopeLoc =
           loc->findInstanceOf<FusedLocWith<LLVM::DILocalScopeAttr>>())
     if (auto *localScope = llvm::dyn_cast<llvm::DILocalScope>(
diff --git a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
index e4905423347a2..7546bb09d1348 100644
--- a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
@@ -410,10 +410,26 @@ LoopMetadataConversion::convertParallelAccesses() {
   return refs;
 }
 
+/// Convert a translated location to a FusedLoc for loop annotation storage.
+/// translateLoc produces DILocAttr, but LoopAnnotationAttr stores locations as
+/// FusedLoc<scope>[raw_loc]. Extract the source location and scope from the
+/// DILocAttr to build the FusedLoc directly, matching the format expected by
+/// LoopAnnotationTranslation on the export side.
+static FusedLoc toFusedLoc(Location loc) {
+  if (auto fused = dyn_cast<FusedLoc>(loc))
+    return fused;
+  if (isa<UnknownLoc>(loc))
+    return {};
+  if (auto diLoc = dyn_cast<LLVM::DILocAttr>(loc))
+    return dyn_cast<FusedLoc>(FusedLoc::get(
+        {diLoc.getSourceLoc()}, diLoc.getScope(), loc.getContext()));
+  return {};
+}
+
 FusedLoc LoopMetadataConversion::convertStartLoc() {
   if (locations.empty())
     return {};
-  return dyn_cast<FusedLoc>(
+  return toFusedLoc(
       loopAnnotationImporter.moduleImport.translateLoc(locations[0]));
 }
 
@@ -423,7 +439,7 @@ FailureOr<FusedLoc> LoopMetadataConversion::convertEndLoc() {
   if (locations.size() > 2)
     return emitError(loc)
            << "expected loop metadata to have at most two DILocations";
-  return dyn_cast<FusedLoc>(
+  return toFusedLoc(
       loopAnnotationImporter.moduleImport.translateLoc(locations[1]));
 }
 
diff --git a/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir b/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir
index 895c3fcb7fb23..30fc670846851 100644
--- a/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir
+++ b/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir
@@ -6,7 +6,7 @@
 // CHECK: loc(#loc[[LOC:[0-9]+]])
 // CHECK: #di_file = #llvm.di_file<"<unknown>" in "">
 // CHECK: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "func_no_debug", linkageName = "func_no_debug", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
-// CHECK: #loc[[LOC]] = loc(fused<#di_subprogram>
+// CHECK: #loc[[LOC]] = #llvm.di_loc<{{.*}} in #di_subprogram>
 module {
   llvm.func @func_no_debug() {
     llvm.return loc(unknown)
@@ -31,7 +31,7 @@ module {
 // CHECK: loc(#loc[[LOC:[0-9]+]])
 // CHECK: #di_file = #llvm.di_file<"<unknown>" in "">
 // CHECK: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "func_with_debug", linkageName = "func_with_debug", file = #di_file, line = 42, scopeLine = 42, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
-// CHECK: #loc[[LOC]] = loc(fused<#di_subprogram>
+// CHECK: #loc[[LOC]] = loc(fused<#di_subprogram>[
 // CHECK_OTHER_KIND: emissionKind = DebugDirectivesOnly
 module {
   llvm.func @func_with_debug() {
@@ -59,7 +59,7 @@ module {
 // CHECK-DAG: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_C, file = #[[DI_FILE_MODULE]], producer = "MLIR", isOptimized = true, emissionKind = LineTablesOnly>
 // CHECK-DAG: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #[[DI_FILE_FUNC]], name = "propagate_compile_unit", linkageName = "propagate_compile_unit", file = #[[DI_FILE_FUNC]], line = 9, scopeLine = 9, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
 // CHECK-DAG: #loc[[MODULELOC]] = loc(fused<#di_compile_unit>[#loc])
-// CHECK-DAG: #loc[[FUNCLOC]] = loc(fused<#di_subprogram>[#loc[[FUNCFILELOC]]
+// CHECK-DAG: #loc[[FUNCLOC]] = #llvm.di_loc<#loc[[FUNCFILELOC]] in #di_subprogram>
 module {
   llvm.func @propagate_compile_unit() {
     llvm.return loc(unknown)
diff --git a/mlir/test/Dialect/LLVMIR/diloc-attr.mlir b/mlir/test/Dialect/LLVMIR/diloc-attr.mlir
new file mode 100644
index 0000000000000..85abbb7783efb
--- /dev/null
+++ b/mlir/test/Dialect/LLVMIR/diloc-attr.mlir
@@ -0,0 +1,17 @@
+// RUN: mlir-opt %s --mlir-print-debuginfo | FileCheck %s
+//
+// Basic parse/print test for DILocAttr (no snapshots).
+// Uses a single source file and exercises two DILocAttr locations (module and function).
+
+#di_file = #llvm.di_file<"source.c" in "/">
+#di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_C, file = #di_file, isOptimized = false, emissionKind = None>
+#di_subprogram = #llvm.di_subprogram<compileUnit = #di_compile_unit, scope = #di_file, name = "test", file = #di_file, subprogramFlags = Definition>
+
+// CHECK-DAG: #llvm.di_loc<{{.*}} in #di_subprogram>
+// CHECK-DAG: #llvm.di_loc<{{.*}} in #di_subprogram>
+#loc_at_module = #llvm.di_loc<loc("source.c":1:1) in #di_subprogram>
+#loc_at_func = #llvm.di_loc<loc("source.c":10:2) in #di_subprogram>
+
+module {
+  llvm.func @f() {} loc(#loc_at_func)
+} loc(#loc_at_module)
diff --git a/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir b/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir
index 38b4ed9f6e83d..0272292874cdd 100644
--- a/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir
@@ -33,3 +33,36 @@ llvm.func @invalid_call_debug_locs() {
   llvm.call @missing_debug_loc() : () -> () loc(#loc)
   llvm.return
 } loc(#loc4)
+
+// -----
+
+// Test the DILocAttr path of hasSubprogram.
+
+#di_file2 = #llvm.di_file<"file.cpp" in "/folder/">
+#di_compile_unit2 = #llvm.di_compile_unit<
+  id = distinct[0]<>, sourceLanguage = DW_LANG_C_plus_plus_14,
+  file = #di_file2, isOptimized = true, emissionKind = Full
+>
+#di_sp_callee = #llvm.di_subprogram<
+  compileUnit = #di_compile_unit2, scope = #di_file2,
+  name = "callee_diloc", file = #di_file2,
+  subprogramFlags = "Definition|Optimized"
+>
+#di_sp_caller = #llvm.di_subprogram<
+  compileUnit = #di_compile_unit2, scope = #di_file2,
+  name = "caller_diloc", file = #di_file2,
+  subprogramFlags = "Definition|Optimized"
+>
+#loc_unknown = loc(unknown)
+#loc_callee = #llvm.di_loc<loc("file.cpp":10:0) in #di_sp_callee>
+#loc_caller = #llvm.di_loc<loc("file.cpp":20:0) in #di_sp_caller>
+
+llvm.func @callee_diloc() {
+  llvm.return
+} loc(#loc_callee)
+
+llvm.func @caller_diloc() {
+// CHECK: <unknown>:0: error: inlinable function call in a function with a DISubprogram location must have a debug location
+  llvm.call @callee_diloc() : () -> () loc(#loc_unknown)
+  llvm.return
+} loc(#loc_caller)
diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll
index 3c2691217e0bf..f582d267cf8b8 100644
--- a/mlir/test/Target/LLVMIR/Import/debug-info.ll
+++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll
@@ -32,11 +32,11 @@ define i32 @instruction_loc(i32 %arg1) {
 ; CHECK-DAG: #[[RAW_FILE_LOC:.+]] = loc("debug-info.ll":1:2)
 ; CHECK-DAG: #[[SP:.+]] =  #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, name = "instruction_loc"
 ; CHECK-DAG: #[[CALLEE:.+]] =  #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, name = "callee"
-; CHECK-DAG: #[[FILE_LOC]] = loc(fused<#[[SP]]>[#[[RAW_FILE_LOC]]])
+; CHECK-DAG: #[[FILE_LOC]] = #llvm.di_loc<#[[RAW_FILE_LOC]] in #[[SP]]>
 ; CHECK-DAG: #[[RAW_CALLEE_LOC:.+]] = loc("debug-info.ll":7:4)
-; CHECK-DAG: #[[CALLEE_LOC:.+]] = loc(fused<#[[CALLEE]]>[#[[RAW_CALLEE_LOC]]])
+; CHECK-DAG: #[[CALLEE_LOC:.+]] = #llvm.di_loc<#[[RAW_CALLEE_LOC]] in #[[CALLEE]]>
 ; CHECK-DAG: #[[RAW_CALLER_LOC:.+]] = loc("debug-info.ll":2:2)
-; CHECK-DAG: #[[CALLER_LOC:.+]] = loc(fused<#[[SP]]>[#[[RAW_CALLER_LOC]]])
+; CHECK-DAG: #[[CALLER_LOC:.+]] = #llvm.di_loc<#[[RAW_CALLER_LOC]] in #[[SP]]>
 ; CHECK-DAG: #[[CALLSITE_LOC:.+]] = loc(callsite(#[[CALLEE_LOC]] at #[[CALLER_LOC]]))
 
 !llvm.dbg.cu = !{!1}
@@ -66,8 +66,8 @@ define i32 @lexical_block(i32 %arg1) {
 ; CHECK: #[[SP:.+]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit =
 ; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block<scope = #[[SP]]>
 ; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block<scope = #[[SP]], file = #[[FILE]], line = 2, column = 2>
-; CHECK: #[[LOC0]] = loc(fused<#[[LB0]]>[{{.*}}])
-; CHECK: #[[LOC1]] = loc(fused<#[[LB1]]>[{{.*}}])
+; CHECK: #[[LOC0]] = #llvm.di_loc<{{.*}} in #[[LB0]]>
+; CHECK: #[[LOC1]] = #llvm.di_loc<{{.*}} in #[[LB1]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -96,8 +96,8 @@ define i32 @lexical_block_file(i32 %arg1) {
 ; CHECK: #[[SP:.+]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit =
 ; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], discriminator = 0>
 ; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], file = #[[FILE]], discriminator = 0>
-; CHECK: #[[LOC0]] = loc(fused<#[[LB0]]>[
-; CHECK: #[[LOC1]] = loc(fused<#[[LB1]]>[
+; CHECK: #[[LOC0]] = #llvm.di_loc<{{.*}} in #[[LB0]]>
+; CHECK: #[[LOC1]] = #llvm.di_loc<{{.*}} in #[[LB1]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -245,8 +245,7 @@ define void @func_loc() !dbg !3 {
 }
 ; CHECK-DAG: #[[FILE_LOC:.+]] = loc("debug-info.ll":42:0)
 ; CHECK-DAG: #[[SP:.+]] =  #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, name = "func_loc", file = #{{.*}}, line = 42, subprogramFlags = Definition>
-
-; CHECK: loc(fused<#[[SP]]>[#[[FILE_LOC]]]
+; CHECK-DAG: #{{.+}} = #llvm.di_loc<#[[FILE_LOC]] in #[[SP]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -287,8 +286,8 @@ define void @intrinsic(i64 %0, ptr %1) {
   ret void
 }
 
-; CHECK: #[[LOC1]] = loc(fused<#[[$SP]]>[{{.*}}])
-; CHECK: #[[LOC0]] = loc(fused<#[[$SP]]>[{{.*}}])
+; CHECK: #[[LOC1]] = #llvm.di_loc<{{.*}} in #[[$SP]]>
+; CHECK: #[[LOC0]] = #llvm.di_loc<{{.*}} in #[[$SP]]>
 
 declare void @llvm.dbg.value(metadata, metadata, metadata)
 declare void @llvm.dbg.declare(metadata, metadata, metadata)
@@ -322,7 +321,7 @@ define void @class_method() {
 ; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[COMP]], sizeInBits = 64, flags = "Artificial|ObjectPointer">
 ; CHECK-DAG: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type<types = #{{.*}}, #[[COMP_PTR]]>
 ; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<recId = [[REC_ID]], id = [[SP_ID:.+]], compileUnit = #{{.*}}, scope = #[[COMP]], name = "class_method", file = #{{.*}}, subprogramFlags = Definition, type = #[[SP_TYPE]]>
-; CHECK-DAG: #[[LOC]] = loc(fused<#[[SP]]>
+; CHECK-DAG: #[[LOC]] = #llvm.di_loc<{{.*}} in #[[SP]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -552,7 +551,7 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
 ; // -----
 
 ; CHECK: #[[SUBPROGRAM:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, file = #{{.*}}, subprogramFlags = Definition>
-; CHECK: #[[FUNC_LOC:.*]] = loc(fused<#[[SUBPROGRAM]]>[{{.*}}])
+; CHECK: #[[FUNC_LOC:.*]] = #llvm.di_loc<{{.*}} in #[[SUBPROGRAM]]>
 define void @noname_subprogram(ptr %arg) !dbg !8 {
   ret void
 }
@@ -618,7 +617,8 @@ declare !dbg !1 void @declaration()
 ; CHECK: #[[SP:.+]] = #llvm.di_subprogram<
 ; CHECK-NOT: id = distinct
 ; CHECK-NOT: subprogramFlags =
-; CHECK: loc(fused<#[[SP]]>
+; CHECK-SAME: >
+; CHECK: #{{.+}} = #llvm.di_loc<{{.*}} in #[[SP]]>
 
 !llvm.module.flags = !{!0}
 !0 = !{i32 2, !"Debug Info Version", i32 3}

>From 4274bf0b7477362a696df09b070e7e15c1fea6fa Mon Sep 17 00:00:00 2001
From: Alexander Yermolovich <ayermolovich at nvidia.com>
Date: Thu, 12 Mar 2026 23:10:12 +0000
Subject: [PATCH 2/4] addressed comments

---
 mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td |  6 ++++--
 .../LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp   | 16 +++++++++-------
 .../LLVMIR/Transforms/InlinerInterfaceImpl.cpp   |  4 ++--
 mlir/lib/Target/LLVMIR/DebugImporter.cpp         | 13 ++++++-------
 mlir/lib/Target/LLVMIR/DebugTranslation.cpp      | 10 +++++-----
 5 files changed, 26 insertions(+), 23 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index ccf7bef462786..a7d3a404d383c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -649,8 +649,10 @@ def LLVM_DILexicalBlockFile : LLVM_Attr<"DILexicalBlockFile", "di_lexical_block_
 def LLVM_DILocAttr : LocationAttrDef<LLVM_Dialect, "DILoc"> {
   let description = [{
     Represents a debug location combining a source position and a debug info
-    scope. Replaces the convention-based FusedLoc encoding for instruction-level
-    and function-level debug locations.
+    scope for instruction-level and function-level debug locations.
+
+    Note: Older code represented this with a FusedLoc carrying the debug
+    scope as its metadata and a convention on how to interpret it.
   }];
   let mnemonic = "di_loc";
 
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
index cb4cb7cab52a4..bd092b0a6650b 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
@@ -49,7 +49,7 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
                                LLVM::DICompileUnitAttr compileUnitAttr) {
 
   Location loc = llvmFunc.getLoc();
-  if (auto diLoc = loc->findInstanceOf<LLVM::DILocAttr>())
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(loc))
     if (isa<LLVM::DISubprogramAttr>(diLoc.getScope()))
       return;
   if (loc->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>())
@@ -94,7 +94,7 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
       /*retainedNodes=*/{}, /*annotations=*/{});
   FileLineColLoc fileLoc = extractFileLoc(loc);
   if (!fileLoc)
-    fileLoc = FileLineColLoc::get(context, "<unknown>", line, /*column=*/0);
+    fileLoc = FileLineColLoc::get(context, "", line, /*column=*/0);
   llvmFunc->setLoc(LLVM::DILocAttr::get(fileLoc, subprogramAttr));
 }
 
@@ -106,6 +106,8 @@ static Location getNestedLoc(Operation *op, LLVM::DIScopeAttr scopeAttr,
                              Location calleeLoc) {
   FileLineColLoc calleeFileLoc = extractFileLoc(calleeLoc);
   auto *context = op->getContext();
+  if (!calleeFileLoc)
+    calleeFileLoc = FileLineColLoc::get(context, "", 0, 0);
   StringAttr calleeFileName = calleeFileLoc.getFilename();
   LLVM::DIFileAttr calleeFileAttr =
       LLVM::DIFileAttr::get(context, llvm::sys::path::filename(calleeFileName),
@@ -129,8 +131,8 @@ static void setLexicalBlockFileAttr(Operation *op) {
 
   // Extract the subprogram scope from the function's location.
   LLVM::DISubprogramAttr scopeAttr;
-  if (auto diLoc = funcOp.getLoc()->findInstanceOf<LLVM::DILocAttr>()) {
-    scopeAttr = dyn_cast<LLVM::DISubprogramAttr>(diLoc.getScope());
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(funcOp.getLoc())) {
+    scopeAttr = dyn_cast_if_present<LLVM::DISubprogramAttr>(diLoc.getScope());
   } else if (auto funcOpLoc =
                  llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
     scopeAttr = dyn_cast<LLVM::DISubprogramAttr>(funcOpLoc.getMetadata());
@@ -139,9 +141,9 @@ static void setLexicalBlockFileAttr(Operation *op) {
     return;
 
   if (auto callSiteLoc = dyn_cast<CallSiteLoc>(opLoc)) {
-    op->setLoc(CallSiteLoc::get(
-        getNestedLoc(op, scopeAttr, callSiteLoc.getCallee()),
-        callSiteLoc.getCaller()));
+    op->setLoc(
+        CallSiteLoc::get(getNestedLoc(op, scopeAttr, callSiteLoc.getCallee()),
+                         callSiteLoc.getCaller()));
     return;
   }
 
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
index 0b2dbc3a707f7..edebd536638c7 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
@@ -492,8 +492,8 @@ handleLoopAnnotations(Operation *call,
   if (!func)
     return;
   LLVM::DISubprogramAttr scope;
-  if (auto diLoc = func->getLoc()->findInstanceOf<LLVM::DILocAttr>())
-    scope = dyn_cast<LLVM::DISubprogramAttr>(diLoc.getScope());
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(func->getLoc()))
+    scope = dyn_cast_if_present<LLVM::DISubprogramAttr>(diLoc.getScope());
   else if (auto fusedLoc = dyn_cast_if_present<FusedLoc>(func->getLoc()))
     scope = dyn_cast_if_present<LLVM::DISubprogramAttr>(fusedLoc.getMetadata());
   if (!scope)
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
index 2fe5f8a0a2b5b..b97ef9f19659f 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -36,8 +36,7 @@ Location DebugImporter::translateFuncLocation(llvm::Function *func) {
   StringAttr fileName = StringAttr::get(context, subprogram->getFilename());
   auto fileLoc =
       FileLineColLoc::get(fileName, subprogram->getLine(), /*column=*/0);
-  auto scope =
-      dyn_cast_or_null<DILocalScopeAttr>(translate(subprogram));
+  auto scope = dyn_cast_if_present<DILocalScopeAttr>(translate(subprogram));
   // DILocAttr requires a non-null DILocalScopeAttr, but
   // translateImpl(DISubprogram*) can return null when the subprogram's parent
   // scope or subroutine type cannot be translated. Preserve the file location
@@ -475,16 +474,16 @@ Location DebugImporter::translateLoc(llvm::DILocation *loc) {
     return UnknownLoc::get(context);
 
   auto fileLoc = FileLineColLoc::get(context, loc->getFilename(),
-                                    loc->getLine(), loc->getColumn());
+                                     loc->getLine(), loc->getColumn());
   auto scope =
-      dyn_cast_or_null<DILocalScopeAttr>(translate(loc->getScope()));
+      dyn_cast_if_present<DILocalScopeAttr>(translate(loc->getScope()));
   // DILocAttr requires a non-null DILocalScopeAttr. When the scope cannot
   // be translated, preserve the file location for diagnostics.
-  Location result = scope
-      ? Location(DILocAttr::get(fileLoc, scope))
-      : Location(fileLoc);
+  Location result =
+      scope ? Location(DILocAttr::get(fileLoc, scope)) : Location(fileLoc);
   if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
     result = CallSiteLoc::get(result, translateLoc(inlinedAt));
+
   return result;
 }
 
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index 52e322f2bf9e6..ef16e2602da2e 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -63,8 +63,8 @@ void DebugTranslation::translate(LLVMFuncOp func, llvm::Function &llvmFunc) {
 
   // Look for a subprogram: check DILocAttr first, fall back to FusedLoc.
   LLVM::DISubprogramAttr sp;
-  if (auto diLoc = func.getLoc()->findInstanceOf<LLVM::DILocAttr>()) {
-    sp = dyn_cast<LLVM::DISubprogramAttr>(diLoc.getScope());
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(func.getLoc())) {
+    sp = dyn_cast_if_present<LLVM::DISubprogramAttr>(diLoc.getScope());
   } else if (auto spLoc =
                  func.getLoc()
                      ->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>()) {
@@ -556,9 +556,9 @@ llvm::DILocation *DebugTranslation::translateLoc(Location loc,
       return nullptr;
 
     auto sourceLoc = diLoc.getSourceLoc();
-    llvmLoc = llvm::DILocation::get(
-        llvmCtx, sourceLoc.getLine(), sourceLoc.getColumn(), diScope,
-        const_cast<llvm::DILocation *>(inlinedAt));
+    llvmLoc = llvm::DILocation::get(llvmCtx, sourceLoc.getLine(),
+                                    sourceLoc.getColumn(), diScope,
+                                    const_cast<llvm::DILocation *>(inlinedAt));
 
   } else if (auto fileLoc = dyn_cast<FileLineColLoc>(loc)) {
     // A scope of a DILocation cannot be null.

>From 25787dc78d5494cd13e57824fb79675c311008ca Mon Sep 17 00:00:00 2001
From: Alexander Yermolovich <ayermolovich at nvidia.com>
Date: Thu, 12 Mar 2026 23:51:57 +0000
Subject: [PATCH 3/4] fix build issue

---
 .../lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
index bd092b0a6650b..ef2337eee36a2 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
@@ -47,11 +47,12 @@ static FileLineColLoc extractFileLoc(Location loc) {
 /// subprogram.
 static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
                                LLVM::DICompileUnitAttr compileUnitAttr) {
-
-  Location loc = llvmFunc.getLoc();
-  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(loc))
+  // Use getLoc() directly so the result is an rvalue; ValueIsPresent<Location>
+  // lacks unwrapValue, so dyn_cast_if_present fails on lvalue Locations.
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(llvmFunc.getLoc()))
     if (isa<LLVM::DISubprogramAttr>(diLoc.getScope()))
       return;
+  Location loc = llvmFunc.getLoc();
   if (loc->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>())
     return;
 

>From e665b23be3a5fa5c0210dc13670652a2c3fcdebb Mon Sep 17 00:00:00 2001
From: Alexander Yermolovich <ayermolovich at nvidia.com>
Date: Sun, 15 Mar 2026 21:17:43 +0000
Subject: [PATCH 4/4] Changed to DILocationAttr

---
 .../mlir/Dialect/LLVMIR/LLVMAttrDefs.td       |  8 +++---
 .../Dialect/LLVMIR/LLVMDialectBytecode.td     |  6 ++---
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    |  2 +-
 .../Transforms/DIScopeForLLVMFuncOp.cpp       | 14 +++++-----
 .../Transforms/InlinerInterfaceImpl.cpp       |  2 +-
 mlir/lib/Target/LLVMIR/DebugImporter.cpp      |  8 +++---
 mlir/lib/Target/LLVMIR/DebugTranslation.cpp   |  8 +++---
 .../LLVMIR/LLVMToLLVMIRTranslation.cpp        |  2 +-
 .../Target/LLVMIR/LoopAnnotationImporter.cpp  | 10 +++----
 .../LLVMIR/add-debuginfo-func-scope.mlir      |  4 +--
 mlir/test/Dialect/LLVMIR/diloc-attr.mlir      | 12 ++++-----
 .../Dialect/LLVMIR/invalid-call-location.mlir |  6 ++---
 mlir/test/Target/LLVMIR/Import/debug-info.ll  | 26 +++++++++----------
 13 files changed, 54 insertions(+), 54 deletions(-)

diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
index a7d3a404d383c..6a8188f731436 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMAttrDefs.td
@@ -643,18 +643,18 @@ def LLVM_DILexicalBlockFile : LLVM_Attr<"DILexicalBlockFile", "di_lexical_block_
 }
 
 //===----------------------------------------------------------------------===//
-// DILocAttr
+// DILocationAttr
 //===----------------------------------------------------------------------===//
 
-def LLVM_DILocAttr : LocationAttrDef<LLVM_Dialect, "DILoc"> {
+def LLVM_DILocationAttr : LocationAttrDef<LLVM_Dialect, "DILocation"> {
   let description = [{
     Represents a debug location combining a source position and a debug info
     scope for instruction-level and function-level debug locations.
 
-    Note: Older code represented this with a FusedLoc carrying the debug
+    Note: Older code represents this with a FusedLoc carrying the debug
     scope as its metadata and a convention on how to interpret it.
   }];
-  let mnemonic = "di_loc";
+  let mnemonic = "di_location";
 
   let parameters = (ins
     "FileLineColLoc":$sourceLoc,
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
index 3da283778d1ff..051f1eebda418 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMDialectBytecode.td
@@ -276,10 +276,10 @@ def DILexicalBlockFileAttr : DialectAttribute<(attr
 )>;
 
 //===----------------------------------------------------------------------===//
-// DILocAttr
+// DILocationAttr
 //===----------------------------------------------------------------------===//
 
-def DILocAttr : DialectAttribute<(attr
+def DILocationAttr : DialectAttribute<(attr
   Attr<"FileLineColLoc">:$sourceLoc,
   Attr<"DILocalScopeAttr">:$scope
 )>;
@@ -347,7 +347,7 @@ def LLVMDialectAttributes : DialectAttributes<"LLVM"> {
     DILabelAttr,
     DILexicalBlockAttr,
     DILexicalBlockFileAttr,
-    DILocAttr,
+    DILocationAttr,
     DILocalVariableAttr,
     DINamespaceAttr,
     DISubprogramAttr,
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 70709ea2f477c..ec03940626abe 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -1142,7 +1142,7 @@ static LogicalResult verifyCallOpDebugInfo(CallOp callOp, LLVMFuncOp callee) {
     return success();
 
   auto hasSubprogram = [](Operation *op) {
-    if (auto diLoc = op->getLoc()->findInstanceOf<LLVM::DILocAttr>())
+    if (auto diLoc = op->getLoc()->findInstanceOf<LLVM::DILocationAttr>())
       return isa<LLVM::DISubprogramAttr>(diLoc.getScope());
     return op->getLoc()
                ->findInstanceOf<FusedLocWith<LLVM::DISubprogramAttr>>() !=
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
index ef2337eee36a2..261b5eb23e241 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/DIScopeForLLVMFuncOp.cpp
@@ -25,7 +25,7 @@ using namespace mlir;
 static FileLineColLoc extractFileLoc(Location loc) {
   if (auto fileLoc = dyn_cast<FileLineColLoc>(loc))
     return fileLoc;
-  if (auto diLoc = dyn_cast<LLVM::DILocAttr>(loc))
+  if (auto diLoc = dyn_cast<LLVM::DILocationAttr>(loc))
     return diLoc.getSourceLoc();
   if (auto nameLoc = dyn_cast<NameLoc>(loc))
     return extractFileLoc(nameLoc.getChildLoc());
@@ -49,7 +49,7 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
                                LLVM::DICompileUnitAttr compileUnitAttr) {
   // Use getLoc() directly so the result is an rvalue; ValueIsPresent<Location>
   // lacks unwrapValue, so dyn_cast_if_present fails on lvalue Locations.
-  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(llvmFunc.getLoc()))
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocationAttr>(llvmFunc.getLoc()))
     if (isa<LLVM::DISubprogramAttr>(diLoc.getScope()))
       return;
   Location loc = llvmFunc.getLoc();
@@ -96,10 +96,10 @@ static void addScopeToFunction(LLVM::LLVMFuncOp llvmFunc,
   FileLineColLoc fileLoc = extractFileLoc(loc);
   if (!fileLoc)
     fileLoc = FileLineColLoc::get(context, "", line, /*column=*/0);
-  llvmFunc->setLoc(LLVM::DILocAttr::get(fileLoc, subprogramAttr));
+  llvmFunc->setLoc(LLVM::DILocationAttr::get(fileLoc, subprogramAttr));
 }
 
-// Build a DILocAttr for an inlined callee. Each recursion level creates a
+// Build a DILocationAttr for an inlined callee. Each recursion level creates a
 // DILexicalBlockFileAttr whose scope chains back through the caller scopes
 // to the enclosing subprogram. The scope nesting is carried by the
 // DILexicalBlockFileAttr hierarchy, not by nesting locations.
@@ -118,7 +118,7 @@ static Location getNestedLoc(Operation *op, LLVM::DIScopeAttr scopeAttr,
   // Recurse if the callee location is again a call site.
   if (auto callSiteLoc = dyn_cast<CallSiteLoc>(calleeLoc))
     return getNestedLoc(op, lexicalBlockFileAttr, callSiteLoc.getCallee());
-  return LLVM::DILocAttr::get(calleeFileLoc, lexicalBlockFileAttr);
+  return LLVM::DILocationAttr::get(calleeFileLoc, lexicalBlockFileAttr);
 }
 
 /// Adds DILexicalBlockFileAttr for operations with CallSiteLoc and operations
@@ -132,7 +132,7 @@ static void setLexicalBlockFileAttr(Operation *op) {
 
   // Extract the subprogram scope from the function's location.
   LLVM::DISubprogramAttr scopeAttr;
-  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(funcOp.getLoc())) {
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocationAttr>(funcOp.getLoc())) {
     scopeAttr = dyn_cast_if_present<LLVM::DISubprogramAttr>(diLoc.getScope());
   } else if (auto funcOpLoc =
                  llvm::dyn_cast_if_present<FusedLoc>(funcOp.getLoc())) {
@@ -170,7 +170,7 @@ static void setLexicalBlockFileAttr(Operation *op) {
     auto lexicalBlockFileAttr =
         LLVM::DILexicalBlockFileAttr::get(context, scopeAttr, opFileAttr, 0);
 
-    op->setLoc(LLVM::DILocAttr::get(opFileLoc, lexicalBlockFileAttr));
+    op->setLoc(LLVM::DILocationAttr::get(opFileLoc, lexicalBlockFileAttr));
   }
 }
 
diff --git a/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp b/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
index edebd536638c7..47a15ec968c96 100644
--- a/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
+++ b/mlir/lib/Dialect/LLVMIR/Transforms/InlinerInterfaceImpl.cpp
@@ -492,7 +492,7 @@ handleLoopAnnotations(Operation *call,
   if (!func)
     return;
   LLVM::DISubprogramAttr scope;
-  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(func->getLoc()))
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocationAttr>(func->getLoc()))
     scope = dyn_cast_if_present<LLVM::DISubprogramAttr>(diLoc.getScope());
   else if (auto fusedLoc = dyn_cast_if_present<FusedLoc>(func->getLoc()))
     scope = dyn_cast_if_present<LLVM::DISubprogramAttr>(fusedLoc.getMetadata());
diff --git a/mlir/lib/Target/LLVMIR/DebugImporter.cpp b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
index b97ef9f19659f..b059453737dc4 100644
--- a/mlir/lib/Target/LLVMIR/DebugImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugImporter.cpp
@@ -37,7 +37,7 @@ Location DebugImporter::translateFuncLocation(llvm::Function *func) {
   auto fileLoc =
       FileLineColLoc::get(fileName, subprogram->getLine(), /*column=*/0);
   auto scope = dyn_cast_if_present<DILocalScopeAttr>(translate(subprogram));
-  // DILocAttr requires a non-null DILocalScopeAttr, but
+  // DILocationAttr requires a non-null DILocalScopeAttr, but
   // translateImpl(DISubprogram*) can return null when the subprogram's parent
   // scope or subroutine type cannot be translated. Preserve the file location
   // so diagnostics still have source info. This also matches the original
@@ -45,7 +45,7 @@ Location DebugImporter::translateFuncLocation(llvm::Function *func) {
   // location to fail FusedLocWith<DISubprogramAttr> classof checks anyway.
   if (!scope)
     return fileLoc;
-  return DILocAttr::get(fileLoc, scope);
+  return DILocationAttr::get(fileLoc, scope);
 }
 
 //===----------------------------------------------------------------------===//
@@ -477,10 +477,10 @@ Location DebugImporter::translateLoc(llvm::DILocation *loc) {
                                      loc->getLine(), loc->getColumn());
   auto scope =
       dyn_cast_if_present<DILocalScopeAttr>(translate(loc->getScope()));
-  // DILocAttr requires a non-null DILocalScopeAttr. When the scope cannot
+  // DILocationAttr requires a non-null DILocalScopeAttr. When the scope cannot
   // be translated, preserve the file location for diagnostics.
   Location result =
-      scope ? Location(DILocAttr::get(fileLoc, scope)) : Location(fileLoc);
+      scope ? Location(DILocationAttr::get(fileLoc, scope)) : Location(fileLoc);
   if (llvm::DILocation *inlinedAt = loc->getInlinedAt())
     result = CallSiteLoc::get(result, translateLoc(inlinedAt));
 
diff --git a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
index ef16e2602da2e..4068e025903ed 100644
--- a/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/DebugTranslation.cpp
@@ -61,9 +61,9 @@ void DebugTranslation::translate(LLVMFuncOp func, llvm::Function &llvmFunc) {
   if (!debugEmissionIsEnabled)
     return;
 
-  // Look for a subprogram: check DILocAttr first, fall back to FusedLoc.
+  // Look for a subprogram: check DILocationAttr first, fall back to FusedLoc.
   LLVM::DISubprogramAttr sp;
-  if (auto diLoc = dyn_cast_if_present<LLVM::DILocAttr>(func.getLoc())) {
+  if (auto diLoc = dyn_cast_if_present<LLVM::DILocationAttr>(func.getLoc())) {
     sp = dyn_cast_if_present<LLVM::DISubprogramAttr>(diLoc.getScope());
   } else if (auto spLoc =
                  func.getLoc()
@@ -549,8 +549,8 @@ llvm::DILocation *DebugTranslation::translateLoc(Location loc,
     if (!llvmLoc)
       llvmLoc = callerLoc;
 
-  } else if (auto diLoc = dyn_cast<LLVM::DILocAttr>(loc)) {
-    // Translate the scope from the DILocAttr.
+  } else if (auto diLoc = dyn_cast<LLVM::DILocationAttr>(loc)) {
+    // Translate the scope from the DILocationAttr.
     llvm::DILocalScope *diScope = translate(diLoc.getScope());
     if (!diScope)
       return nullptr;
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 10d611dfee3a9..cc2b9676512c1 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -364,7 +364,7 @@ static void convertModuleFlagsOp(ArrayAttr flags, llvm::IRBuilderBase &builder,
 static llvm::DILocalScope *
 getLocalScopeFromLoc(llvm::IRBuilderBase &builder, Location loc,
                      LLVM::ModuleTranslation &moduleTranslation) {
-  if (auto diLoc = loc->findInstanceOf<LLVM::DILocAttr>())
+  if (auto diLoc = loc->findInstanceOf<LLVM::DILocationAttr>())
     if (auto *localScope = llvm::dyn_cast<llvm::DILocalScope>(
             moduleTranslation.translateDebugInfo(diLoc.getScope())))
       return localScope;
diff --git a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
index 7546bb09d1348..1c966c7600bb5 100644
--- a/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
+++ b/mlir/lib/Target/LLVMIR/LoopAnnotationImporter.cpp
@@ -411,16 +411,16 @@ LoopMetadataConversion::convertParallelAccesses() {
 }
 
 /// Convert a translated location to a FusedLoc for loop annotation storage.
-/// translateLoc produces DILocAttr, but LoopAnnotationAttr stores locations as
-/// FusedLoc<scope>[raw_loc]. Extract the source location and scope from the
-/// DILocAttr to build the FusedLoc directly, matching the format expected by
-/// LoopAnnotationTranslation on the export side.
+/// translateLoc produces DILocationAttr, but LoopAnnotationAttr stores
+/// locations as FusedLoc<scope>[raw_loc]. Extract the source location and scope
+/// from the DILocationAttr to build the FusedLoc directly, matching the format
+/// expected by LoopAnnotationTranslation on the export side.
 static FusedLoc toFusedLoc(Location loc) {
   if (auto fused = dyn_cast<FusedLoc>(loc))
     return fused;
   if (isa<UnknownLoc>(loc))
     return {};
-  if (auto diLoc = dyn_cast<LLVM::DILocAttr>(loc))
+  if (auto diLoc = dyn_cast<LLVM::DILocationAttr>(loc))
     return dyn_cast<FusedLoc>(FusedLoc::get(
         {diLoc.getSourceLoc()}, diLoc.getScope(), loc.getContext()));
   return {};
diff --git a/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir b/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir
index 30fc670846851..517aa6da169ee 100644
--- a/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir
+++ b/mlir/test/Dialect/LLVMIR/add-debuginfo-func-scope.mlir
@@ -6,7 +6,7 @@
 // CHECK: loc(#loc[[LOC:[0-9]+]])
 // CHECK: #di_file = #llvm.di_file<"<unknown>" in "">
 // CHECK: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #di_file, name = "func_no_debug", linkageName = "func_no_debug", file = #di_file, line = 1, scopeLine = 1, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
-// CHECK: #loc[[LOC]] = #llvm.di_loc<{{.*}} in #di_subprogram>
+// CHECK: #loc[[LOC]] = #llvm.di_location<{{.*}} in #di_subprogram>
 module {
   llvm.func @func_no_debug() {
     llvm.return loc(unknown)
@@ -59,7 +59,7 @@ module {
 // CHECK-DAG: #di_compile_unit = #llvm.di_compile_unit<id = distinct[{{.*}}]<>, sourceLanguage = DW_LANG_C, file = #[[DI_FILE_MODULE]], producer = "MLIR", isOptimized = true, emissionKind = LineTablesOnly>
 // CHECK-DAG: #di_subprogram = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #di_compile_unit, scope = #[[DI_FILE_FUNC]], name = "propagate_compile_unit", linkageName = "propagate_compile_unit", file = #[[DI_FILE_FUNC]], line = 9, scopeLine = 9, subprogramFlags = "Definition|Optimized", type = #di_subroutine_type>
 // CHECK-DAG: #loc[[MODULELOC]] = loc(fused<#di_compile_unit>[#loc])
-// CHECK-DAG: #loc[[FUNCLOC]] = #llvm.di_loc<#loc[[FUNCFILELOC]] in #di_subprogram>
+// CHECK-DAG: #loc[[FUNCLOC]] = #llvm.di_location<#loc[[FUNCFILELOC]] in #di_subprogram>
 module {
   llvm.func @propagate_compile_unit() {
     llvm.return loc(unknown)
diff --git a/mlir/test/Dialect/LLVMIR/diloc-attr.mlir b/mlir/test/Dialect/LLVMIR/diloc-attr.mlir
index 85abbb7783efb..e0d04eff29154 100644
--- a/mlir/test/Dialect/LLVMIR/diloc-attr.mlir
+++ b/mlir/test/Dialect/LLVMIR/diloc-attr.mlir
@@ -1,16 +1,16 @@
 // RUN: mlir-opt %s --mlir-print-debuginfo | FileCheck %s
 //
-// Basic parse/print test for DILocAttr (no snapshots).
-// Uses a single source file and exercises two DILocAttr locations (module and function).
+// Basic parse/print test for DILocationAttr (no snapshots).
+// Uses a single source file and exercises two DILocationAttr locations (module and function).
 
 #di_file = #llvm.di_file<"source.c" in "/">
 #di_compile_unit = #llvm.di_compile_unit<id = distinct[0]<>, sourceLanguage = DW_LANG_C, file = #di_file, isOptimized = false, emissionKind = None>
 #di_subprogram = #llvm.di_subprogram<compileUnit = #di_compile_unit, scope = #di_file, name = "test", file = #di_file, subprogramFlags = Definition>
 
-// CHECK-DAG: #llvm.di_loc<{{.*}} in #di_subprogram>
-// CHECK-DAG: #llvm.di_loc<{{.*}} in #di_subprogram>
-#loc_at_module = #llvm.di_loc<loc("source.c":1:1) in #di_subprogram>
-#loc_at_func = #llvm.di_loc<loc("source.c":10:2) in #di_subprogram>
+// CHECK-DAG: #llvm.di_location<{{.*}} in #di_subprogram>
+// CHECK-DAG: #llvm.di_location<{{.*}} in #di_subprogram>
+#loc_at_module = #llvm.di_location<loc("source.c":1:1) in #di_subprogram>
+#loc_at_func = #llvm.di_location<loc("source.c":10:2) in #di_subprogram>
 
 module {
   llvm.func @f() {} loc(#loc_at_func)
diff --git a/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir b/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir
index 0272292874cdd..9cd12242afbd1 100644
--- a/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid-call-location.mlir
@@ -36,7 +36,7 @@ llvm.func @invalid_call_debug_locs() {
 
 // -----
 
-// Test the DILocAttr path of hasSubprogram.
+// Test the DILocationAttr path of hasSubprogram.
 
 #di_file2 = #llvm.di_file<"file.cpp" in "/folder/">
 #di_compile_unit2 = #llvm.di_compile_unit<
@@ -54,8 +54,8 @@ llvm.func @invalid_call_debug_locs() {
   subprogramFlags = "Definition|Optimized"
 >
 #loc_unknown = loc(unknown)
-#loc_callee = #llvm.di_loc<loc("file.cpp":10:0) in #di_sp_callee>
-#loc_caller = #llvm.di_loc<loc("file.cpp":20:0) in #di_sp_caller>
+#loc_callee = #llvm.di_location<loc("file.cpp":10:0) in #di_sp_callee>
+#loc_caller = #llvm.di_location<loc("file.cpp":20:0) in #di_sp_caller>
 
 llvm.func @callee_diloc() {
   llvm.return
diff --git a/mlir/test/Target/LLVMIR/Import/debug-info.ll b/mlir/test/Target/LLVMIR/Import/debug-info.ll
index f582d267cf8b8..88faf5aa9c08f 100644
--- a/mlir/test/Target/LLVMIR/Import/debug-info.ll
+++ b/mlir/test/Target/LLVMIR/Import/debug-info.ll
@@ -32,11 +32,11 @@ define i32 @instruction_loc(i32 %arg1) {
 ; CHECK-DAG: #[[RAW_FILE_LOC:.+]] = loc("debug-info.ll":1:2)
 ; CHECK-DAG: #[[SP:.+]] =  #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, name = "instruction_loc"
 ; CHECK-DAG: #[[CALLEE:.+]] =  #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, name = "callee"
-; CHECK-DAG: #[[FILE_LOC]] = #llvm.di_loc<#[[RAW_FILE_LOC]] in #[[SP]]>
+; CHECK-DAG: #[[FILE_LOC]] = #llvm.di_location<#[[RAW_FILE_LOC]] in #[[SP]]>
 ; CHECK-DAG: #[[RAW_CALLEE_LOC:.+]] = loc("debug-info.ll":7:4)
-; CHECK-DAG: #[[CALLEE_LOC:.+]] = #llvm.di_loc<#[[RAW_CALLEE_LOC]] in #[[CALLEE]]>
+; CHECK-DAG: #[[CALLEE_LOC:.+]] = #llvm.di_location<#[[RAW_CALLEE_LOC]] in #[[CALLEE]]>
 ; CHECK-DAG: #[[RAW_CALLER_LOC:.+]] = loc("debug-info.ll":2:2)
-; CHECK-DAG: #[[CALLER_LOC:.+]] = #llvm.di_loc<#[[RAW_CALLER_LOC]] in #[[SP]]>
+; CHECK-DAG: #[[CALLER_LOC:.+]] = #llvm.di_location<#[[RAW_CALLER_LOC]] in #[[SP]]>
 ; CHECK-DAG: #[[CALLSITE_LOC:.+]] = loc(callsite(#[[CALLEE_LOC]] at #[[CALLER_LOC]]))
 
 !llvm.dbg.cu = !{!1}
@@ -66,8 +66,8 @@ define i32 @lexical_block(i32 %arg1) {
 ; CHECK: #[[SP:.+]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit =
 ; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block<scope = #[[SP]]>
 ; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block<scope = #[[SP]], file = #[[FILE]], line = 2, column = 2>
-; CHECK: #[[LOC0]] = #llvm.di_loc<{{.*}} in #[[LB0]]>
-; CHECK: #[[LOC1]] = #llvm.di_loc<{{.*}} in #[[LB1]]>
+; CHECK: #[[LOC0]] = #llvm.di_location<{{.*}} in #[[LB0]]>
+; CHECK: #[[LOC1]] = #llvm.di_location<{{.*}} in #[[LB1]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -96,8 +96,8 @@ define i32 @lexical_block_file(i32 %arg1) {
 ; CHECK: #[[SP:.+]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit =
 ; CHECK: #[[LB0:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], discriminator = 0>
 ; CHECK: #[[LB1:.+]] = #llvm.di_lexical_block_file<scope = #[[SP]], file = #[[FILE]], discriminator = 0>
-; CHECK: #[[LOC0]] = #llvm.di_loc<{{.*}} in #[[LB0]]>
-; CHECK: #[[LOC1]] = #llvm.di_loc<{{.*}} in #[[LB1]]>
+; CHECK: #[[LOC0]] = #llvm.di_location<{{.*}} in #[[LB0]]>
+; CHECK: #[[LOC1]] = #llvm.di_location<{{.*}} in #[[LB1]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -245,7 +245,7 @@ define void @func_loc() !dbg !3 {
 }
 ; CHECK-DAG: #[[FILE_LOC:.+]] = loc("debug-info.ll":42:0)
 ; CHECK-DAG: #[[SP:.+]] =  #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, name = "func_loc", file = #{{.*}}, line = 42, subprogramFlags = Definition>
-; CHECK-DAG: #{{.+}} = #llvm.di_loc<#[[FILE_LOC]] in #[[SP]]>
+; CHECK-DAG: #{{.+}} = #llvm.di_location<#[[FILE_LOC]] in #[[SP]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -286,8 +286,8 @@ define void @intrinsic(i64 %0, ptr %1) {
   ret void
 }
 
-; CHECK: #[[LOC1]] = #llvm.di_loc<{{.*}} in #[[$SP]]>
-; CHECK: #[[LOC0]] = #llvm.di_loc<{{.*}} in #[[$SP]]>
+; CHECK: #[[LOC1]] = #llvm.di_location<{{.*}} in #[[$SP]]>
+; CHECK: #[[LOC0]] = #llvm.di_location<{{.*}} in #[[$SP]]>
 
 declare void @llvm.dbg.value(metadata, metadata, metadata)
 declare void @llvm.dbg.declare(metadata, metadata, metadata)
@@ -321,7 +321,7 @@ define void @class_method() {
 ; CHECK-DAG: #[[COMP_PTR:.+]] = #llvm.di_derived_type<tag = DW_TAG_pointer_type, baseType = #[[COMP]], sizeInBits = 64, flags = "Artificial|ObjectPointer">
 ; CHECK-DAG: #[[SP_TYPE:.+]] = #llvm.di_subroutine_type<types = #{{.*}}, #[[COMP_PTR]]>
 ; CHECK-DAG: #[[SP:.+]] = #llvm.di_subprogram<recId = [[REC_ID]], id = [[SP_ID:.+]], compileUnit = #{{.*}}, scope = #[[COMP]], name = "class_method", file = #{{.*}}, subprogramFlags = Definition, type = #[[SP_TYPE]]>
-; CHECK-DAG: #[[LOC]] = #llvm.di_loc<{{.*}} in #[[SP]]>
+; CHECK-DAG: #[[LOC]] = #llvm.di_location<{{.*}} in #[[SP]]>
 
 !llvm.dbg.cu = !{!1}
 !llvm.module.flags = !{!0}
@@ -551,7 +551,7 @@ declare void @llvm.dbg.value(metadata, metadata, metadata)
 ; // -----
 
 ; CHECK: #[[SUBPROGRAM:.*]] = #llvm.di_subprogram<id = distinct[{{.*}}]<>, compileUnit = #{{.*}}, scope = #{{.*}}, file = #{{.*}}, subprogramFlags = Definition>
-; CHECK: #[[FUNC_LOC:.*]] = #llvm.di_loc<{{.*}} in #[[SUBPROGRAM]]>
+; CHECK: #[[FUNC_LOC:.*]] = #llvm.di_location<{{.*}} in #[[SUBPROGRAM]]>
 define void @noname_subprogram(ptr %arg) !dbg !8 {
   ret void
 }
@@ -618,7 +618,7 @@ declare !dbg !1 void @declaration()
 ; CHECK-NOT: id = distinct
 ; CHECK-NOT: subprogramFlags =
 ; CHECK-SAME: >
-; CHECK: #{{.+}} = #llvm.di_loc<{{.*}} in #[[SP]]>
+; CHECK: #{{.+}} = #llvm.di_location<{{.*}} in #[[SP]]>
 
 !llvm.module.flags = !{!0}
 !0 = !{i32 2, !"Debug Info Version", i32 3}



More information about the Mlir-commits mailing list