[llvm] [DebugInfo] getMergedLocation: match scopes based on their location (PR #132286)

Vladislav Dzhidzhoev via llvm-commits llvm-commits at lists.llvm.org
Mon Apr 7 06:41:20 PDT 2025


https://github.com/dzhidzhoev updated https://github.com/llvm/llvm-project/pull/132286

>From 5b6c19b743a59479b5a0d6e4554a4fb3476ab2d8 Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Sun, 16 Mar 2025 21:49:21 +0100
Subject: [PATCH 1/7] [DebugInfo] getMergedLocation: match scopes based on
 their location

GetNearestCommonScope finds a common scope for two locations by finding
the common parent scope object.

With this commit, GetNearestCommonScope considers two scopes equal if
they have the same file, line and column values. Thus, it can find
the "nearest common included location" when merging locations from
different files. This may be useful for a case described here
https://github.com/llvm/llvm-project/pull/125780#issuecomment-2651657856.

DIScope's pointer equality isn't enough for scope equality check, since, for
example, two `#include "x.inc"` directives showing up on different lines
produce different DILocalScope objects representing the same file content.
Thus, two (even same) locations from "x.inc" may have different
parent scope objects representing the same source location.

If input DILocations are from different files, or common scope is in
another file than input locations, a textual inclusion case is assumed,
and the location of common scope ("nearest common included location") is
returned as a result of getMergedLocation.
It fixes https://github.com/llvm/llvm-project/issues/122846.
---
 llvm/lib/IR/DebugInfoMetadata.cpp             |  72 +++++-
 .../AArch64/merge-nested-block-loc.ll         | 194 +++++++++++++++
 .../AArch64/merge-nested-block-loc2.ll        | 229 ++++++++++++++++++
 llvm/unittests/IR/MetadataTest.cpp            | 211 +++++++++++++++-
 4 files changed, 691 insertions(+), 15 deletions(-)
 create mode 100644 llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
 create mode 100644 llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll

diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 12aba7d2bd123..f64de47c6f51a 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -13,7 +13,7 @@
 #include "llvm/IR/DebugInfoMetadata.h"
 #include "LLVMContextImpl.h"
 #include "MetadataImpl.h"
-#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/StringSwitch.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/IR/DebugProgramInstruction.h"
@@ -125,6 +125,22 @@ DILocation *DILocation::getMergedLocations(ArrayRef<DILocation *> Locs) {
   return Merged;
 }
 
+using LineColumn = std::pair<unsigned /* Line */, unsigned /* Column */>;
+
+/// Returns the location of DILocalScope, if present, or a default value.
+static LineColumn getLocalScopeLocationOr(DIScope *S, LineColumn Default) {
+  assert(isa<DILocalScope>(S) && "Expected DILocalScope.");
+
+  if (isa<DILexicalBlockFile>(S))
+    return Default;
+  if (auto *LB = dyn_cast<DILexicalBlock>(S))
+    return {LB->getLine(), LB->getColumn()};
+  if (auto *SP = dyn_cast<DISubprogram>(S))
+    return {SP->getLine(), 0u};
+
+  llvm_unreachable("Unhandled type of DILocalScope.");
+}
+
 DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
   if (!LocA || !LocB)
     return nullptr;
@@ -209,27 +225,67 @@ DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
       return nullptr;
 
     // Return the nearest common scope inside a subprogram.
-    auto GetNearestCommonScope = [](DIScope *S1, DIScope *S2) -> DIScope * {
-      SmallPtrSet<DIScope *, 8> Scopes;
+    auto GetNearestCommonScope =
+        [](const DILocation *L1,
+           const DILocation *L2) -> std::pair<DIScope *, LineColumn> {
+      DIScope *S1 = L1->getScope();
+      DIScope *S2 = L2->getScope();
+
+      SmallMapVector<std::tuple<DIFile *, LineColumn>,
+                     SmallSetVector<DIScope *, 8>, 8>
+          Scopes;
+
+      // When matching DILexicalBlockFile's, ignore column numbers, so that
+      // DILocation's having different columns within the same
+      // DILexicalBlockFile will match.
+      auto getLocForBlockFile = [](LineColumn L) {
+        L.second = 0;
+        return L;
+      };
+
+      LineColumn Loc1(L1->getLine(), L1->getColumn());
       for (; S1; S1 = S1->getScope()) {
-        Scopes.insert(S1);
+        Loc1 = getLocalScopeLocationOr(S1, getLocForBlockFile(Loc1));
+        Scopes[{S1->getFile(), Loc1}].insert(S1);
+
         if (isa<DISubprogram>(S1))
           break;
       }
 
+      LineColumn Loc2(L2->getLine(), L2->getColumn());
       for (; S2; S2 = S2->getScope()) {
-        if (Scopes.count(S2))
-          return S2;
+        Loc2 = getLocalScopeLocationOr(S2, getLocForBlockFile(Loc2));
+
+        auto ScopesAtLoc = Scopes.find({S2->getFile(), Loc2});
+        // No scope found with the same file, line and column as S2.
+        if (ScopesAtLoc == Scopes.end())
+          continue;
+
+        // Return S2 if it is L1's parent.
+        if (ScopesAtLoc->second.contains(S2))
+          return std::make_pair(S2, Loc2);
+
+        // Return any L1's parent with the same file, line and column as S2.
+        if (!ScopesAtLoc->second.empty())
+          return std::make_pair(*ScopesAtLoc->second.begin(), Loc2);
+
         if (isa<DISubprogram>(S2))
           break;
       }
 
-      return nullptr;
+      return std::make_pair(nullptr,
+                            LineColumn(L2->getLine(), L2->getColumn()));
     };
 
-    auto Scope = GetNearestCommonScope(L1->getScope(), L2->getScope());
+    auto [Scope, ScopeLoc] = GetNearestCommonScope(L1, L2);
     assert(Scope && "No common scope in the same subprogram?");
 
+    // Use inclusion location if files are different.
+    if (Scope->getFile() != L1->getFile() || L1->getFile() != L2->getFile()) {
+      return DILocation::get(C, ScopeLoc.first, ScopeLoc.second, Scope,
+                             InlinedAt);
+    }
+
     bool SameLine = L1->getLine() == L2->getLine();
     bool SameCol = L1->getColumn() == L2->getColumn();
     unsigned Line = SameLine ? L1->getLine() : 0;
diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
new file mode 100644
index 0000000000000..7fa0024847283
--- /dev/null
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
@@ -0,0 +1,194 @@
+; RUN: opt -mtriple=aarch64-unknown-linux-gnu -S %s -passes=sroa -o - | FileCheck %s
+
+; In this test we want to ensure that the location of phi instruction merged from locations
+; of %mul3 and %mul9 belongs to the correct scope (DILexicalBlockFile), so that line
+; number of that location belongs to the corresponding file.
+
+; Generated with clang from
+; # 1 "1.c" 1
+; # 1 "1.c" 2
+; int foo(int a) {
+;   int i = 0;
+;   if ((a & 1) == 1) {
+;     a -= 1;
+; # 1 "m.c" 1
+; # 40 "m.c"
+; i += a;
+; i -= 10*a;
+; i *= a*a;
+; # 6 "1.c" 2
+;  } else {
+;     a += 3;
+; # 1 "m.c" 1
+; # 40 "m.c"
+; i += a;
+; i -= 10*a;
+; i *= a*a;
+; # 9 "1.c" 2
+;  }
+;   return i;
+; }
+
+source_filename = "repro.c"
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "aarch64-unknown-linux-gnu"
+
+; Function Attrs: nounwind uwtable
+define dso_local i32 @foo(i32 noundef %a) !dbg !9 {
+; CHECK:    phi i32 {{.*}}, !dbg [[PHILOC:![0-9]+]]
+;
+entry:
+  %a.addr = alloca i32, align 4, !DIAssignID !17
+  #dbg_assign(i1 undef, !15, !DIExpression(), !17, ptr %a.addr, !DIExpression(), !18)
+  %i = alloca i32, align 4, !DIAssignID !19
+  #dbg_assign(i1 undef, !16, !DIExpression(), !19, ptr %i, !DIExpression(), !18)
+  store i32 %a, ptr %a.addr, align 4, !tbaa !20, !DIAssignID !24
+  #dbg_assign(i32 %a, !15, !DIExpression(), !24, ptr %a.addr, !DIExpression(), !18)
+  call void @llvm.lifetime.start.p0(i64 4, ptr %i), !dbg !25
+  store i32 0, ptr %i, align 4, !dbg !26, !tbaa !20, !DIAssignID !27
+  #dbg_assign(i32 0, !16, !DIExpression(), !27, ptr %i, !DIExpression(), !18)
+  %0 = load i32, ptr %a.addr, align 4, !dbg !28, !tbaa !20
+  %and = and i32 %0, 1, !dbg !30
+  %cmp = icmp eq i32 %and, 1, !dbg !31
+  br i1 %cmp, label %if.then, label %if.else, !dbg !31
+
+if.then:                                          ; preds = %entry
+  %1 = load i32, ptr %a.addr, align 4, !dbg !32, !tbaa !20
+  %sub = sub nsw i32 %1, 1, !dbg !32
+  store i32 %sub, ptr %a.addr, align 4, !dbg !32, !tbaa !20, !DIAssignID !34
+  #dbg_assign(i32 %sub, !15, !DIExpression(), !34, ptr %a.addr, !DIExpression(), !18)
+  %2 = load i32, ptr %a.addr, align 4, !dbg !35, !tbaa !20
+  %3 = load i32, ptr %i, align 4, !dbg !38, !tbaa !20
+  %add = add nsw i32 %3, %2, !dbg !38
+  store i32 %add, ptr %i, align 4, !dbg !38, !tbaa !20, !DIAssignID !39
+  #dbg_assign(i32 %add, !16, !DIExpression(), !39, ptr %i, !DIExpression(), !18)
+  %4 = load i32, ptr %a.addr, align 4, !dbg !40, !tbaa !20
+  %mul = mul nsw i32 10, %4, !dbg !41
+  %5 = load i32, ptr %i, align 4, !dbg !42, !tbaa !20
+  %sub1 = sub nsw i32 %5, %mul, !dbg !42
+  store i32 %sub1, ptr %i, align 4, !dbg !42, !tbaa !20, !DIAssignID !43
+  #dbg_assign(i32 %sub1, !16, !DIExpression(), !43, ptr %i, !DIExpression(), !18)
+  %6 = load i32, ptr %a.addr, align 4, !dbg !44, !tbaa !20
+  %7 = load i32, ptr %a.addr, align 4, !dbg !45, !tbaa !20
+  %mul2 = mul nsw i32 %6, %7, !dbg !46
+  %8 = load i32, ptr %i, align 4, !dbg !47, !tbaa !20
+  %mul3 = mul nsw i32 %8, %mul2, !dbg !47
+  store i32 %mul3, ptr %i, align 4, !dbg !47, !tbaa !20, !DIAssignID !48
+  #dbg_assign(i32 %mul3, !16, !DIExpression(), !48, ptr %i, !DIExpression(), !18)
+  br label %if.end, !dbg !49
+
+if.else:                                          ; preds = %entry
+  %9 = load i32, ptr %a.addr, align 4, !dbg !51, !tbaa !20
+  %add4 = add nsw i32 %9, 3, !dbg !51
+  store i32 %add4, ptr %a.addr, align 4, !dbg !51, !tbaa !20, !DIAssignID !53
+  #dbg_assign(i32 %add4, !15, !DIExpression(), !53, ptr %a.addr, !DIExpression(), !18)
+  %10 = load i32, ptr %a.addr, align 4, !dbg !54, !tbaa !20
+  %11 = load i32, ptr %i, align 4, !dbg !56, !tbaa !20
+  %add5 = add nsw i32 %11, %10, !dbg !56
+  store i32 %add5, ptr %i, align 4, !dbg !56, !tbaa !20, !DIAssignID !57
+  #dbg_assign(i32 %add5, !16, !DIExpression(), !57, ptr %i, !DIExpression(), !18)
+  %12 = load i32, ptr %a.addr, align 4, !dbg !58, !tbaa !20
+  %mul6 = mul nsw i32 10, %12, !dbg !59
+  %13 = load i32, ptr %i, align 4, !dbg !60, !tbaa !20
+  %sub7 = sub nsw i32 %13, %mul6, !dbg !60
+  store i32 %sub7, ptr %i, align 4, !dbg !60, !tbaa !20, !DIAssignID !61
+  #dbg_assign(i32 %sub7, !16, !DIExpression(), !61, ptr %i, !DIExpression(), !18)
+  %14 = load i32, ptr %a.addr, align 4, !dbg !62, !tbaa !20
+  %15 = load i32, ptr %a.addr, align 4, !dbg !63, !tbaa !20
+  %mul8 = mul nsw i32 %14, %15, !dbg !64
+  %16 = load i32, ptr %i, align 4, !dbg !65, !tbaa !20
+  %mul9 = mul nsw i32 %16, %mul8, !dbg !65
+  store i32 %mul9, ptr %i, align 4, !dbg !65, !tbaa !20, !DIAssignID !66
+  #dbg_assign(i32 %mul9, !16, !DIExpression(), !66, ptr %i, !DIExpression(), !18)
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  %17 = load i32, ptr %i, align 4, !dbg !67, !tbaa !20
+  call void @llvm.lifetime.end.p0(i64 4, ptr %i), !dbg !68
+  ret i32 %17, !dbg !69
+}
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
+
+; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "repro.c", directory: "")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{!"clang version 21.0.0git"}
+!9 = distinct !DISubprogram(name: "foo", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14)
+!10 = !DIFile(filename: "1.c", directory: "")
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{!15, !16}
+!15 = !DILocalVariable(name: "a", arg: 1, scope: !9, file: !10, line: 1, type: !13)
+!16 = !DILocalVariable(name: "i", scope: !9, file: !10, line: 2, type: !13)
+!17 = distinct !DIAssignID()
+!18 = !DILocation(line: 0, scope: !9)
+!19 = distinct !DIAssignID()
+!20 = !{!21, !21, i64 0}
+!21 = !{!"int", !22, i64 0}
+!22 = !{!"omnipotent char", !23, i64 0}
+!23 = !{!"Simple C/C++ TBAA"}
+!24 = distinct !DIAssignID()
+!25 = !DILocation(line: 2, column: 3, scope: !9)
+!26 = !DILocation(line: 2, column: 7, scope: !9)
+!27 = distinct !DIAssignID()
+!28 = !DILocation(line: 3, column: 8, scope: !29)
+!29 = distinct !DILexicalBlock(scope: !9, file: !10, line: 3, column: 7)
+!30 = !DILocation(line: 3, column: 10, scope: !29)
+!31 = !DILocation(line: 3, column: 15, scope: !29)
+!32 = !DILocation(line: 4, column: 7, scope: !33)
+!33 = distinct !DILexicalBlock(scope: !29, file: !10, line: 3, column: 21)
+!34 = distinct !DIAssignID()
+!35 = !DILocation(line: 40, column: 6, scope: !36)
+!36 = !DILexicalBlockFile(scope: !33, file: !37, discriminator: 0)
+!37 = !DIFile(filename: "m.c", directory: "")
+!38 = !DILocation(line: 40, column: 3, scope: !36)
+!39 = distinct !DIAssignID()
+!40 = !DILocation(line: 41, column: 9, scope: !36)
+!41 = !DILocation(line: 41, column: 8, scope: !36)
+!42 = !DILocation(line: 41, column: 3, scope: !36)
+!43 = distinct !DIAssignID()
+!44 = !DILocation(line: 42, column: 6, scope: !36)
+!45 = !DILocation(line: 42, column: 8, scope: !36)
+!46 = !DILocation(line: 42, column: 7, scope: !36)
+!47 = !DILocation(line: 42, column: 3, scope: !36)
+!48 = distinct !DIAssignID()
+!49 = !DILocation(line: 6, column: 2, scope: !50)
+!50 = !DILexicalBlockFile(scope: !33, file: !10, discriminator: 0)
+!51 = !DILocation(line: 7, column: 7, scope: !52)
+!52 = distinct !DILexicalBlock(scope: !29, file: !10, line: 6, column: 9)
+!53 = distinct !DIAssignID()
+!54 = !DILocation(line: 40, column: 6, scope: !55)
+!55 = !DILexicalBlockFile(scope: !52, file: !37, discriminator: 0)
+!56 = !DILocation(line: 40, column: 3, scope: !55)
+!57 = distinct !DIAssignID()
+!58 = !DILocation(line: 41, column: 9, scope: !55)
+!59 = !DILocation(line: 41, column: 8, scope: !55)
+!60 = !DILocation(line: 41, column: 3, scope: !55)
+!61 = distinct !DIAssignID()
+!62 = !DILocation(line: 42, column: 6, scope: !55)
+!63 = !DILocation(line: 42, column: 8, scope: !55)
+!64 = !DILocation(line: 42, column: 7, scope: !55)
+!65 = !DILocation(line: 42, column: 3, scope: !55)
+!66 = distinct !DIAssignID()
+!67 = !DILocation(line: 10, column: 10, scope: !9)
+!68 = !DILocation(line: 11, column: 1, scope: !9)
+!69 = !DILocation(line: 10, column: 3, scope: !9)
+
+; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE1:![0-9]+]], file: [[FILE1]], line: 1
+; CHECK: [[FILE1]] = !DIFile(filename: "1.c", directory: "")
+; CHECK: [[LB1:![0-9]+]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE1]], line: 3, column: 7)
+; CHECK: [[LB2:![0-9]+]] = distinct !DILexicalBlock(scope: [[LB1]], file: [[FILE1]], line: 3, column: 21)
+; CHECK: [[LBF:![0-9]+]] = !DILexicalBlockFile(scope: [[LB2]], file: [[FILE2:![0-9]+]], discriminator: 0)
+; CHECK: [[FILE2]] = !DIFile(filename: "m.c", directory: "")
+; CHECK: [[PHILOC]] = !DILocation(line: 42, column: 3, scope: [[LBF]])
diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
new file mode 100644
index 0000000000000..dd52bf7907a76
--- /dev/null
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
@@ -0,0 +1,229 @@
+; RUN: opt -mtriple=aarch64-unknown-linux-gnu -S %s -passes=sroa -o - | FileCheck %s
+
+; In this test we want to ensure that getMergedLocations uses common include
+; location if incoming locations belong to different files.
+; The location of phi instruction merged from locations of %mul3 and %mul10
+; should be the location of do-loop lexical block from y.c.
+
+; Generated with clang from
+;
+; main.c:
+;   int foo(int a) {
+;     int i = 0;
+;     if ((a & 1) == 1) {
+;       a -= 1;
+;   #define A
+;   #include "y.c"
+;    } else {
+;       a += 3;
+;   #undef A
+;   #include "y.c"
+;    }
+;     return i;
+;   }
+;
+; y.c:
+;   # 300 "y.c" 1
+;   do {
+;   #ifdef A
+;   #include "z1.c"
+;   #else
+;   #include "z2.c"
+;   #endif
+;   } while (0);
+;
+; z1.c:
+;   # 100 "z1.c" 1
+;   i += a;
+;   i -= 10*a;
+;   i *= a*a;
+;
+; z2.c:
+;   # 200 "z1.c" 1
+;   i += a;
+;   i -= 10*a;
+;   i *= a*a;
+;
+; Preprocessed source:
+;
+; # 1 "main.c"
+; int foo(int a) {
+;   int i = 0;
+;   if ((a & 1) == 1) {
+;     a -= 1;
+; # 300 "y.c" 1
+; do {
+; # 100 "z1.c" 1
+; i += a;
+; i -= 10*a;
+; i *= a*a;
+; # 303 "y.c" 2
+; } while (0);
+; # 7 "main.c" 2
+;  } else {
+;     a += 3;
+; # 300 "y.c" 1
+; do {
+; # 200 "z2.c" 1
+; i += a;
+; i -= 10*a;
+; i *= a*a;
+; # 305 "y.c" 2
+; } while (0);
+; # 11 "main.c" 2
+;  }
+;   return i;
+; }
+
+source_filename = "main.preproc.c"
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
+target triple = "arm64-apple-macosx15.0.0"
+
+; Function Attrs: noinline nounwind ssp uwtable(sync)
+define i32 @foo(i32 noundef %a) !dbg !9 {
+; CHECK:    phi i32 {{.*}}, !dbg [[PHILOC:![0-9]+]]
+;
+entry:
+  %a.addr = alloca i32, align 4
+  %i = alloca i32, align 4
+  store i32 %a, ptr %a.addr, align 4
+    #dbg_declare(ptr %a.addr, !15, !DIExpression(), !16)
+    #dbg_declare(ptr %i, !17, !DIExpression(), !18)
+  store i32 0, ptr %i, align 4, !dbg !18
+  %0 = load i32, ptr %a.addr, align 4, !dbg !19
+  %and = and i32 %0, 1, !dbg !21
+  %cmp = icmp eq i32 %and, 1, !dbg !22
+  br i1 %cmp, label %if.then, label %if.else, !dbg !22
+
+if.then:                                          ; preds = %entry
+  %1 = load i32, ptr %a.addr, align 4, !dbg !23
+  %sub = sub nsw i32 %1, 1, !dbg !23
+  store i32 %sub, ptr %a.addr, align 4, !dbg !23
+  br label %do.body, !dbg !25
+
+do.body:                                          ; preds = %if.then
+  %2 = load i32, ptr %a.addr, align 4, !dbg !28
+  %3 = load i32, ptr %i, align 4, !dbg !32
+  %add = add nsw i32 %3, %2, !dbg !32
+  store i32 %add, ptr %i, align 4, !dbg !32
+  %4 = load i32, ptr %a.addr, align 4, !dbg !33
+  %mul = mul nsw i32 10, %4, !dbg !34
+  %5 = load i32, ptr %i, align 4, !dbg !35
+  %sub1 = sub nsw i32 %5, %mul, !dbg !35
+  store i32 %sub1, ptr %i, align 4, !dbg !35
+  %6 = load i32, ptr %a.addr, align 4, !dbg !36
+  %7 = load i32, ptr %a.addr, align 4, !dbg !37
+  %mul2 = mul nsw i32 %6, %7, !dbg !38
+  %8 = load i32, ptr %i, align 4, !dbg !39
+  %mul3 = mul nsw i32 %8, %mul2, !dbg !39
+  store i32 %mul3, ptr %i, align 4, !dbg !39
+  br label %do.end, !dbg !40
+
+do.end:                                           ; preds = %do.body
+  br label %if.end, !dbg !42
+
+if.else:                                          ; preds = %entry
+  %9 = load i32, ptr %a.addr, align 4, !dbg !44
+  %add4 = add nsw i32 %9, 3, !dbg !44
+  store i32 %add4, ptr %a.addr, align 4, !dbg !44
+  br label %do.body5, !dbg !46
+
+do.body5:                                         ; preds = %if.else
+  %10 = load i32, ptr %a.addr, align 4, !dbg !48
+  %11 = load i32, ptr %i, align 4, !dbg !52
+  %add6 = add nsw i32 %11, %10, !dbg !52
+  store i32 %add6, ptr %i, align 4, !dbg !52
+  %12 = load i32, ptr %a.addr, align 4, !dbg !53
+  %mul7 = mul nsw i32 10, %12, !dbg !54
+  %13 = load i32, ptr %i, align 4, !dbg !55
+  %sub8 = sub nsw i32 %13, %mul7, !dbg !55
+  store i32 %sub8, ptr %i, align 4, !dbg !55
+  %14 = load i32, ptr %a.addr, align 4, !dbg !56
+  %15 = load i32, ptr %a.addr, align 4, !dbg !57
+  %mul9 = mul nsw i32 %14, %15, !dbg !58
+  %16 = load i32, ptr %i, align 4, !dbg !59
+  %mul10 = mul nsw i32 %16, %mul9, !dbg !59
+  store i32 %mul10, ptr %i, align 4, !dbg !59
+  br label %do.end11, !dbg !60
+
+do.end11:                                         ; preds = %do.body5
+  br label %if.end
+
+if.end:                                           ; preds = %do.end11, %do.end
+  %17 = load i32, ptr %i, align 4, !dbg !62
+  ret i32 %17, !dbg !63
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!2, !3}
+!llvm.ident = !{!8}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
+!1 = !DIFile(filename: "main.preproc.c", directory: "")
+!2 = !{i32 7, !"Dwarf Version", i32 5}
+!3 = !{i32 2, !"Debug Info Version", i32 3}
+!8 = !{!"clang version 21.0.0git"}
+!9 = distinct !DISubprogram(name: "foo", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
+!10 = !DIFile(filename: "main.c", directory: "")
+!11 = !DISubroutineType(types: !12)
+!12 = !{!13, !13}
+!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!14 = !{}
+!15 = !DILocalVariable(name: "a", arg: 1, scope: !9, file: !10, line: 1, type: !13)
+!16 = !DILocation(line: 1, column: 13, scope: !9)
+!17 = !DILocalVariable(name: "i", scope: !9, file: !10, line: 2, type: !13)
+!18 = !DILocation(line: 2, column: 7, scope: !9)
+!19 = !DILocation(line: 3, column: 8, scope: !20)
+!20 = distinct !DILexicalBlock(scope: !9, file: !10, line: 3, column: 7)
+!21 = !DILocation(line: 3, column: 10, scope: !20)
+!22 = !DILocation(line: 3, column: 15, scope: !20)
+!23 = !DILocation(line: 4, column: 7, scope: !24)
+!24 = distinct !DILexicalBlock(scope: !20, file: !10, line: 3, column: 21)
+!25 = !DILocation(line: 300, column: 1, scope: !26)
+!26 = !DILexicalBlockFile(scope: !24, file: !27, discriminator: 0)
+!27 = !DIFile(filename: "y.c", directory: "")
+!28 = !DILocation(line: 100, column: 6, scope: !29)
+!29 = !DILexicalBlockFile(scope: !31, file: !30, discriminator: 0)
+!30 = !DIFile(filename: "z1.c", directory: "")
+!31 = distinct !DILexicalBlock(scope: !26, file: !27, line: 300, column: 4)
+!32 = !DILocation(line: 100, column: 3, scope: !29)
+!33 = !DILocation(line: 101, column: 9, scope: !29)
+!34 = !DILocation(line: 101, column: 8, scope: !29)
+!35 = !DILocation(line: 101, column: 3, scope: !29)
+!36 = !DILocation(line: 102, column: 6, scope: !29)
+!37 = !DILocation(line: 102, column: 8, scope: !29)
+!38 = !DILocation(line: 102, column: 7, scope: !29)
+!39 = !DILocation(line: 102, column: 3, scope: !29)
+!40 = !DILocation(line: 303, column: 1, scope: !41)
+!41 = !DILexicalBlockFile(scope: !31, file: !27, discriminator: 0)
+!42 = !DILocation(line: 7, column: 2, scope: !43)
+!43 = !DILexicalBlockFile(scope: !24, file: !10, discriminator: 0)
+!44 = !DILocation(line: 8, column: 7, scope: !45)
+!45 = distinct !DILexicalBlock(scope: !20, file: !10, line: 7, column: 9)
+!46 = !DILocation(line: 300, column: 1, scope: !47)
+!47 = !DILexicalBlockFile(scope: !45, file: !27, discriminator: 0)
+!48 = !DILocation(line: 200, column: 6, scope: !49)
+!49 = !DILexicalBlockFile(scope: !51, file: !50, discriminator: 0)
+!50 = !DIFile(filename: "z2.c", directory: "")
+!51 = distinct !DILexicalBlock(scope: !47, file: !27, line: 300, column: 4)
+!52 = !DILocation(line: 200, column: 3, scope: !49)
+!53 = !DILocation(line: 201, column: 9, scope: !49)
+!54 = !DILocation(line: 201, column: 8, scope: !49)
+!55 = !DILocation(line: 201, column: 3, scope: !49)
+!56 = !DILocation(line: 202, column: 6, scope: !49)
+!57 = !DILocation(line: 202, column: 8, scope: !49)
+!58 = !DILocation(line: 202, column: 7, scope: !49)
+!59 = !DILocation(line: 202, column: 3, scope: !49)
+!60 = !DILocation(line: 305, column: 1, scope: !61)
+!61 = !DILexicalBlockFile(scope: !51, file: !27, discriminator: 0)
+!62 = !DILocation(line: 12, column: 10, scope: !9)
+!63 = !DILocation(line: 12, column: 3, scope: !9)
+
+; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE_MAIN:![0-9]+]], file: [[FILE_MAIN]], line: 1
+; CHECK: [[FILE_MAIN]] = !DIFile(filename: "main.c"
+; CHECK: [[BLOCK1_MAIN:![0-9]+]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE_MAIN]], line: 3, column: 7)
+; CHECK: [[BLOCK2_MAIN:![0-9]+]] = distinct !DILexicalBlock(scope: [[BLOCK1_MAIN]], file: [[FILE_MAIN]], line: 3, column: 21)
+; CHECK: [[LBF1_Y:![0-9]+]] = !DILexicalBlockFile(scope: [[BLOCK2_MAIN]], file: [[FILE_Y:![0-9]+]], discriminator: 0)
+; CHECK: [[FILE_Y]] = !DIFile(filename: "y.c"
+; CHECK: [[BLOCK_Y:![0-9]+]] = distinct !DILexicalBlock(scope: [[LBF1_Y]], file: [[FILE_Y]], line: 300, column: 4)
+; CHECK: [[PHILOC]] = !DILocation(line: 300, column: 4, scope: [[BLOCK_Y]])
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index 94cebb0406598..b77475a6ea855 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -85,10 +85,10 @@ class MetadataTest : public testing::Test {
     return DISubroutineType::getDistinct(Context, DINode::FlagZero, 0,
                                          getNode(nullptr));
   }
-  DISubprogram *getSubprogram() {
-    return DISubprogram::getDistinct(
-        Context, nullptr, "", "", nullptr, 0, nullptr, 0, nullptr, 0, 0,
-        DINode::FlagZero, DISubprogram::SPFlagZero, nullptr);
+  DISubprogram *getSubprogram(DIFile *F = nullptr) {
+    return DISubprogram::getDistinct(Context, nullptr, "", "", F, 0, nullptr, 0,
+                                     nullptr, 0, 0, DINode::FlagZero,
+                                     DISubprogram::SPFlagZero, nullptr);
   }
   DIFile *getFile() {
     return DIFile::getDistinct(Context, "file.c", "/path/to/dir");
@@ -919,8 +919,9 @@ TEST_F(MDNodeTest, deleteTemporaryWithTrackingRef) {
 typedef MetadataTest DILocationTest;
 
 TEST_F(DILocationTest, Merge) {
-  DISubprogram *N = getSubprogram();
-  DIScope *S = DILexicalBlock::get(Context, N, getFile(), 3, 4);
+  DIFile *F = getFile();
+  DISubprogram *N = getSubprogram(F);
+  DIScope *S = DILexicalBlock::get(Context, N, F, 3, 4);
 
   {
     // Identical.
@@ -932,6 +933,18 @@ TEST_F(DILocationTest, Merge) {
     EXPECT_EQ(N, M->getScope());
   }
 
+  {
+    // Identical, inside DILexicalBlockFile.
+    auto *OtherF = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    auto *LBF = DILexicalBlockFile::get(Context, S, OtherF, 0);
+    auto *A = DILocation::get(Context, 2, 7, LBF);
+    auto *B = DILocation::get(Context, 2, 7, LBF);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(2u, M->getLine());
+    EXPECT_EQ(7u, M->getColumn());
+    EXPECT_EQ(LBF, M->getScope());
+  }
+
   {
     // Identical, different scopes.
     auto *A = DILocation::get(Context, 2, 7, N);
@@ -956,7 +969,22 @@ TEST_F(DILocationTest, Merge) {
   }
 
   {
-    // Different lines, same scopes.
+    // Same line, different column, same DILexicalBlockFile scope.
+    auto *OtherF = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    auto *LBF = DILexicalBlockFile::get(Context, S, OtherF, 0);
+    auto *A = DILocation::get(Context, 2, 7, LBF);
+    auto *B = DILocation::get(Context, 2, 10, LBF);
+    auto *M0 = DILocation::getMergedLocation(A, B);
+    auto *M1 = DILocation::getMergedLocation(B, A);
+    for (auto *M : {M0, M1}) {
+      EXPECT_EQ(2u, M->getLine());
+      EXPECT_EQ(0u, M->getColumn());
+      EXPECT_EQ(LBF, M->getScope());
+    }
+  }
+
+  {
+    // Different lines, same DISubprogram scopes.
     auto *A = DILocation::get(Context, 1, 6, N);
     auto *B = DILocation::get(Context, 2, 7, N);
     auto *M = DILocation::getMergedLocation(A, B);
@@ -965,6 +993,28 @@ TEST_F(DILocationTest, Merge) {
     EXPECT_EQ(N, M->getScope());
   }
 
+  {
+    // Different lines, same DILexicalBlockFile scopes.
+    auto *OtherF = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    auto *LBF = DILexicalBlockFile::get(Context, S, OtherF, 0);
+    auto *A = DILocation::get(Context, 1, 6, LBF);
+    auto *B = DILocation::get(Context, 2, 7, LBF);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(3u, M->getLine());
+    EXPECT_EQ(4u, M->getColumn());
+    EXPECT_EQ(S, M->getScope());
+  }
+
+  {
+    // Different lines, same DILexicalBlock scopes.
+    auto *A = DILocation::get(Context, 1, 6, S);
+    auto *B = DILocation::get(Context, 2, 7, S);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(0u, M->getLine());
+    EXPECT_EQ(0u, M->getColumn());
+    EXPECT_EQ(S, M->getScope());
+  }
+
   {
     // Twisty locations, all different, same function.
     auto *A = DILocation::get(Context, 1, 6, N);
@@ -975,6 +1025,153 @@ TEST_F(DILocationTest, Merge) {
     EXPECT_EQ(N, M->getScope());
   }
 
+  {
+    // Different files, same line numbers, same subprogram.
+    auto *F1 = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    auto *F2 = DIFile::getDistinct(Context, "file2.c", "/path/to/dir");
+    DISubprogram *N = getSubprogram(F1);
+    auto *LBF = DILexicalBlockFile::get(Context, N, F2, 0);
+    auto *A = DILocation::get(Context, 1, 6, N);
+    auto *B = DILocation::get(Context, 1, 6, LBF);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(0u, M->getLine());
+    EXPECT_EQ(0u, M->getColumn());
+    EXPECT_EQ(N, M->getScope());
+  }
+
+  {
+    // Different files, same line numbers.
+    auto *F1 = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    auto *F2 = DIFile::getDistinct(Context, "file2.c", "/path/to/dir");
+    DISubprogram *N = getSubprogram(F1);
+    auto *LB = DILexicalBlock::getDistinct(Context, N, F1, 4, 9);
+    auto *LBF = DILexicalBlockFile::get(Context, LB, F2, 0);
+    auto *A = DILocation::get(Context, 1, 6, LB);
+    auto *B = DILocation::get(Context, 1, 6, LBF);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(4u, M->getLine());
+    EXPECT_EQ(9u, M->getColumn());
+    EXPECT_EQ(LB, M->getScope());
+  }
+
+  {
+    // Different files, same line numbers,
+    // both locations have DILexicalBlockFile scopes.
+    auto *F1 = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    auto *F2 = DIFile::getDistinct(Context, "file2.c", "/path/to/dir");
+    auto *F3 = DIFile::getDistinct(Context, "file3.c", "/path/to/dir");
+    DISubprogram *N = getSubprogram(F1);
+    auto *LB = DILexicalBlock::getDistinct(Context, N, F1, 4, 9);
+    auto *LBF1 = DILexicalBlockFile::get(Context, LB, F2, 0);
+    auto *LBF2 = DILexicalBlockFile::get(Context, LB, F3, 0);
+    auto *A = DILocation::get(Context, 1, 6, LBF1);
+    auto *B = DILocation::get(Context, 1, 6, LBF2);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(4u, M->getLine());
+    EXPECT_EQ(9u, M->getColumn());
+    EXPECT_EQ(LB, M->getScope());
+  }
+
+  {
+    // Same file, same line numbers, but different LBF objects.
+    // both locations have DILexicalBlockFile scope.
+    auto *F1 = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    DISubprogram *N = getSubprogram(F1);
+    auto *LB1 = DILexicalBlock::getDistinct(Context, N, F1, 4, 9);
+    auto *LB2 = DILexicalBlock::getDistinct(Context, N, F1, 5, 9);
+    auto *F2 = DIFile::getDistinct(Context, "file2.c", "/path/to/dir");
+    auto *LBF1 = DILexicalBlockFile::get(Context, LB1, F2, 0);
+    auto *LBF2 = DILexicalBlockFile::get(Context, LB2, F2, 0);
+    auto *A = DILocation::get(Context, 1, 6, LBF1);
+    auto *B = DILocation::get(Context, 1, 6, LBF2);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(1u, M->getLine());
+    EXPECT_EQ(6u, M->getColumn());
+    EXPECT_EQ(LBF1, M->getScope());
+  }
+
+  {
+    // Merge locations A and B, where B is included in A's file
+    // at the same position as A's position.
+    auto *F1 = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    DISubprogram *N = getSubprogram(F1);
+    auto *LB = DILexicalBlock::getDistinct(Context, N, F1, 4, 9);
+    auto *F2 = DIFile::getDistinct(Context, "file2.c", "/path/to/dir");
+    auto *LBF = DILexicalBlockFile::get(Context, LB, F2, 0);
+    auto *A = DILocation::get(Context, 4, 9, LB);
+    auto *B = DILocation::get(Context, 1, 6, LBF);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(4u, M->getLine());
+    EXPECT_EQ(9u, M->getColumn());
+    EXPECT_EQ(LB, M->getScope());
+  }
+
+  {
+    // Different locations from different files included from the same block.
+    auto *F1 = DIFile::getDistinct(Context, "file1.c", "/path/to/dir");
+    DISubprogram *N = getSubprogram(F1);
+
+    auto *LBCommon = DILexicalBlock::getDistinct(Context, N, F1, 4, 9);
+
+    auto *F2 = DIFile::getDistinct(Context, "file2.c", "/path/to/dir");
+    LBCommon = DILexicalBlock::getDistinct(Context, LBCommon, F2, 5, 9);
+
+    auto *F3 = DIFile::getDistinct(Context, "file3.c", "/path/to/dir");
+    auto *LB1 = DILexicalBlock::getDistinct(Context, LBCommon, F3, 6, 9);
+
+    auto *F4 = DIFile::getDistinct(Context, "file4.c", "/path/to/dir");
+    auto *LB2 = DILexicalBlock::getDistinct(Context, LBCommon, F4, 7, 9);
+
+    auto *F5 = DIFile::getDistinct(Context, "file5.c", "/path/to/dir");
+    auto *LBF1 = DILexicalBlockFile::get(Context, LB1, F5, 0);
+
+    auto *A = DILocation::get(Context, 8, 9, LB2);
+    auto *B = DILocation::get(Context, 9, 6, LBF1);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(5u, M->getLine());
+    EXPECT_EQ(9u, M->getColumn());
+    EXPECT_EQ(LBCommon, M->getScope());
+  }
+
+  {
+    // Different locations from different files having common include parent.
+    auto *LBCommon = DILexicalBlock::getDistinct(Context, N, F, 4, 1);
+
+    // Different scopes.
+    DILexicalBlock *Block[2] = {};
+    Block[0] = DILexicalBlock::get(Context, LBCommon, F, 10, 2);
+    Block[1] = DILexicalBlock::get(Context, LBCommon, F, 20, 3);
+
+    // Includes of the same file.
+    auto *F1 = DIFile::getDistinct(Context, "file1.inc", "/path/to/dir");
+    DILexicalBlock *Block1[2] = {};
+    Block1[0] = DILexicalBlock::get(
+        Context, DILexicalBlockFile::get(Context, Block[0], F1, 0), F1, 30, 4);
+    Block1[1] = DILexicalBlock::get(
+        Context, DILexicalBlockFile::get(Context, Block[1], F1, 0), F1, 30, 4);
+
+    // Different sub-includes.
+    DIFile *F2[2] = {};
+    DILexicalBlock *Block2[2] = {};
+
+    F2[0] = DIFile::getDistinct(Context, "file2_a.inc", "/path/to/dir");
+    Block2[0] = DILexicalBlock::get(
+        Context, DILexicalBlockFile::get(Context, Block1[0], F2[0], 0), F2[0],
+        40, 5);
+
+    F2[1] = DIFile::getDistinct(Context, "file2_b.inc", "/path/to/dir");
+    Block2[1] = DILexicalBlock::get(
+        Context, DILexicalBlockFile::get(Context, Block1[1], F2[1], 0), F2[1],
+        50, 6);
+
+    auto *A = DILocation::get(Context, 41, 7, Block2[0]);
+    auto *B = DILocation::get(Context, 51, 8, Block2[1]);
+    auto *M = DILocation::getMergedLocation(A, B);
+    EXPECT_EQ(30u, M->getLine());
+    EXPECT_EQ(4u, M->getColumn());
+    EXPECT_EQ(Block1[0], M->getScope());
+  }
+
   {
     // Different function, same inlined-at.
     auto *F = getFile();

>From cff1e3a23267971b2f0d91661fb8c35d23c16118 Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Fri, 21 Mar 2025 17:19:57 +0100
Subject: [PATCH 2/7] Use std::pair instead of std::tuple

---
 llvm/lib/IR/DebugInfoMetadata.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index f64de47c6f51a..2212d5626e0da 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -231,7 +231,7 @@ DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
       DIScope *S1 = L1->getScope();
       DIScope *S2 = L2->getScope();
 
-      SmallMapVector<std::tuple<DIFile *, LineColumn>,
+      SmallMapVector<std::pair<DIFile *, LineColumn>,
                      SmallSetVector<DIScope *, 8>, 8>
           Scopes;
 

>From 8db41818799748ad3245c9447c509d22f1dac32c Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Thu, 27 Mar 2025 18:40:00 +0100
Subject: [PATCH 3/7] Reduced *.ll tests.

---
 .../AArch64/merge-nested-block-loc.ll         | 175 ++++--------------
 .../AArch64/merge-nested-block-loc2.ll        | 171 ++++-------------
 2 files changed, 74 insertions(+), 272 deletions(-)

diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
index 7fa0024847283..62153663266d5 100644
--- a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
@@ -29,166 +29,65 @@
 ;   return i;
 ; }
 
-source_filename = "repro.c"
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
 target triple = "aarch64-unknown-linux-gnu"
 
-; Function Attrs: nounwind uwtable
-define dso_local i32 @foo(i32 noundef %a) !dbg !9 {
+define i32 @foo() !dbg !3 {
 ; CHECK:    phi i32 {{.*}}, !dbg [[PHILOC:![0-9]+]]
 ;
 entry:
-  %a.addr = alloca i32, align 4, !DIAssignID !17
-  #dbg_assign(i1 undef, !15, !DIExpression(), !17, ptr %a.addr, !DIExpression(), !18)
-  %i = alloca i32, align 4, !DIAssignID !19
-  #dbg_assign(i1 undef, !16, !DIExpression(), !19, ptr %i, !DIExpression(), !18)
-  store i32 %a, ptr %a.addr, align 4, !tbaa !20, !DIAssignID !24
-  #dbg_assign(i32 %a, !15, !DIExpression(), !24, ptr %a.addr, !DIExpression(), !18)
-  call void @llvm.lifetime.start.p0(i64 4, ptr %i), !dbg !25
-  store i32 0, ptr %i, align 4, !dbg !26, !tbaa !20, !DIAssignID !27
-  #dbg_assign(i32 0, !16, !DIExpression(), !27, ptr %i, !DIExpression(), !18)
-  %0 = load i32, ptr %a.addr, align 4, !dbg !28, !tbaa !20
-  %and = and i32 %0, 1, !dbg !30
-  %cmp = icmp eq i32 %and, 1, !dbg !31
-  br i1 %cmp, label %if.then, label %if.else, !dbg !31
+  %i = alloca i32, align 4
+  br i1 false, label %if.then, label %if.else
 
 if.then:                                          ; preds = %entry
-  %1 = load i32, ptr %a.addr, align 4, !dbg !32, !tbaa !20
-  %sub = sub nsw i32 %1, 1, !dbg !32
-  store i32 %sub, ptr %a.addr, align 4, !dbg !32, !tbaa !20, !DIAssignID !34
-  #dbg_assign(i32 %sub, !15, !DIExpression(), !34, ptr %a.addr, !DIExpression(), !18)
-  %2 = load i32, ptr %a.addr, align 4, !dbg !35, !tbaa !20
-  %3 = load i32, ptr %i, align 4, !dbg !38, !tbaa !20
-  %add = add nsw i32 %3, %2, !dbg !38
-  store i32 %add, ptr %i, align 4, !dbg !38, !tbaa !20, !DIAssignID !39
-  #dbg_assign(i32 %add, !16, !DIExpression(), !39, ptr %i, !DIExpression(), !18)
-  %4 = load i32, ptr %a.addr, align 4, !dbg !40, !tbaa !20
-  %mul = mul nsw i32 10, %4, !dbg !41
-  %5 = load i32, ptr %i, align 4, !dbg !42, !tbaa !20
-  %sub1 = sub nsw i32 %5, %mul, !dbg !42
-  store i32 %sub1, ptr %i, align 4, !dbg !42, !tbaa !20, !DIAssignID !43
-  #dbg_assign(i32 %sub1, !16, !DIExpression(), !43, ptr %i, !DIExpression(), !18)
-  %6 = load i32, ptr %a.addr, align 4, !dbg !44, !tbaa !20
-  %7 = load i32, ptr %a.addr, align 4, !dbg !45, !tbaa !20
-  %mul2 = mul nsw i32 %6, %7, !dbg !46
-  %8 = load i32, ptr %i, align 4, !dbg !47, !tbaa !20
-  %mul3 = mul nsw i32 %8, %mul2, !dbg !47
-  store i32 %mul3, ptr %i, align 4, !dbg !47, !tbaa !20, !DIAssignID !48
-  #dbg_assign(i32 %mul3, !16, !DIExpression(), !48, ptr %i, !DIExpression(), !18)
-  br label %if.end, !dbg !49
+  %mul3 = mul i32 0, 0, !dbg !14
+  store i32 %mul3, ptr %i, align 4, !dbg !14
+  br label %if.end
 
 if.else:                                          ; preds = %entry
-  %9 = load i32, ptr %a.addr, align 4, !dbg !51, !tbaa !20
-  %add4 = add nsw i32 %9, 3, !dbg !51
-  store i32 %add4, ptr %a.addr, align 4, !dbg !51, !tbaa !20, !DIAssignID !53
-  #dbg_assign(i32 %add4, !15, !DIExpression(), !53, ptr %a.addr, !DIExpression(), !18)
-  %10 = load i32, ptr %a.addr, align 4, !dbg !54, !tbaa !20
-  %11 = load i32, ptr %i, align 4, !dbg !56, !tbaa !20
-  %add5 = add nsw i32 %11, %10, !dbg !56
-  store i32 %add5, ptr %i, align 4, !dbg !56, !tbaa !20, !DIAssignID !57
-  #dbg_assign(i32 %add5, !16, !DIExpression(), !57, ptr %i, !DIExpression(), !18)
-  %12 = load i32, ptr %a.addr, align 4, !dbg !58, !tbaa !20
-  %mul6 = mul nsw i32 10, %12, !dbg !59
-  %13 = load i32, ptr %i, align 4, !dbg !60, !tbaa !20
-  %sub7 = sub nsw i32 %13, %mul6, !dbg !60
-  store i32 %sub7, ptr %i, align 4, !dbg !60, !tbaa !20, !DIAssignID !61
-  #dbg_assign(i32 %sub7, !16, !DIExpression(), !61, ptr %i, !DIExpression(), !18)
-  %14 = load i32, ptr %a.addr, align 4, !dbg !62, !tbaa !20
-  %15 = load i32, ptr %a.addr, align 4, !dbg !63, !tbaa !20
-  %mul8 = mul nsw i32 %14, %15, !dbg !64
-  %16 = load i32, ptr %i, align 4, !dbg !65, !tbaa !20
-  %mul9 = mul nsw i32 %16, %mul8, !dbg !65
-  store i32 %mul9, ptr %i, align 4, !dbg !65, !tbaa !20, !DIAssignID !66
-  #dbg_assign(i32 %mul9, !16, !DIExpression(), !66, ptr %i, !DIExpression(), !18)
+  %mul9 = mul i32 0, 0, !dbg !15
+  store i32 %mul9, ptr %i, align 4, !dbg !15
   br label %if.end
 
 if.end:                                           ; preds = %if.else, %if.then
-  %17 = load i32, ptr %i, align 4, !dbg !67, !tbaa !20
-  call void @llvm.lifetime.end.p0(i64 4, ptr %i), !dbg !68
-  ret i32 %17, !dbg !69
+  %0 = load i32, ptr %i, align 4
+  ret i32 0
 }
 
-; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
-declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0
+
+; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
+declare void @llvm.lifetime.end.p0(i64 immarg, ptr captures(none)) #0
 
-; Function Attrs: mustprogress nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
-declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
+attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
 
 !llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!2, !3}
-!llvm.ident = !{!8}
+!llvm.module.flags = !{!2}
 
 !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None)
 !1 = !DIFile(filename: "repro.c", directory: "")
-!2 = !{i32 7, !"Dwarf Version", i32 5}
-!3 = !{i32 2, !"Debug Info Version", i32 3}
-!8 = !{!"clang version 21.0.0git"}
-!9 = distinct !DISubprogram(name: "foo", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !14)
-!10 = !DIFile(filename: "1.c", directory: "")
-!11 = !DISubroutineType(types: !12)
-!12 = !{!13, !13}
-!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!14 = !{!15, !16}
-!15 = !DILocalVariable(name: "a", arg: 1, scope: !9, file: !10, line: 1, type: !13)
-!16 = !DILocalVariable(name: "i", scope: !9, file: !10, line: 2, type: !13)
-!17 = distinct !DIAssignID()
-!18 = !DILocation(line: 0, scope: !9)
-!19 = distinct !DIAssignID()
-!20 = !{!21, !21, i64 0}
-!21 = !{!"int", !22, i64 0}
-!22 = !{!"omnipotent char", !23, i64 0}
-!23 = !{!"Simple C/C++ TBAA"}
-!24 = distinct !DIAssignID()
-!25 = !DILocation(line: 2, column: 3, scope: !9)
-!26 = !DILocation(line: 2, column: 7, scope: !9)
-!27 = distinct !DIAssignID()
-!28 = !DILocation(line: 3, column: 8, scope: !29)
-!29 = distinct !DILexicalBlock(scope: !9, file: !10, line: 3, column: 7)
-!30 = !DILocation(line: 3, column: 10, scope: !29)
-!31 = !DILocation(line: 3, column: 15, scope: !29)
-!32 = !DILocation(line: 4, column: 7, scope: !33)
-!33 = distinct !DILexicalBlock(scope: !29, file: !10, line: 3, column: 21)
-!34 = distinct !DIAssignID()
-!35 = !DILocation(line: 40, column: 6, scope: !36)
-!36 = !DILexicalBlockFile(scope: !33, file: !37, discriminator: 0)
-!37 = !DIFile(filename: "m.c", directory: "")
-!38 = !DILocation(line: 40, column: 3, scope: !36)
-!39 = distinct !DIAssignID()
-!40 = !DILocation(line: 41, column: 9, scope: !36)
-!41 = !DILocation(line: 41, column: 8, scope: !36)
-!42 = !DILocation(line: 41, column: 3, scope: !36)
-!43 = distinct !DIAssignID()
-!44 = !DILocation(line: 42, column: 6, scope: !36)
-!45 = !DILocation(line: 42, column: 8, scope: !36)
-!46 = !DILocation(line: 42, column: 7, scope: !36)
-!47 = !DILocation(line: 42, column: 3, scope: !36)
-!48 = distinct !DIAssignID()
-!49 = !DILocation(line: 6, column: 2, scope: !50)
-!50 = !DILexicalBlockFile(scope: !33, file: !10, discriminator: 0)
-!51 = !DILocation(line: 7, column: 7, scope: !52)
-!52 = distinct !DILexicalBlock(scope: !29, file: !10, line: 6, column: 9)
-!53 = distinct !DIAssignID()
-!54 = !DILocation(line: 40, column: 6, scope: !55)
-!55 = !DILexicalBlockFile(scope: !52, file: !37, discriminator: 0)
-!56 = !DILocation(line: 40, column: 3, scope: !55)
-!57 = distinct !DIAssignID()
-!58 = !DILocation(line: 41, column: 9, scope: !55)
-!59 = !DILocation(line: 41, column: 8, scope: !55)
-!60 = !DILocation(line: 41, column: 3, scope: !55)
-!61 = distinct !DIAssignID()
-!62 = !DILocation(line: 42, column: 6, scope: !55)
-!63 = !DILocation(line: 42, column: 8, scope: !55)
-!64 = !DILocation(line: 42, column: 7, scope: !55)
-!65 = !DILocation(line: 42, column: 3, scope: !55)
-!66 = distinct !DIAssignID()
-!67 = !DILocation(line: 10, column: 10, scope: !9)
-!68 = !DILocation(line: 11, column: 1, scope: !9)
-!69 = !DILocation(line: 10, column: 3, scope: !9)
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = distinct !DISubprogram(name: "foo", scope: !4, file: !4, line: 1, type: !5, scopeLine: 1, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !6)
+!4 = !DIFile(filename: "1.c", directory: "")
+!5 = !DISubroutineType(types: !6)
+!6 = !{}
+!7 = !DILocation(line: 3, column: 10, scope: !8)
+!8 = distinct !DILexicalBlock(scope: !3, file: !4, line: 3, column: 7)
+!9 = !DILocation(line: 4, column: 7, scope: !10)
+!10 = distinct !DILexicalBlock(scope: !8, file: !4, line: 3, column: 21)
+!11 = !DILocation(line: 40, column: 3, scope: !12)
+!12 = !DILexicalBlockFile(scope: !10, file: !13, discriminator: 0)
+!13 = !DIFile(filename: "m.c", directory: "")
+!14 = !DILocation(line: 42, column: 3, scope: !12)
+!15 = !DILocation(line: 42, column: 3, scope: !16)
+!16 = !DILexicalBlockFile(scope: !17, file: !13, discriminator: 0)
+!17 = distinct !DILexicalBlock(scope: !8, file: !4, line: 6, column: 9)
 
 ; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE1:![0-9]+]], file: [[FILE1]], line: 1
 ; CHECK: [[FILE1]] = !DIFile(filename: "1.c", directory: "")
-; CHECK: [[LB1:![0-9]+]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE1]], line: 3, column: 7)
-; CHECK: [[LB2:![0-9]+]] = distinct !DILexicalBlock(scope: [[LB1]], file: [[FILE1]], line: 3, column: 21)
-; CHECK: [[LBF:![0-9]+]] = !DILexicalBlockFile(scope: [[LB2]], file: [[FILE2:![0-9]+]], discriminator: 0)
+; CHECK: [[PHILOC]] = !DILocation(line: 42, column: 3, scope: [[LBF:![0-9]+]])
+; CHECK: [[LBF]] = !DILexicalBlockFile(scope: [[LB1:![0-9]+]], file: [[FILE2:![0-9]+]], discriminator: 0)
 ; CHECK: [[FILE2]] = !DIFile(filename: "m.c", directory: "")
-; CHECK: [[PHILOC]] = !DILocation(line: 42, column: 3, scope: [[LBF]])
+; CHECK: [[LB1]] = distinct !DILexicalBlock(scope: [[LB2:![0-9]+]], file: [[FILE1]], line: 3, column: 21)
+; CHECK: [[LB2]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE1]], line: 3, column: 7)
diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
index dd52bf7907a76..040833b1a2e89 100644
--- a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
@@ -75,155 +75,58 @@
 ;   return i;
 ; }
 
-source_filename = "main.preproc.c"
 target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"
 target triple = "arm64-apple-macosx15.0.0"
 
-; Function Attrs: noinline nounwind ssp uwtable(sync)
-define i32 @foo(i32 noundef %a) !dbg !9 {
+define i32 @foo() !dbg !3 {
 ; CHECK:    phi i32 {{.*}}, !dbg [[PHILOC:![0-9]+]]
 ;
 entry:
-  %a.addr = alloca i32, align 4
   %i = alloca i32, align 4
-  store i32 %a, ptr %a.addr, align 4
-    #dbg_declare(ptr %a.addr, !15, !DIExpression(), !16)
-    #dbg_declare(ptr %i, !17, !DIExpression(), !18)
-  store i32 0, ptr %i, align 4, !dbg !18
-  %0 = load i32, ptr %a.addr, align 4, !dbg !19
-  %and = and i32 %0, 1, !dbg !21
-  %cmp = icmp eq i32 %and, 1, !dbg !22
-  br i1 %cmp, label %if.then, label %if.else, !dbg !22
+  br i1 false, label %do.body, label %if.else
 
-if.then:                                          ; preds = %entry
-  %1 = load i32, ptr %a.addr, align 4, !dbg !23
-  %sub = sub nsw i32 %1, 1, !dbg !23
-  store i32 %sub, ptr %a.addr, align 4, !dbg !23
-  br label %do.body, !dbg !25
-
-do.body:                                          ; preds = %if.then
-  %2 = load i32, ptr %a.addr, align 4, !dbg !28
-  %3 = load i32, ptr %i, align 4, !dbg !32
-  %add = add nsw i32 %3, %2, !dbg !32
-  store i32 %add, ptr %i, align 4, !dbg !32
-  %4 = load i32, ptr %a.addr, align 4, !dbg !33
-  %mul = mul nsw i32 10, %4, !dbg !34
-  %5 = load i32, ptr %i, align 4, !dbg !35
-  %sub1 = sub nsw i32 %5, %mul, !dbg !35
-  store i32 %sub1, ptr %i, align 4, !dbg !35
-  %6 = load i32, ptr %a.addr, align 4, !dbg !36
-  %7 = load i32, ptr %a.addr, align 4, !dbg !37
-  %mul2 = mul nsw i32 %6, %7, !dbg !38
-  %8 = load i32, ptr %i, align 4, !dbg !39
-  %mul3 = mul nsw i32 %8, %mul2, !dbg !39
-  store i32 %mul3, ptr %i, align 4, !dbg !39
-  br label %do.end, !dbg !40
-
-do.end:                                           ; preds = %do.body
-  br label %if.end, !dbg !42
+do.body:                                          ; preds = %entry
+  store i32 1, ptr %i, align 4, !dbg !6
+  br label %if.end
 
 if.else:                                          ; preds = %entry
-  %9 = load i32, ptr %a.addr, align 4, !dbg !44
-  %add4 = add nsw i32 %9, 3, !dbg !44
-  store i32 %add4, ptr %a.addr, align 4, !dbg !44
-  br label %do.body5, !dbg !46
-
-do.body5:                                         ; preds = %if.else
-  %10 = load i32, ptr %a.addr, align 4, !dbg !48
-  %11 = load i32, ptr %i, align 4, !dbg !52
-  %add6 = add nsw i32 %11, %10, !dbg !52
-  store i32 %add6, ptr %i, align 4, !dbg !52
-  %12 = load i32, ptr %a.addr, align 4, !dbg !53
-  %mul7 = mul nsw i32 10, %12, !dbg !54
-  %13 = load i32, ptr %i, align 4, !dbg !55
-  %sub8 = sub nsw i32 %13, %mul7, !dbg !55
-  store i32 %sub8, ptr %i, align 4, !dbg !55
-  %14 = load i32, ptr %a.addr, align 4, !dbg !56
-  %15 = load i32, ptr %a.addr, align 4, !dbg !57
-  %mul9 = mul nsw i32 %14, %15, !dbg !58
-  %16 = load i32, ptr %i, align 4, !dbg !59
-  %mul10 = mul nsw i32 %16, %mul9, !dbg !59
-  store i32 %mul10, ptr %i, align 4, !dbg !59
-  br label %do.end11, !dbg !60
-
-do.end11:                                         ; preds = %do.body5
+  store i32 0, ptr %i, align 4, !dbg !14
   br label %if.end
 
-if.end:                                           ; preds = %do.end11, %do.end
-  %17 = load i32, ptr %i, align 4, !dbg !62
-  ret i32 %17, !dbg !63
+if.end:                                           ; preds = %if.else, %do.body
+  %0 = load i32, ptr %i, align 4
+  ret i32 0
 }
 
 !llvm.dbg.cu = !{!0}
-!llvm.module.flags = !{!2, !3}
-!llvm.ident = !{!8}
+!llvm.module.flags = !{!2}
 
 !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "clang version 21.0.0git", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
-!1 = !DIFile(filename: "main.preproc.c", directory: "")
-!2 = !{i32 7, !"Dwarf Version", i32 5}
-!3 = !{i32 2, !"Debug Info Version", i32 3}
-!8 = !{!"clang version 21.0.0git"}
-!9 = distinct !DISubprogram(name: "foo", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14)
-!10 = !DIFile(filename: "main.c", directory: "")
-!11 = !DISubroutineType(types: !12)
-!12 = !{!13, !13}
-!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
-!14 = !{}
-!15 = !DILocalVariable(name: "a", arg: 1, scope: !9, file: !10, line: 1, type: !13)
-!16 = !DILocation(line: 1, column: 13, scope: !9)
-!17 = !DILocalVariable(name: "i", scope: !9, file: !10, line: 2, type: !13)
-!18 = !DILocation(line: 2, column: 7, scope: !9)
-!19 = !DILocation(line: 3, column: 8, scope: !20)
-!20 = distinct !DILexicalBlock(scope: !9, file: !10, line: 3, column: 7)
-!21 = !DILocation(line: 3, column: 10, scope: !20)
-!22 = !DILocation(line: 3, column: 15, scope: !20)
-!23 = !DILocation(line: 4, column: 7, scope: !24)
-!24 = distinct !DILexicalBlock(scope: !20, file: !10, line: 3, column: 21)
-!25 = !DILocation(line: 300, column: 1, scope: !26)
-!26 = !DILexicalBlockFile(scope: !24, file: !27, discriminator: 0)
-!27 = !DIFile(filename: "y.c", directory: "")
-!28 = !DILocation(line: 100, column: 6, scope: !29)
-!29 = !DILexicalBlockFile(scope: !31, file: !30, discriminator: 0)
-!30 = !DIFile(filename: "z1.c", directory: "")
-!31 = distinct !DILexicalBlock(scope: !26, file: !27, line: 300, column: 4)
-!32 = !DILocation(line: 100, column: 3, scope: !29)
-!33 = !DILocation(line: 101, column: 9, scope: !29)
-!34 = !DILocation(line: 101, column: 8, scope: !29)
-!35 = !DILocation(line: 101, column: 3, scope: !29)
-!36 = !DILocation(line: 102, column: 6, scope: !29)
-!37 = !DILocation(line: 102, column: 8, scope: !29)
-!38 = !DILocation(line: 102, column: 7, scope: !29)
-!39 = !DILocation(line: 102, column: 3, scope: !29)
-!40 = !DILocation(line: 303, column: 1, scope: !41)
-!41 = !DILexicalBlockFile(scope: !31, file: !27, discriminator: 0)
-!42 = !DILocation(line: 7, column: 2, scope: !43)
-!43 = !DILexicalBlockFile(scope: !24, file: !10, discriminator: 0)
-!44 = !DILocation(line: 8, column: 7, scope: !45)
-!45 = distinct !DILexicalBlock(scope: !20, file: !10, line: 7, column: 9)
-!46 = !DILocation(line: 300, column: 1, scope: !47)
-!47 = !DILexicalBlockFile(scope: !45, file: !27, discriminator: 0)
-!48 = !DILocation(line: 200, column: 6, scope: !49)
-!49 = !DILexicalBlockFile(scope: !51, file: !50, discriminator: 0)
-!50 = !DIFile(filename: "z2.c", directory: "")
-!51 = distinct !DILexicalBlock(scope: !47, file: !27, line: 300, column: 4)
-!52 = !DILocation(line: 200, column: 3, scope: !49)
-!53 = !DILocation(line: 201, column: 9, scope: !49)
-!54 = !DILocation(line: 201, column: 8, scope: !49)
-!55 = !DILocation(line: 201, column: 3, scope: !49)
-!56 = !DILocation(line: 202, column: 6, scope: !49)
-!57 = !DILocation(line: 202, column: 8, scope: !49)
-!58 = !DILocation(line: 202, column: 7, scope: !49)
-!59 = !DILocation(line: 202, column: 3, scope: !49)
-!60 = !DILocation(line: 305, column: 1, scope: !61)
-!61 = !DILexicalBlockFile(scope: !51, file: !27, discriminator: 0)
-!62 = !DILocation(line: 12, column: 10, scope: !9)
-!63 = !DILocation(line: 12, column: 3, scope: !9)
+!1 = !DIFile(filename: "main.c", directory: "")
+!2 = !{i32 2, !"Debug Info Version", i32 3}
+!3 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 1, type: !4, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !5)
+!4 = !DISubroutineType(types: !5)
+!5 = !{}
+!6 = !DILocation(line: 102, column: 3, scope: !7)
+!7 = !DILexicalBlockFile(scope: !9, file: !8, discriminator: 0)
+!8 = !DIFile(filename: "z1.c", directory: "")
+!9 = distinct !DILexicalBlock(scope: !11, file: !10, line: 300, column: 4)
+!10 = !DIFile(filename: "y.c", directory: "")
+!11 = !DILexicalBlockFile(scope: !12, file: !10, discriminator: 0)
+!12 = distinct !DILexicalBlock(scope: !13, file: !1, line: 3, column: 21)
+!13 = distinct !DILexicalBlock(scope: !3, file: !1, line: 3, column: 7)
+!14 = !DILocation(line: 202, column: 3, scope: !15)
+!15 = !DILexicalBlockFile(scope: !17, file: !16, discriminator: 0)
+!16 = !DIFile(filename: "z2.c", directory: "")
+!17 = distinct !DILexicalBlock(scope: !18, file: !10, line: 300, column: 4)
+!18 = !DILexicalBlockFile(scope: !19, file: !10, discriminator: 0)
+!19 = distinct !DILexicalBlock(scope: !13, file: !1, line: 7, column: 9)
 
-; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE_MAIN:![0-9]+]], file: [[FILE_MAIN]], line: 1
-; CHECK: [[FILE_MAIN]] = !DIFile(filename: "main.c"
-; CHECK: [[BLOCK1_MAIN:![0-9]+]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE_MAIN]], line: 3, column: 7)
-; CHECK: [[BLOCK2_MAIN:![0-9]+]] = distinct !DILexicalBlock(scope: [[BLOCK1_MAIN]], file: [[FILE_MAIN]], line: 3, column: 21)
-; CHECK: [[LBF1_Y:![0-9]+]] = !DILexicalBlockFile(scope: [[BLOCK2_MAIN]], file: [[FILE_Y:![0-9]+]], discriminator: 0)
-; CHECK: [[FILE_Y]] = !DIFile(filename: "y.c"
-; CHECK: [[BLOCK_Y:![0-9]+]] = distinct !DILexicalBlock(scope: [[LBF1_Y]], file: [[FILE_Y]], line: 300, column: 4)
-; CHECK: [[PHILOC]] = !DILocation(line: 300, column: 4, scope: [[BLOCK_Y]])
+; CHECK: [[FILE_MAIN:![0-9]+]] = !DIFile(filename: "main.c"
+; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE_MAIN]], file: [[FILE_MAIN]], line: 1
+; CHECK: [[PHILOC]] = !DILocation(line: 300, column: 4, scope: [[BLOCK_Y:![0-9]+]])
+; CHECK-NEXT: [[BLOCK_Y]] = distinct !DILexicalBlock(scope: [[LBF_Y:![0-9]+]], file: [[FILE_Y:![0-9]+]], line: 300, column: 4)
+; CHECK-NEXT: [[FILE_Y]] = !DIFile(filename: "y.c"
+; CHECK: [[LBF_Y]] = !DILexicalBlockFile(scope: [[BLOCK2_MAIN:![0-9]+]], file: [[FILE_Y]], discriminator: 0)
+; CHECK-NEXT: [[BLOCK2_MAIN]] = distinct !DILexicalBlock(scope: [[BLOCK1_MAIN:![0-9]+]], file: [[FILE_MAIN]], line: 3, column: 21)
+; CHECK: [[BLOCK1_MAIN]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE_MAIN]], line: 3, column: 7)

>From 7d6b37ee195e1d9e88c91abc84226adf17b94752 Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Thu, 27 Mar 2025 21:05:31 +0100
Subject: [PATCH 4/7] Reduce merge-nested-block-loc.ll

---
 .../AArch64/merge-nested-block-loc.ll         | 33 ++++++-------------
 1 file changed, 10 insertions(+), 23 deletions(-)

diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
index 62153663266d5..d1cefb0e2f500 100644
--- a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
@@ -40,13 +40,11 @@ entry:
   br i1 false, label %if.then, label %if.else
 
 if.then:                                          ; preds = %entry
-  %mul3 = mul i32 0, 0, !dbg !14
-  store i32 %mul3, ptr %i, align 4, !dbg !14
+  store i32 1, ptr %i, align 4, !dbg !7
   br label %if.end
 
 if.else:                                          ; preds = %entry
-  %mul9 = mul i32 0, 0, !dbg !15
-  store i32 %mul9, ptr %i, align 4, !dbg !15
+  store i32 0, ptr %i, align 4, !dbg !12
   br label %if.end
 
 if.end:                                           ; preds = %if.else, %if.then
@@ -54,14 +52,6 @@ if.end:                                           ; preds = %if.else, %if.then
   ret i32 0
 }
 
-; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
-declare void @llvm.lifetime.start.p0(i64 immarg, ptr captures(none)) #0
-
-; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
-declare void @llvm.lifetime.end.p0(i64 immarg, ptr captures(none)) #0
-
-attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
-
 !llvm.dbg.cu = !{!0}
 !llvm.module.flags = !{!2}
 
@@ -72,17 +62,14 @@ attributes #0 = { nocallback nofree nosync nounwind willreturn memory(argmem: re
 !4 = !DIFile(filename: "1.c", directory: "")
 !5 = !DISubroutineType(types: !6)
 !6 = !{}
-!7 = !DILocation(line: 3, column: 10, scope: !8)
-!8 = distinct !DILexicalBlock(scope: !3, file: !4, line: 3, column: 7)
-!9 = !DILocation(line: 4, column: 7, scope: !10)
-!10 = distinct !DILexicalBlock(scope: !8, file: !4, line: 3, column: 21)
-!11 = !DILocation(line: 40, column: 3, scope: !12)
-!12 = !DILexicalBlockFile(scope: !10, file: !13, discriminator: 0)
-!13 = !DIFile(filename: "m.c", directory: "")
-!14 = !DILocation(line: 42, column: 3, scope: !12)
-!15 = !DILocation(line: 42, column: 3, scope: !16)
-!16 = !DILexicalBlockFile(scope: !17, file: !13, discriminator: 0)
-!17 = distinct !DILexicalBlock(scope: !8, file: !4, line: 6, column: 9)
+!7 = !DILocation(line: 42, column: 3, scope: !8)
+!8 = !DILexicalBlockFile(scope: !10, file: !9, discriminator: 0)
+!9 = !DIFile(filename: "m.c", directory: "")
+!10 = distinct !DILexicalBlock(scope: !11, file: !4, line: 3, column: 21)
+!11 = distinct !DILexicalBlock(scope: !3, file: !4, line: 3, column: 7)
+!12 = !DILocation(line: 42, column: 3, scope: !13)
+!13 = !DILexicalBlockFile(scope: !14, file: !9, discriminator: 0)
+!14 = distinct !DILexicalBlock(scope: !11, file: !4, line: 6, column: 9)
 
 ; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE1:![0-9]+]], file: [[FILE1]], line: 1
 ; CHECK: [[FILE1]] = !DIFile(filename: "1.c", directory: "")

>From 6f5f234f15a869a9e6c8bc6ea1add32e953f8c9a Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Thu, 27 Mar 2025 21:12:36 +0100
Subject: [PATCH 5/7] Fix test comment

---
 llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
index d1cefb0e2f500..de606de35e2e8 100644
--- a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
@@ -1,8 +1,8 @@
 ; RUN: opt -mtriple=aarch64-unknown-linux-gnu -S %s -passes=sroa -o - | FileCheck %s
 
-; In this test we want to ensure that the location of phi instruction merged from locations
-; of %mul3 and %mul9 belongs to the correct scope (DILexicalBlockFile), so that line
-; number of that location belongs to the corresponding file.
+; In this test we want to ensure that the merged location of phi instruction
+; belongs to the correct scope (DILexicalBlockFile), so that line number
+; of that location belongs to the corresponding file.
 
 ; Generated with clang from
 ; # 1 "1.c" 1

>From 5b825aed1827a6aca08b3202c870bc2e2a281b96 Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Wed, 2 Apr 2025 12:24:34 +0200
Subject: [PATCH 6/7] Next iteration of the algorithm

---
 llvm/lib/IR/DebugInfoMetadata.cpp             | 167 +++++++++++-------
 .../AArch64/merge-nested-block-loc.ll         |   5 +-
 .../AArch64/merge-nested-block-loc2.ll        |   6 +-
 llvm/unittests/IR/MetadataTest.cpp            |  19 +-
 4 files changed, 124 insertions(+), 73 deletions(-)

diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index 2212d5626e0da..ce4fc76ce9e63 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -125,6 +125,14 @@ DILocation *DILocation::getMergedLocations(ArrayRef<DILocation *> Locs) {
   return Merged;
 }
 
+static DILexicalBlockBase *cloneAndReplaceParentScope(DILexicalBlockBase *LBB,
+                                                      DIScope *NewParent) {
+  TempMDNode ClonedScope = LBB->clone();
+  cast<DILexicalBlockBase>(*ClonedScope).replaceScope(NewParent);
+  return cast<DILexicalBlockBase>(
+      MDNode::replaceWithUniqued(std::move(ClonedScope)));
+}
+
 using LineColumn = std::pair<unsigned /* Line */, unsigned /* Column */>;
 
 /// Returns the location of DILocalScope, if present, or a default value.
@@ -141,6 +149,82 @@ static LineColumn getLocalScopeLocationOr(DIScope *S, LineColumn Default) {
   llvm_unreachable("Unhandled type of DILocalScope.");
 }
 
+// Returns the nearest matching scope inside a subprogram.
+template <typename MatcherT>
+static std::pair<DIScope *, LineColumn>
+getNearestMatchingScope(const DILocation *L1, const DILocation *L2) {
+  MatcherT Matcher;
+
+  DIScope *S1 = L1->getScope();
+  DIScope *S2 = L2->getScope();
+
+  // When matching DILexicalBlockFile's, ignore column numbers, so that
+  // DILocation's having different columns within the same
+  // DILexicalBlockFile will match.
+  auto GetLocForBlockFile = [](LineColumn L) {
+    L.second = 0;
+    return L;
+  };
+
+  LineColumn Loc1(L1->getLine(), L1->getColumn());
+  for (; S1; S1 = S1->getScope()) {
+    Loc1 = getLocalScopeLocationOr(S1, GetLocForBlockFile(Loc1));
+    Matcher.insert(S1, Loc1);
+    if (isa<DISubprogram>(S1))
+      break;
+  }
+
+  LineColumn Loc2(L2->getLine(), L2->getColumn());
+  for (; S2; S2 = S2->getScope()) {
+    Loc2 = getLocalScopeLocationOr(S2, GetLocForBlockFile(Loc2));
+
+    if (DIScope *S = Matcher.match(S2, Loc2))
+      return std::make_pair(S, Loc2);
+
+    if (isa<DISubprogram>(S2))
+      break;
+  }
+  return std::make_pair(nullptr, LineColumn(L2->getLine(), L2->getColumn()));
+}
+
+// Matches equal scopes.
+struct EqualScopesMatcher {
+  SmallPtrSet<DIScope *, 8> Scopes;
+
+  void insert(DIScope *S, LineColumn Loc) { Scopes.insert(S); }
+
+  DIScope *match(DIScope *S, LineColumn Loc) {
+    return Scopes.contains(S) ? S : nullptr;
+  }
+};
+
+// Matches scopes with the same location.
+struct ScopeLocationsMatcher {
+  SmallMapVector<std::pair<DIFile *, LineColumn>, SmallSetVector<DIScope *, 8>,
+                 8>
+      Scopes;
+
+  void insert(DIScope *S, LineColumn Loc) {
+    Scopes[{S->getFile(), Loc}].insert(S);
+  }
+
+  DIScope *match(DIScope *S, LineColumn Loc) {
+    auto ScopesAtLoc = Scopes.find({S->getFile(), Loc});
+    // No scope found with the given location.
+    if (ScopesAtLoc == Scopes.end())
+      return nullptr;
+
+    // Prefer S over other scopes with the same location.
+    if (ScopesAtLoc->second.contains(S))
+      return S;
+
+    if (!ScopesAtLoc->second.empty())
+      return *ScopesAtLoc->second.begin();
+
+    llvm_unreachable("Scopes must not have empty entries.");
+  }
+};
+
 DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
   if (!LocA || !LocB)
     return nullptr;
@@ -224,66 +308,29 @@ DILocation *DILocation::getMergedLocation(DILocation *LocA, DILocation *LocB) {
     if (L1->getScope()->getSubprogram() != L2->getScope()->getSubprogram())
       return nullptr;
 
-    // Return the nearest common scope inside a subprogram.
-    auto GetNearestCommonScope =
-        [](const DILocation *L1,
-           const DILocation *L2) -> std::pair<DIScope *, LineColumn> {
-      DIScope *S1 = L1->getScope();
-      DIScope *S2 = L2->getScope();
-
-      SmallMapVector<std::pair<DIFile *, LineColumn>,
-                     SmallSetVector<DIScope *, 8>, 8>
-          Scopes;
-
-      // When matching DILexicalBlockFile's, ignore column numbers, so that
-      // DILocation's having different columns within the same
-      // DILexicalBlockFile will match.
-      auto getLocForBlockFile = [](LineColumn L) {
-        L.second = 0;
-        return L;
-      };
-
-      LineColumn Loc1(L1->getLine(), L1->getColumn());
-      for (; S1; S1 = S1->getScope()) {
-        Loc1 = getLocalScopeLocationOr(S1, getLocForBlockFile(Loc1));
-        Scopes[{S1->getFile(), Loc1}].insert(S1);
-
-        if (isa<DISubprogram>(S1))
-          break;
-      }
-
-      LineColumn Loc2(L2->getLine(), L2->getColumn());
-      for (; S2; S2 = S2->getScope()) {
-        Loc2 = getLocalScopeLocationOr(S2, getLocForBlockFile(Loc2));
-
-        auto ScopesAtLoc = Scopes.find({S2->getFile(), Loc2});
-        // No scope found with the same file, line and column as S2.
-        if (ScopesAtLoc == Scopes.end())
-          continue;
-
-        // Return S2 if it is L1's parent.
-        if (ScopesAtLoc->second.contains(S2))
-          return std::make_pair(S2, Loc2);
-
-        // Return any L1's parent with the same file, line and column as S2.
-        if (!ScopesAtLoc->second.empty())
-          return std::make_pair(*ScopesAtLoc->second.begin(), Loc2);
-
-        if (isa<DISubprogram>(S2))
-          break;
-      }
-
-      return std::make_pair(nullptr,
-                            LineColumn(L2->getLine(), L2->getColumn()));
-    };
-
-    auto [Scope, ScopeLoc] = GetNearestCommonScope(L1, L2);
+    // Find nearest common scope inside subprogram.
+    DIScope *Scope = getNearestMatchingScope<EqualScopesMatcher>(L1, L2).first;
     assert(Scope && "No common scope in the same subprogram?");
 
-    // Use inclusion location if files are different.
+    // Try using the nearest scope with common location if files are different.
     if (Scope->getFile() != L1->getFile() || L1->getFile() != L2->getFile()) {
-      return DILocation::get(C, ScopeLoc.first, ScopeLoc.second, Scope,
-                             InlinedAt);
+      auto [CommonLocScope, CommonLoc] =
+          getNearestMatchingScope<ScopeLocationsMatcher>(L1, L2);
+
+      // If CommonLocScope is a DILexicalBlockBase, clone it and locate
+      // a new scope inside the nearest common scope to preserve
+      // lexical blocks structure.
+      if (auto *LBB = dyn_cast<DILexicalBlockBase>(CommonLocScope);
+          LBB && LBB != Scope)
+        CommonLocScope = cloneAndReplaceParentScope(LBB, Scope);
+
+      Scope = CommonLocScope;
+
+      // If files are still different, assume that L1 and L2 were "included"
+      // from CommonLoc. Use it as merged location.
+      if (Scope->getFile() != L1->getFile() || L1->getFile() != L2->getFile())
+        return DILocation::get(C, CommonLoc.first, CommonLoc.second,
+                               CommonLocScope, InlinedAt);
     }
 
     bool SameLine = L1->getLine() == L2->getLine();
@@ -1243,10 +1290,8 @@ DILocalScope *DILocalScope::cloneScopeForSubprogram(
   // cached result).
   DIScope *UpdatedScope = CachedResult ? CachedResult : &NewSP;
   for (DIScope *ScopeToUpdate : reverse(ScopeChain)) {
-    TempMDNode ClonedScope = ScopeToUpdate->clone();
-    cast<DILexicalBlockBase>(*ClonedScope).replaceScope(UpdatedScope);
-    UpdatedScope =
-        cast<DIScope>(MDNode::replaceWithUniqued(std::move(ClonedScope)));
+    UpdatedScope = cloneAndReplaceParentScope(
+        cast<DILexicalBlockBase>(ScopeToUpdate), UpdatedScope);
     Cache[ScopeToUpdate] = UpdatedScope;
   }
 
diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
index de606de35e2e8..bff705bfc1ad4 100644
--- a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc.ll
@@ -74,7 +74,6 @@ if.end:                                           ; preds = %if.else, %if.then
 ; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE1:![0-9]+]], file: [[FILE1]], line: 1
 ; CHECK: [[FILE1]] = !DIFile(filename: "1.c", directory: "")
 ; CHECK: [[PHILOC]] = !DILocation(line: 42, column: 3, scope: [[LBF:![0-9]+]])
-; CHECK: [[LBF]] = !DILexicalBlockFile(scope: [[LB1:![0-9]+]], file: [[FILE2:![0-9]+]], discriminator: 0)
+; CHECK: [[LBF]] = !DILexicalBlockFile(scope: [[LB:![0-9]+]], file: [[FILE2:![0-9]+]], discriminator: 0)
 ; CHECK: [[FILE2]] = !DIFile(filename: "m.c", directory: "")
-; CHECK: [[LB1]] = distinct !DILexicalBlock(scope: [[LB2:![0-9]+]], file: [[FILE1]], line: 3, column: 21)
-; CHECK: [[LB2]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE1]], line: 3, column: 7)
+; CHECK: [[LB]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE1]], line: 3, column: 7)
diff --git a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
index 040833b1a2e89..e5c9a32318b00 100644
--- a/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
+++ b/llvm/test/DebugInfo/AArch64/merge-nested-block-loc2.ll
@@ -125,8 +125,6 @@ if.end:                                           ; preds = %if.else, %do.body
 ; CHECK: [[FILE_MAIN:![0-9]+]] = !DIFile(filename: "main.c"
 ; CHECK: [[SP:![0-9]+]] = distinct !DISubprogram(name: "foo", scope: [[FILE_MAIN]], file: [[FILE_MAIN]], line: 1
 ; CHECK: [[PHILOC]] = !DILocation(line: 300, column: 4, scope: [[BLOCK_Y:![0-9]+]])
-; CHECK-NEXT: [[BLOCK_Y]] = distinct !DILexicalBlock(scope: [[LBF_Y:![0-9]+]], file: [[FILE_Y:![0-9]+]], line: 300, column: 4)
+; CHECK-NEXT: [[BLOCK_Y]] = !DILexicalBlock(scope: [[BLOCK_MAIN:![0-9]+]], file: [[FILE_Y:![0-9]+]], line: 300, column: 4)
 ; CHECK-NEXT: [[FILE_Y]] = !DIFile(filename: "y.c"
-; CHECK: [[LBF_Y]] = !DILexicalBlockFile(scope: [[BLOCK2_MAIN:![0-9]+]], file: [[FILE_Y]], discriminator: 0)
-; CHECK-NEXT: [[BLOCK2_MAIN]] = distinct !DILexicalBlock(scope: [[BLOCK1_MAIN:![0-9]+]], file: [[FILE_MAIN]], line: 3, column: 21)
-; CHECK: [[BLOCK1_MAIN]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE_MAIN]], line: 3, column: 7)
+; CHECK: [[BLOCK_MAIN]] = distinct !DILexicalBlock(scope: [[SP]], file: [[FILE_MAIN]], line: 3, column: 7)
diff --git a/llvm/unittests/IR/MetadataTest.cpp b/llvm/unittests/IR/MetadataTest.cpp
index b77475a6ea855..76bdfeb880bb0 100644
--- a/llvm/unittests/IR/MetadataTest.cpp
+++ b/llvm/unittests/IR/MetadataTest.cpp
@@ -1000,9 +1000,9 @@ TEST_F(DILocationTest, Merge) {
     auto *A = DILocation::get(Context, 1, 6, LBF);
     auto *B = DILocation::get(Context, 2, 7, LBF);
     auto *M = DILocation::getMergedLocation(A, B);
-    EXPECT_EQ(3u, M->getLine());
-    EXPECT_EQ(4u, M->getColumn());
-    EXPECT_EQ(S, M->getScope());
+    EXPECT_EQ(0u, M->getLine());
+    EXPECT_EQ(0u, M->getColumn());
+    EXPECT_EQ(LBF, M->getScope());
   }
 
   {
@@ -1084,10 +1084,15 @@ TEST_F(DILocationTest, Merge) {
     auto *LBF2 = DILexicalBlockFile::get(Context, LB2, F2, 0);
     auto *A = DILocation::get(Context, 1, 6, LBF1);
     auto *B = DILocation::get(Context, 1, 6, LBF2);
+    llvm::errs() << "Check\n";
     auto *M = DILocation::getMergedLocation(A, B);
+    M->dump();
+    M->getScope()->dump();
+    LBF1->dump();
     EXPECT_EQ(1u, M->getLine());
     EXPECT_EQ(6u, M->getColumn());
-    EXPECT_EQ(LBF1, M->getScope());
+    EXPECT_EQ(LBF1->getFile(), M->getScope()->getFile());
+    EXPECT_EQ(N, M->getScope()->getScope());
   }
 
   {
@@ -1167,9 +1172,13 @@ TEST_F(DILocationTest, Merge) {
     auto *A = DILocation::get(Context, 41, 7, Block2[0]);
     auto *B = DILocation::get(Context, 51, 8, Block2[1]);
     auto *M = DILocation::getMergedLocation(A, B);
+    auto *MScope = dyn_cast<DILexicalBlock>(M->getScope());
     EXPECT_EQ(30u, M->getLine());
     EXPECT_EQ(4u, M->getColumn());
-    EXPECT_EQ(Block1[0], M->getScope());
+    EXPECT_EQ(Block1[0]->getFile(), MScope->getFile());
+    EXPECT_EQ(Block1[0]->getLine(), MScope->getLine());
+    EXPECT_EQ(Block1[0]->getColumn(), MScope->getColumn());
+    EXPECT_EQ(LBCommon, MScope->getScope());
   }
 
   {

>From b61a02b7eb7d723f16280bdfba6130eec14fbd00 Mon Sep 17 00:00:00 2001
From: Vladislav Dzhidzhoev <vdzhidzhoev at accesssoftek.com>
Date: Fri, 4 Apr 2025 18:34:04 +0200
Subject: [PATCH 7/7] Remove GetLocForBlockFile

---
 llvm/lib/IR/DebugInfoMetadata.cpp | 12 ++----------
 1 file changed, 2 insertions(+), 10 deletions(-)

diff --git a/llvm/lib/IR/DebugInfoMetadata.cpp b/llvm/lib/IR/DebugInfoMetadata.cpp
index ce4fc76ce9e63..e43f2cf6b0a70 100644
--- a/llvm/lib/IR/DebugInfoMetadata.cpp
+++ b/llvm/lib/IR/DebugInfoMetadata.cpp
@@ -158,17 +158,9 @@ getNearestMatchingScope(const DILocation *L1, const DILocation *L2) {
   DIScope *S1 = L1->getScope();
   DIScope *S2 = L2->getScope();
 
-  // When matching DILexicalBlockFile's, ignore column numbers, so that
-  // DILocation's having different columns within the same
-  // DILexicalBlockFile will match.
-  auto GetLocForBlockFile = [](LineColumn L) {
-    L.second = 0;
-    return L;
-  };
-
   LineColumn Loc1(L1->getLine(), L1->getColumn());
   for (; S1; S1 = S1->getScope()) {
-    Loc1 = getLocalScopeLocationOr(S1, GetLocForBlockFile(Loc1));
+    Loc1 = getLocalScopeLocationOr(S1, Loc1);
     Matcher.insert(S1, Loc1);
     if (isa<DISubprogram>(S1))
       break;
@@ -176,7 +168,7 @@ getNearestMatchingScope(const DILocation *L1, const DILocation *L2) {
 
   LineColumn Loc2(L2->getLine(), L2->getColumn());
   for (; S2; S2 = S2->getScope()) {
-    Loc2 = getLocalScopeLocationOr(S2, GetLocForBlockFile(Loc2));
+    Loc2 = getLocalScopeLocationOr(S2, Loc2);
 
     if (DIScope *S = Matcher.match(S2, Loc2))
       return std::make_pair(S, Loc2);



More information about the llvm-commits mailing list