Index: llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
===================================================================
--- llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
+++ llvm/lib/CodeGen/AssignmentTrackingAnalysis.cpp
@@ -47,6 +47,12 @@
 static cl::opt<bool> PrintResults("print-debug-ata", cl::init(false),
                                   cl::Hidden);
 
+/// Coalesce adjacent dbg locs describing memory locations that have contiguous
+/// fragments. This reduces the cost of LiveDebugValues which does SSA
+/// construction for each explicitly stated variable fragment.
+static cl::opt<bool> CoalesceAdjacentFragments("debug-ata-coalesce-frags",
+                                               cl::init(true), cl::Hidden);
+
 // Implicit conversions are disabled for enum class types, so unfortunately we
 // need to create a DenseMapInfo wrapper around the specified underlying type.
 template <> struct llvm::DenseMapInfo<VariableID> {
@@ -567,6 +573,31 @@
                       << " bits [" << StartBit << ", " << EndBit << ")\n");
   }
 
+  /// Inserts a new dbg def if the interval found when looking up \p StartBit
+  /// in \p FragMap starts before \p StartBit or ends after \p EndBit (which
+  /// indicates - assuming StartBit->EndBit has just been inserted - that the
+  /// slice has been coalesced in the map).
+  void coalesceFragments(BasicBlock &BB, Instruction &Before, unsigned Var,
+                         unsigned StartBit, unsigned EndBit, unsigned Base,
+                         DebugLoc DL, const FragsInMemMap &FragMap) {
+    if (!CoalesceAdjacentFragments)
+      return;
+    // We've inserted the location into the map. The map will have coalesced
+    // adjacent intervals (variable fragments) that describe the same memory
+    // location. Use this knowledge to insert a debug location that describes
+    // that coalesced fragment. This may eclipse other locs we've just
+    // inserted. This is okay as redundant locs will be cleaned up later.
+    auto CoalescedFrag = FragMap.find(StartBit);
+    // Bail if no coalescing has taken place.
+    if (CoalescedFrag.start() == StartBit && CoalescedFrag.stop() == EndBit)
+      return;
+
+    LLVM_DEBUG(dbgs() << "- Insert loc for bits " << CoalescedFrag.start()
+                      << " to " << CoalescedFrag.stop() << "\n");
+    insertMemLoc(BB, Before, Var, CoalescedFrag.start(), CoalescedFrag.stop(),
+                 Base, DL);
+  }
+
   void addDef(const VarLocInfo &VarLoc, Instruction &Before, BasicBlock &BB,
               VarFragMap &LiveSet) {
     DebugVariable DbgVar = FnVarLocs->getVariable(VarLoc.VariableID);
@@ -632,6 +663,8 @@
     if (!FragMap.overlaps(StartBit, EndBit)) {
       LLVM_DEBUG(dbgs() << "- No overlaps\n");
       FragMap.insert(StartBit, EndBit, Base);
+      coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,
+                        FragMap);
       return;
     }
     // There is at least one overlap.
@@ -722,6 +755,9 @@
       LLVM_DEBUG(dbgs() << "- Insert DEF into now-empty space\n");
       FragMap.insert(StartBit, EndBit, Base);
     }
+
+    coalesceFragments(BB, Before, Var, StartBit, EndBit, Base, VarLoc.DL,
+                      FragMap);
   }
 
   bool skipVariable(const DILocalVariable *V) { return !V->getSizeInBits(); }
@@ -857,8 +893,10 @@
 
         for (auto FragMemLoc : FragMemLocs) {
           DIExpression *Expr = DIExpression::get(Ctx, std::nullopt);
-          Expr = *DIExpression::createFragmentExpression(
-              Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
+          if (FragMemLoc.SizeInBits !=
+              *Aggregates[FragMemLoc.Var].first->getSizeInBits())
+            Expr = *DIExpression::createFragmentExpression(
+                Expr, FragMemLoc.OffsetInBits, FragMemLoc.SizeInBits);
           Expr = DIExpression::prepend(Expr, DIExpression::DerefAfter,
                                        FragMemLoc.OffsetInBits / 8);
           DebugVariable Var(Aggregates[FragMemLoc.Var].first, Expr,
Index: llvm/test/DebugInfo/assignment-tracking/X86/coalesce-cfg.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/assignment-tracking/X86/coalesce-cfg.ll
@@ -0,0 +1,104 @@
+; RUN: llc %s -o - -stop-after=finalize-isel \
+; RUN: | FileCheck %s --implicit-check-not=DBG_
+
+;; Test coalescing of contiguous fragments in adjacent location definitions.
+;; Further details and check directives inline.
+
+target triple = "x86_64-unknown-linux-gnu"
+
+@cond = dso_local global i8 0, align 1
+
+;; The final store and linked dbg.assign indicate the whole variable is located
+;; on the stack. Coalesce the two fragment defs that are generated (0-32,
+;; 32-64) at the final dbg.assign into one (0-64, which covers the whole
+;; variable meaning we don't need a fragment expression). And check the two
+;; DBG_VALUEs in if.then are not coalesced, since they specify different
+;; locations. This is the same as the first test in coalesce-simple.ll except
+;; the dbg intrinsics are split up over a simple diamond CFG to check the info
+;; is propagated betweeen blocks correctly.
+
+; CHECK-LABEL: bb.0.entry:
+; CHECK-NEXT: successors:
+; CHECK-NEXT: {{^ *$}}
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_deref)
+; CHECK-NEXT: TEST8mi
+; CHECK-NEXT: JCC_1 %bb.2
+; CHECK-NEXT: JMP_1 %bb.1
+
+; CHECK-LABEL: bb.1.if.then:
+; CHECK-NEXT: successors:
+; CHECK-NEXT: {{^ *$}}
+; CHECK-NEXT: MOV8mi $rip, 1, $noreg, @cond, $noreg, 0 :: (store (s8) into @cond)
+; CHECK-NEXT: DBG_VALUE 1, $noreg, ![[#]], !DIExpression(DW_OP_LLVM_fragment, 0, 32)
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
+; CHECK-NEXT: JMP_1 %bb.3
+
+; CHECK-LABEL: bb.2.if.else:
+; CHECK-NEXT: successors:
+; CHECK-NEXT: {{^ *$}}
+; CHECK-NEXT:   MOV8mi $rip, 1, $noreg, @cond, $noreg, 1 :: (store (s8) into @cond)
+
+; CHECK-LABEL: bb.3.if.end:
+; CHECK-NEXT:   MOV32mi %stack.0.a, 1, $noreg, 0, $noreg, 5 :: (store (s32) into %ir.a, align 8)
+; CHECK-NEXT:   DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_deref)
+; CHECK-NEXT:   RET 0
+
+define dso_local void @_Z3funv() local_unnamed_addr !dbg !16 {
+entry:
+  %a = alloca i64, !DIAssignID !37
+  call void @llvm.dbg.assign(metadata i64 poison, metadata !20, metadata !DIExpression(), metadata !37, metadata ptr %a, metadata !DIExpression()), !dbg !25
+  %0 = load i8, ptr @cond, align 1
+  %tobool = trunc i8 %0 to i1
+  br i1 %tobool, label %if.then, label %if.else
+
+if.then:
+  store i1 false, ptr @cond
+  call void @llvm.dbg.value(metadata i32 1, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25
+  br label %if.end
+
+if.else:
+  store i1 true, ptr @cond
+  br label %if.end
+
+if.end:
+  store i32 5, ptr %a, !DIAssignID !38
+  call void @llvm.dbg.assign(metadata i32 5, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32), metadata !38, metadata ptr %a, metadata !DIExpression()), !dbg !25
+  ret void
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12, !13, !14}
+!llvm.ident = !{!15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "G", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 17.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test.cpp", directory: "/")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "F", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 8, !"PIC Level", i32 2}
+!12 = !{i32 7, !"PIE Level", i32 2}
+!13 = !{i32 7, !"uwtable", i32 2}
+!14 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!15 = !{!"clang version 17.0.0"}
+!16 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funv", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !19)
+!17 = !DISubroutineType(types: !18)
+!18 = !{null}
+!19 = !{!20}
+!20 = !DILocalVariable(name: "X", scope: !16, file: !3, line: 4, type: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Pair", file: !3, line: 2, size: 64, flags: DIFlagTypePassByValue, elements: !22, identifier: "_ZTS4Pair")
+!22 = !{}
+!25 = !DILocation(line: 0, scope: !16)
+!26 = !DILocation(line: 7, column: 7, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !16, file: !3, line: 7, column: 7)
+!28 = distinct !DIAssignID()
+!37 = distinct !DIAssignID()
+!38 = distinct !DIAssignID()
Index: llvm/test/DebugInfo/assignment-tracking/X86/coalesce-simple.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/assignment-tracking/X86/coalesce-simple.ll
@@ -0,0 +1,125 @@
+; RUN: llc %s -o - -stop-after=finalize-isel \
+; RUN: | FileCheck %s --implicit-check-not=DBG_
+
+;; Test coalescing of contiguous fragments in adjacent location definitions.
+;; Further details and check directives inline.
+
+target triple = "x86_64-unknown-linux-gnu"
+
+;; The final store and linked dbg.assign indicate the whole variable is located
+;; on the stack. Coalesce the two fragment defs that are generated (0-32,
+;; 32-64) at the final dbg.assign into one (0-64, which covers the whole
+;; variable meaning we don't need a fragment expression). And check the
+;; first two DBG_VALUEs are not coalesced, since they specify different
+;; locations.
+; CHECK: _Z3fun
+; CHECK-LABEL: bb.0.entry:
+; CHECK-NEXT: DBG_VALUE 1, $noreg, ![[#]], !DIExpression(DW_OP_LLVM_fragment, 0, 32)
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
+; CHECK-NEXT: MOV32mi %stack.0.a, 1, $noreg, 0, $noreg, 5
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_deref)
+; CHECK-NEXT: RET
+define dso_local void @_Z3funv() local_unnamed_addr !dbg !16 {
+entry:
+  %a = alloca i64, !DIAssignID !37
+  call void @llvm.dbg.assign(metadata i64 poison, metadata !20, metadata !DIExpression(), metadata !37, metadata ptr %a, metadata !DIExpression()), !dbg !25
+  call void @llvm.dbg.value(metadata i32 1, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !25
+  store i32 5, ptr %a, !DIAssignID !38
+  call void @llvm.dbg.assign(metadata i32 5, metadata !20, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32), metadata !38, metadata ptr %a, metadata !DIExpression()), !dbg !25
+  ret void
+}
+
+;; Similar to the test above except that the variable has been split over two
+;; allocas, so coalescing should not take place (different memory location for
+;; the fragments).
+; CHECK: Z3funv2
+; CHECK-LABEL: bb.0.entry:
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32)
+; CHECK-NEXT: DBG_VALUE %stack.1.b, $noreg, ![[#]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
+; CHECK-NEXT: DBG_VALUE 1, $noreg, ![[#]], !DIExpression(DW_OP_LLVM_fragment, 0, 32)
+; CHECK-NEXT: MOV32mi %stack.0.a, 1, $noreg, 0, $noreg, 5
+;; Both fragments 0-32 and 32-64 are in memory now, but located in different stack slots.
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32)
+; CHECK-NEXT: RET
+define dso_local void @_Z3funv2() local_unnamed_addr !dbg !39 {
+entry:
+  %a = alloca i32, !DIAssignID !42
+  call void @llvm.dbg.assign(metadata i64 poison, metadata !41, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32), metadata !42, metadata ptr %a, metadata !DIExpression()), !dbg !44
+  %b = alloca i32, !DIAssignID !45
+  call void @llvm.dbg.assign(metadata i64 poison, metadata !41, metadata !DIExpression(DW_OP_LLVM_fragment, 32, 32), metadata !45, metadata ptr %b, metadata !DIExpression()), !dbg !44
+  call void @llvm.dbg.value(metadata i32 1, metadata !41, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32)), !dbg !44
+  store i32 5, ptr %a, !DIAssignID !43
+  call void @llvm.dbg.assign(metadata i32 5, metadata !41, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 32), metadata !43, metadata ptr %a, metadata !DIExpression()), !dbg !44
+  ret void
+}
+
+;; Similar to the first test above except the part that it's the slice 16-32
+;; that is "partially promoted". The dbg defs after the alloca cannot be
+;; coalesced (slices 0-16 and 32-64 are in memory but 16-32 isn't). The entire
+;; variable is on the stack after the store.
+; CHECK: _Z2funv3
+; CHECK-LABEL: bb.0.entry:
+; CHECK-NEXT: DBG_VALUE 2, $noreg, ![[#]], !DIExpression(DW_OP_LLVM_fragment, 16, 16)
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16)
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
+; CHECK-NEXT: MOV32mi %stack.0.a, 1, $noreg, 0, $noreg, 5
+; CHECK-NEXT: DBG_VALUE %stack.0.a, $noreg, ![[#]], !DIExpression(DW_OP_deref)
+; CHECK-NEXT: RET
+define dso_local void @_Z2funv3() local_unnamed_addr !dbg !46 {
+entry:
+  %a = alloca i64, !DIAssignID !49
+  call void @llvm.dbg.assign(metadata i64 poison, metadata !48, metadata !DIExpression(), metadata !49, metadata ptr %a, metadata !DIExpression()), !dbg !51
+  call void @llvm.dbg.value(metadata i32 2, metadata !48, metadata !DIExpression(DW_OP_LLVM_fragment, 16, 16)), !dbg !51
+  store i32 5, ptr %a, !DIAssignID !50
+  call void @llvm.dbg.assign(metadata i32 5, metadata !48, metadata !DIExpression(DW_OP_LLVM_fragment, 16, 16), metadata !50, metadata ptr %a, metadata !DIExpression(DW_OP_plus_uconst, 2)), !dbg !51
+  ret void
+}
+
+declare void @llvm.dbg.value(metadata, metadata, metadata)
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!8, !9, !10, !11, !12, !13, !14}
+!llvm.ident = !{!15}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "G", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !3, producer: "clang version 17.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test.cpp", directory: "/")
+!4 = !{!0, !5}
+!5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression())
+!6 = distinct !DIGlobalVariable(name: "F", scope: !2, file: !3, line: 1, type: !7, isLocal: false, isDefinition: true)
+!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!8 = !{i32 7, !"Dwarf Version", i32 5}
+!9 = !{i32 2, !"Debug Info Version", i32 3}
+!10 = !{i32 1, !"wchar_size", i32 4}
+!11 = !{i32 8, !"PIC Level", i32 2}
+!12 = !{i32 7, !"PIE Level", i32 2}
+!13 = !{i32 7, !"uwtable", i32 2}
+!14 = !{i32 7, !"debug-info-assignment-tracking", i1 true}
+!15 = !{!"clang version 17.0.0"}
+!16 = distinct !DISubprogram(name: "fun", linkageName: "_Z3funv", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !19)
+!17 = !DISubroutineType(types: !18)
+!18 = !{null}
+!19 = !{!20}
+!20 = !DILocalVariable(name: "X", scope: !16, file: !3, line: 4, type: !21)
+!21 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "Pair", file: !3, line: 2, size: 64, flags: DIFlagTypePassByValue, elements: !22, identifier: "_ZTS4Pair")
+!22 = !{}
+!25 = !DILocation(line: 0, scope: !16)
+!26 = !DILocation(line: 7, column: 7, scope: !27)
+!27 = distinct !DILexicalBlock(scope: !16, file: !3, line: 7, column: 7)
+!37 = distinct !DIAssignID()
+!38 = distinct !DIAssignID()
+!39 = distinct !DISubprogram(name: "fun2", linkageName: "_Z3funv2", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !40)
+!40 = !{!41}
+!41 = !DILocalVariable(name: "X", scope: !39, file: !3, line: 10, type: !21)
+!42 = distinct !DIAssignID()
+!43 = distinct !DIAssignID()
+!44 = !DILocation(line: 0, scope: !39)
+!45 = distinct !DIAssignID()
+!46 = distinct !DISubprogram(name: "fun3", linkageName: "_Z3funv3", scope: !3, file: !3, line: 3, type: !17, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !47)
+!47 = !{!48}
+!48 = !DILocalVariable(name: "X", scope: !46, file: !3, line: 10, type: !21)
+!49 = distinct !DIAssignID()
+!50 = distinct !DIAssignID()
+!51 = !DILocation(line: 0, scope: !46)
Index: llvm/test/DebugInfo/assignment-tracking/X86/lower-to-value.ll
===================================================================
--- llvm/test/DebugInfo/assignment-tracking/X86/lower-to-value.ll
+++ llvm/test/DebugInfo/assignment-tracking/X86/lower-to-value.ll
@@ -37,10 +37,7 @@
 
 ;; Then there is a store to the upper 64 bits.
 ; CHECK: MOV64mi32 %stack.0.X, 1, $noreg, 8, $noreg, 0, debug-location
-;; This DBG_VALUE is added by the mem-loc-frag-fill pass because bits [0, 64)
-;; are still live in memory.
-; CHECK-NEXT: DBG_VALUE %stack.0.X, $noreg, ![[VAR]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 64)
-; CHECK-NEXT: DBG_VALUE %stack.0.X, $noreg, ![[VAR]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref, DW_OP_LLVM_fragment, 64, 64), debug-location
+;; No change in variable location: the stack home is still valid.
 
 ;; The final assignment (X.B += 2) doesn't get stored back to the alloca. This
 ;; means that that the stack location isn't valid for the entire lifetime of X.
Index: llvm/test/DebugInfo/assignment-tracking/X86/mem-loc-frag-fill-cfg.ll
===================================================================
--- llvm/test/DebugInfo/assignment-tracking/X86/mem-loc-frag-fill-cfg.ll
+++ llvm/test/DebugInfo/assignment-tracking/X86/mem-loc-frag-fill-cfg.ll
@@ -8,8 +8,8 @@
 ;; Check that the mem-loc-frag-fill pseudo-pass works on a simple CFG. When
 ;; LLVM sees a dbg.value with an overlapping fragment it essentially considers
 ;; the previous location as valid for all bits in that fragment. The pass
-;; inserts dbg.value fragments to preserve memory locations for bits in memory
-;; when overlapping fragments are encountered.
+;; tracks which bits are in memory and inserts dbg.values preserve memory
+;; locations for bits in memory when overlapping fragments are encountered.
 
 ;; nums lives in mem, except prior to the second call to step() where there has
 ;; been some DSE. At this point, the memory loc for nums.c is invalid.  But the
@@ -82,8 +82,9 @@
   call void @llvm.dbg.assign(metadata i32 2, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32), metadata !56, metadata ptr %c, metadata !DIExpression()), !dbg !46
   %call1 = tail call noundef zeroext i1 @_Z4stepv(), !dbg !57
   store i32 1, ptr %c, align 4, !dbg !58, !DIAssignID !61
+;; Store to bits 64 to 96 - the whole variable is in memory again.
 ; CHECK:      MOV32mi %stack.0.nums, 1, $noreg, 8, $noreg, 1
-; CHECK-NEXT: DBG_VALUE %stack.0.nums, $noreg, ![[nums]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref, DW_OP_LLVM_fragment, 64, 32)
+; CHECK-NEXT: DBG_VALUE %stack.0.nums, $noreg, ![[nums]], !DIExpression(DW_OP_deref)
   call void @llvm.dbg.assign(metadata i32 1, metadata !44, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32), metadata !61, metadata ptr %c, metadata !DIExpression()), !dbg !46
   call void @_Z4esc1P4Nums(ptr noundef nonnull %nums), !dbg !62
   ret i32 0, !dbg !64
Index: llvm/test/DebugInfo/assignment-tracking/X86/mem-loc-frag-fill.ll
===================================================================
--- llvm/test/DebugInfo/assignment-tracking/X86/mem-loc-frag-fill.ll
+++ llvm/test/DebugInfo/assignment-tracking/X86/mem-loc-frag-fill.ll
@@ -50,7 +50,7 @@
   store i32 2, ptr %c, align 8, !dbg !25, !DIAssignID !31
 ; CHECK: MOV32mi %stack.0.nums, 1, $noreg, 8, $noreg, 2
   call void @llvm.dbg.assign(metadata i32 2, metadata !12, metadata !DIExpression(DW_OP_LLVM_fragment, 64, 32), metadata !31, metadata ptr %c, metadata !DIExpression()), !dbg !19
-; CHECK-NEXT: DBG_VALUE %stack.0.nums, $noreg, ![[nums]], !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref, DW_OP_LLVM_fragment, 64, 32)
+; CHECK-NEXT: DBG_VALUE %stack.0.nums, $noreg, ![[nums]], !DIExpression(DW_OP_deref)
   tail call void @_Z4stepv(), !dbg !32
 ;; Next dbg.assign added by hand to test that the bits [64, 32) have been
 ;; correctly tracked as in memory - we know this has worked if
Index: llvm/test/DebugInfo/assignment-tracking/X86/nested-loop-frags.ll
===================================================================
--- llvm/test/DebugInfo/assignment-tracking/X86/nested-loop-frags.ll
+++ llvm/test/DebugInfo/assignment-tracking/X86/nested-loop-frags.ll
@@ -122,8 +122,6 @@
 ; CHECK-NEXT:    DBG_VALUE %stack.4.e.addr, $noreg, ![[e]], !DIExpression(DW_OP_deref)
 ; CHECK-NEXT:    MOV64mi32 %stack.0.a.addr, 1, $noreg, 0, $noreg, 1
 ; CHECK-NEXT:    MOV64mi32 %stack.1.b.addr, 1, $noreg, 0, $noreg, 2
-; CHECK-NEXT:    DBG_VALUE %stack.4.e.addr, $noreg, ![[e]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
-; CHECK-NEXT:    DBG_VALUE %stack.4.e.addr, $noreg, ![[e]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32)
 ; CHECK-NEXT:    MOV32mi %stack.0.a.addr, 1, $noreg, 0, $noreg, 3
 ; CHECK-NEXT:    DBG_VALUE $noreg, $noreg, ![[a]], !DIExpression(DW_OP_LLVM_fragment, 0, 32)
 ; CHECK-NEXT:    DBG_VALUE %stack.0.a.addr, $noreg, ![[a]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
@@ -156,7 +154,6 @@
 ; CHECK-LABEL: bb.2.do.body1:
 ; CHECK-NEXT: successors
 ; CHECK-NEXT: {{^ *$}}
-; CxHECK-NEXT:    DBG_VALUE 11, $noreg, ![[f]], !DIExpression(DW_OP_LLVM_fragment, 0, 32)
 ; CHECK:         JMP_1
 ; CHECK-NEXT: {{^ *$}}
 
@@ -174,13 +171,12 @@
 ; CHECK-NEXT: {{^ *$}}
 ; CHECK-NEXT:    %5:gr32 = MOV32rm $rip, 1, $noreg, @g_a, $noreg
 ; CHECK-NEXT:    MOV32mr %stack.1.b.addr, 1, $noreg, 0, $noreg, killed %5
-; CHECK-NEXT:    DBG_VALUE %stack.1.b.addr, $noreg, ![[b]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32)
+; CHECK-NEXT:    DBG_VALUE %stack.1.b.addr, $noreg, ![[b]], !DIExpression(DW_OP_deref)
 ; CHECK-NEXT:    MOV32mi %stack.3.d.addr, 1, $noreg, 0, $noreg, 6
 ; CHECK-NEXT:    DBG_VALUE 8, $noreg, ![[e]], !DIExpression(DW_OP_LLVM_fragment, 32, 32)
 ; CHECK-NEXT:    MOV32mi %stack.4.e.addr, 1, $noreg, 0, $noreg, 8
 ; CHECK-NEXT:    DBG_VALUE %stack.4.e.addr, $noreg, ![[e]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
 ; CHECK-NEXT:    JMP_1 %bb.5
-; CHECxK-NEXT: {{^ *$}}
 
 if.else:                                          ; preds = %do.body1
   store i32 6, ptr %d.addr, !DIAssignID !74 ; VAR:d
Index: llvm/test/DebugInfo/assignment-tracking/X86/use-known-value-at-early-mem-def-2.ll
===================================================================
--- llvm/test/DebugInfo/assignment-tracking/X86/use-known-value-at-early-mem-def-2.ll
+++ llvm/test/DebugInfo/assignment-tracking/X86/use-known-value-at-early-mem-def-2.ll
@@ -18,9 +18,12 @@
 ;; live in memory.
 ; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var]], !DIExpression(DW_OP_plus_uconst, 4, DW_OP_deref, DW_OP_LLVM_fragment, 32, 32)
 
+;; After the call to @d there's a dbg.assign linked to the store to bits 0-32
+;; that comes before it. Meaning the stack location for bits 0-32 are valid
+;; from here (bits 32-64 for the variable are already located in memory).
 ; CHECK: CALL64pcrel32 @d
 ; CHECK-NEXT: ADJCALLSTACKUP64
-; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 32), debug-location
+; CHECK-NEXT: DBG_VALUE %stack.0.c, $noreg, ![[var]], !DIExpression(DW_OP_deref), debug-location
 
 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
 target triple = "x86_64-unknown-linux-gnu"