Index: llvm/lib/Transforms/Scalar/LICM.cpp
===================================================================
--- llvm/lib/Transforms/Scalar/LICM.cpp
+++ llvm/lib/Transforms/Scalar/LICM.cpp
@@ -1824,6 +1824,7 @@
   AAMDNodes AATags;
   ICFLoopSafetyInfo &SafetyInfo;
   bool CanInsertStoresInExitBlocks;
+  ArrayRef<const Instruction *> Uses;
 
   // We're about to add a use of V in a loop exit block.  Insert an LCSSA phi
   // (if legal) if doing so would add an out-of-loop use to an instruction
@@ -1856,7 +1857,7 @@
         PredCache(PIC), MSSAU(MSSAU), LI(li), DL(std::move(dl)),
         Alignment(Alignment), UnorderedAtomic(UnorderedAtomic), AATags(AATags),
         SafetyInfo(SafetyInfo),
-        CanInsertStoresInExitBlocks(CanInsertStoresInExitBlocks) {}
+        CanInsertStoresInExitBlocks(CanInsertStoresInExitBlocks), Uses(Insts) {}
 
   bool isInstInList(Instruction *I,
                     const SmallVectorImpl<Instruction *> &) const override {
@@ -1873,6 +1874,7 @@
     // store of the live-out values that feed them.  Since we've already told
     // the SSA updater about the defs in the loop and the preheader
     // definition, it is all set and we can start using it.
+    DIAssignID *NewID = nullptr;
     for (unsigned i = 0, e = LoopExitBlocks.size(); i != e; ++i) {
       BasicBlock *ExitBlock = LoopExitBlocks[i];
       Value *LiveInValue = SSA.GetValueInMiddleOfBlock(ExitBlock);
@@ -1884,6 +1886,14 @@
         NewSI->setOrdering(AtomicOrdering::Unordered);
       NewSI->setAlignment(Alignment);
       NewSI->setDebugLoc(DL);
+      if (!NewID) {
+        NewSI->mergeDIAssignID(Uses);
+        NewID = cast_or_null<DIAssignID>(
+            NewSI->getMetadata(LLVMContext::MD_DIAssignID));
+      } else {
+        NewSI->setMetadata(LLVMContext::MD_DIAssignID, NewID);
+      }
+
       if (AATags)
         NewSI->setAAMetadata(AATags);
 
Index: llvm/test/DebugInfo/Generic/assignment-tracking/licm/merge.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/Generic/assignment-tracking/licm/merge.ll
@@ -0,0 +1,109 @@
+; RUN: opt -licm %s -S -experimental-assignment-tracking | FileCheck %s
+
+;; Ensure that we correctly merge the DIAssignID's from the sunk stores, add it
+;; to the new new store instruction, and update the dbg.assign intrinsics using
+;; them to use it instead.
+
+;; Generated from the following, with some changes to the IR by hand:
+;; $ cat test.c
+;; void b(int c) {
+;;   esc(&c);
+;;   for (; c;  c++) // NOTE: I've added another store to c in the loop by hand.
+;;   ;
+;; }
+;; $ clang -O2 -Xclang -disable-llvm-passes -g -emit-llvm -S -o a.ll
+;; $ opt -passes=declare-to-assign,sroa,instcombine,simplifycfg,loop-simplify,lcssa,loop-rotate a.ll
+
+; CHECK: for.inc:
+;; Check that the stores have actually been removed from this block, otherwise
+;; this test is useless.
+; CHECK-NOT: store i32 %inc, i32* %c.addr
+;; Check that the two dbg.assigns now have the same (merged) !DIAssingID ID.
+; CHECK: call void @llvm.dbg.assign(metadata i32 %inc, metadata ![[VAR_C:[0-9]+]], metadata !DIExpression(), metadata ![[ID:[0-9]+]], metadata i32* %c.addr, metadata !DIExpression()), !dbg
+; CHECK-NOT: store i32 %inc, i32* %c.addr
+; CHECK: call void @llvm.dbg.assign(metadata i32 %inc, metadata ![[VAR_C]], metadata !DIExpression(), metadata ![[ID]], metadata i32* %c.addr, metadata !DIExpression()), !dbg
+
+; CHECK: for.cond.for.end_crit_edge:
+; CHECK-NEXT: %[[PHI:.*]] = phi i32 [ %inc, %for.inc ]
+; CHECK-NEXT: store i32 %[[PHI]], i32* %c.addr{{.*}}, !DIAssignID ![[ID]]
+; CHECK-NOT:  {{.*}}llvm.dbg{{.*}}
+; CHECK-NEXT: br label %for.end
+
+; CHECK: ![[VAR_C]] = !DILocalVariable(name: "c",
+
+define dso_local void @b(i32 %c) !dbg !7 {
+entry:
+  %c.addr = alloca i32, align 4
+  store i32 %c, i32* %c.addr, align 4, !tbaa !14, !DIAssignID !36
+  call void @llvm.dbg.assign(metadata i32 %c, metadata !12, metadata !DIExpression(), metadata !36, metadata i32* %c.addr, metadata !DIExpression()), !dbg !13
+  call void @esc(i32* nonnull %c.addr), !dbg !18
+  %0 = load i32, i32* %c.addr, align 4, !dbg !19, !tbaa !14
+  %tobool.not1 = icmp eq i32 %0, 0, !dbg !22
+  br i1 %tobool.not1, label %for.end, label %for.inc.lr.ph, !dbg !22
+
+for.inc.lr.ph:                                    ; preds = %entry
+  br label %for.inc, !dbg !22
+
+for.inc:                                          ; preds = %for.inc.lr.ph, %for.inc
+  %1 = load i32, i32* %c.addr, align 4, !dbg !23, !tbaa !14
+  %inc = add nsw i32 %1, 1, !dbg !23
+  store i32 %inc, i32* %c.addr, align 4, !dbg !23, !tbaa !14, !DIAssignID !38
+  call void @llvm.dbg.assign(metadata i32 %inc, metadata !12, metadata !DIExpression(), metadata !38, metadata i32* %c.addr, metadata !DIExpression()), !dbg !13
+  ;; The following store and dbg.assign intrinsics are copies of those above,
+  ;; with a new DIAssignID.
+  store i32 %inc, i32* %c.addr, align 4, !dbg !23, !tbaa !14, !DIAssignID !37
+  call void @llvm.dbg.assign(metadata i32 %inc, metadata !12, metadata !DIExpression(), metadata !37, metadata i32* %c.addr, metadata !DIExpression()), !dbg !13
+  %2 = load i32, i32* %c.addr, align 4, !dbg !19, !tbaa !14
+  %tobool.not = icmp eq i32 %2, 0, !dbg !22
+  br i1 %tobool.not, label %for.cond.for.end_crit_edge, label %for.inc, !dbg !22, !llvm.loop !24
+
+for.cond.for.end_crit_edge:                       ; preds = %for.inc
+  br label %for.end, !dbg !22
+
+for.end:                                          ; preds = %for.cond.for.end_crit_edge, %entry
+  ret void, !dbg !27
+}
+
+
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata)
+declare !dbg !28 dso_local void @esc(i32*)
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!3, !4, !5}
+!llvm.ident = !{!6}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None)
+!1 = !DIFile(filename: "test.c", directory: "/")
+!2 = !{}
+!3 = !{i32 7, !"Dwarf Version", i32 4}
+!4 = !{i32 2, !"Debug Info Version", i32 3}
+!5 = !{i32 1, !"wchar_size", i32 4}
+!6 = !{!"clang version 12.0.0"}
+!7 = distinct !DISubprogram(name: "b", scope: !1, file: !1, line: 2, type: !8, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !11)
+!8 = !DISubroutineType(types: !9)
+!9 = !{null, !10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !{!12}
+!12 = !DILocalVariable(name: "c", arg: 1, scope: !7, file: !1, line: 2, type: !10)
+!13 = !DILocation(line: 0, scope: !7)
+!14 = !{!15, !15, i64 0}
+!15 = !{!"int", !16, i64 0}
+!16 = !{!"omnipotent char", !17, i64 0}
+!17 = !{!"Simple C/C++ TBAA"}
+!18 = !DILocation(line: 3, column: 3, scope: !7)
+!19 = !DILocation(line: 4, column: 10, scope: !20)
+!20 = distinct !DILexicalBlock(scope: !21, file: !1, line: 4, column: 3)
+!21 = distinct !DILexicalBlock(scope: !7, file: !1, line: 4, column: 3)
+!22 = !DILocation(line: 4, column: 3, scope: !21)
+!23 = !DILocation(line: 4, column: 15, scope: !20)
+!24 = distinct !{!24, !22, !25, !26}
+!25 = !DILocation(line: 5, column: 3, scope: !21)
+!26 = !{!"llvm.loop.mustprogress"}
+!27 = !DILocation(line: 6, column: 1, scope: !7)
+!28 = !DISubprogram(name: "esc", scope: !1, file: !1, line: 1, type: !29, flags: DIFlagPrototyped, spFlags: DISPFlagOptimized, retainedNodes: !2)
+!29 = !DISubroutineType(types: !30)
+!30 = !{null, !31}
+!31 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !10, size: 64)
+!36 = distinct !DIAssignID()
+!37 = distinct !DIAssignID()
+!38 = distinct !DIAssignID()
Index: llvm/test/DebugInfo/Generic/assignment-tracking/licm/multi-exit.ll
===================================================================
--- /dev/null
+++ llvm/test/DebugInfo/Generic/assignment-tracking/licm/multi-exit.ll
@@ -0,0 +1,170 @@
+; RUN: opt %s -S -licm -o - -experimental-assignment-tracking | FileCheck %s
+
+;; $ cat test.c
+;; int b, c, d;
+;; void e();
+;; void f(int *g) { *g = b; }
+;; void i() {
+;;   int h, a;
+;;   for (;;) {
+;;     e();
+;;     a = 1;
+;;     if (h) {
+;;       if (d)
+;;         continue;
+;;       h = c;
+;;     }
+;;     f(&a);
+;;   }
+;; }
+;; Generated by getting the IR before LICM in:
+;; $ clang  -c  -O2 -g  test.c -fno-unroll-loops -fno-vectorize -fno-inline -Xclang -fexperimental-assignment-tracking -o -
+;;
+;; Check that a store sunk into multiple exits retains its (their) dbg.assign,
+;; and that the new stores share the same DIAssignID.
+
+; CHECK: for.cond:
+; CHECK: call void @llvm.dbg.assign(metadata i32 1, metadata ![[var:[0-9]+]], metadata !DIExpression(), metadata ![[id:[0-9]+]], metadata i32* %a, metadata !DIExpression()), !dbg !38
+
+; CHECK: if.end:
+; CHECK-NEXT: store i32 1, i32* %a, align 1,{{.*}}!DIAssignID ![[id]]
+
+; CHECK: if.end3.loopexit:
+; CHECK-NEXT: store i32 1, i32* %a, align 1,{{.*}}!DIAssignID ![[id]]
+
+; CHECK-DAG: ![[var]] = !DILocalVariable(name: "a",
+
+@b = dso_local local_unnamed_addr global i32 0, align 4, !dbg !0
+@d = dso_local local_unnamed_addr global i32 0, align 4, !dbg !9
+@c = dso_local local_unnamed_addr global i32 0, align 4, !dbg !6
+
+; Function Attrs: nofree noinline norecurse nounwind uwtable
+define dso_local void @f(i32* nocapture %g) local_unnamed_addr #0 !dbg !15 {
+entry:
+  call void @llvm.dbg.assign(metadata i1 undef, metadata !20, metadata !DIExpression(), metadata !21, metadata i32** undef, metadata !DIExpression()), !dbg !22
+  call void @llvm.dbg.assign(metadata i32* %g, metadata !20, metadata !DIExpression(), metadata !23, metadata i32** undef, metadata !DIExpression()), !dbg !22
+  %0 = load i32, i32* @b, align 4, !dbg !24, !tbaa !25
+  store i32 %0, i32* %g, align 4, !dbg !29, !tbaa !25
+  ret void, !dbg !30
+}
+
+; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
+declare void @llvm.dbg.assign(metadata, metadata, metadata, metadata, metadata, metadata) #1
+
+; Function Attrs: noinline noreturn nounwind uwtable
+define dso_local void @i() local_unnamed_addr #2 !dbg !31 {
+entry:
+  call void @llvm.dbg.assign(metadata i1 undef, metadata !35, metadata !DIExpression(), metadata !37, metadata i32* undef, metadata !DIExpression()), !dbg !38
+  %a = alloca i32, align 4, !DIAssignID !39
+  call void @llvm.dbg.assign(metadata i1 undef, metadata !36, metadata !DIExpression(), metadata !39, metadata i32* %a, metadata !DIExpression()), !dbg !38
+  %0 = bitcast i32* %a to i8*, !dbg !40
+  call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %0) #5, !dbg !40
+  br label %for.cond.outer, !dbg !41
+
+for.cond.outer:                                   ; preds = %if.end3, %entry
+  %h.0.ph = phi i32 [ %h.1, %if.end3 ], [ undef, %entry ]
+  br label %for.cond, !dbg !42
+
+for.cond:                                         ; preds = %for.cond.outer, %if.then
+  call void @llvm.dbg.value(metadata i32 %h.0.ph, metadata !35, metadata !DIExpression()), !dbg !38
+  tail call void (...) @e() #5, !dbg !44
+  store i32 1, i32* %a, align 4, !dbg !47, !tbaa !25, !DIAssignID !48
+  call void @llvm.dbg.assign(metadata i32 1, metadata !36, metadata !DIExpression(), metadata !48, metadata i32* %a, metadata !DIExpression()), !dbg !38
+  %tobool.not = icmp eq i32 %h.0.ph, 0, !dbg !49
+  br i1 %tobool.not, label %if.end3.loopexit, label %if.then, !dbg !51
+
+if.then:                                          ; preds = %for.cond
+  %1 = load i32, i32* @d, align 4, !dbg !52, !tbaa !25
+  %tobool1.not = icmp eq i32 %1, 0, !dbg !52
+  br i1 %tobool1.not, label %if.end, label %for.cond, !dbg !55, !llvm.loop !56
+
+if.end:                                           ; preds = %if.then
+  %2 = load i32, i32* @c, align 4, !dbg !59, !tbaa !25
+  call void @llvm.dbg.assign(metadata i32 %2, metadata !35, metadata !DIExpression(), metadata !60, metadata i32* undef, metadata !DIExpression()), !dbg !38
+  br label %if.end3, !dbg !61
+
+if.end3.loopexit:                                 ; preds = %for.cond
+  br label %if.end3, !dbg !62
+
+if.end3:                                          ; preds = %if.end3.loopexit, %if.end
+  %h.1 = phi i32 [ %2, %if.end ], [ 0, %if.end3.loopexit ]
+  call void @llvm.dbg.value(metadata i32 %h.1, metadata !35, metadata !DIExpression()), !dbg !38
+  call void @f(i32* nonnull %a), !dbg !62
+  br label %for.cond.outer, !dbg !63, !llvm.loop !56
+}
+
+declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #3
+declare !dbg !64 dso_local void @e(...) local_unnamed_addr #4
+declare void @llvm.dbg.value(metadata, metadata, metadata) #1
+
+!llvm.dbg.cu = !{!2}
+!llvm.module.flags = !{!11, !12, !13}
+!llvm.ident = !{!14}
+
+!0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression())
+!1 = distinct !DIGlobalVariable(name: "b", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 12.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5, splitDebugInlining: false, nameTableKind: None)
+!3 = !DIFile(filename: "test.c", directory: "/")
+!4 = !{}
+!5 = !{!0, !6, !9}
+!6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression())
+!7 = distinct !DIGlobalVariable(name: "c", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!8 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!9 = !DIGlobalVariableExpression(var: !10, expr: !DIExpression())
+!10 = distinct !DIGlobalVariable(name: "d", scope: !2, file: !3, line: 1, type: !8, isLocal: false, isDefinition: true)
+!11 = !{i32 7, !"Dwarf Version", i32 4}
+!12 = !{i32 2, !"Debug Info Version", i32 3}
+!13 = !{i32 1, !"wchar_size", i32 4}
+!14 = !{!"clang version 12.0.0 (https://github.sie.sony.com/gbhyamso/coffee-chat.git 86b8b3e1d2bad2da3b3f53c6366fec9eb5d91a36)"}
+!15 = distinct !DISubprogram(name: "f", scope: !3, file: !3, line: 3, type: !16, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !19)
+!16 = !DISubroutineType(types: !17)
+!17 = !{null, !18}
+!18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !8, size: 64)
+!19 = !{!20}
+!20 = !DILocalVariable(name: "g", arg: 1, scope: !15, file: !3, line: 3, type: !18)
+!21 = distinct !DIAssignID()
+!22 = !DILocation(line: 0, scope: !15)
+!23 = distinct !DIAssignID()
+!24 = !DILocation(line: 3, column: 23, scope: !15)
+!25 = !{!26, !26, i64 0}
+!26 = !{!"int", !27, i64 0}
+!27 = !{!"omnipotent char", !28, i64 0}
+!28 = !{!"Simple C/C++ TBAA"}
+!29 = !DILocation(line: 3, column: 21, scope: !15)
+!30 = !DILocation(line: 3, column: 26, scope: !15)
+!31 = distinct !DISubprogram(name: "i", scope: !3, file: !3, line: 4, type: !32, scopeLine: 4, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !2, retainedNodes: !34)
+!32 = !DISubroutineType(types: !33)
+!33 = !{null}
+!34 = !{!35, !36}
+!35 = !DILocalVariable(name: "h", scope: !31, file: !3, line: 5, type: !8)
+!36 = !DILocalVariable(name: "a", scope: !31, file: !3, line: 5, type: !8)
+!37 = distinct !DIAssignID()
+!38 = !DILocation(line: 0, scope: !31)
+!39 = distinct !DIAssignID()
+!40 = !DILocation(line: 5, column: 3, scope: !31)
+!41 = !DILocation(line: 6, column: 3, scope: !31)
+!42 = !DILocation(line: 6, column: 3, scope: !43)
+!43 = distinct !DILexicalBlock(scope: !31, file: !3, line: 6, column: 3)
+!44 = !DILocation(line: 7, column: 5, scope: !45)
+!45 = distinct !DILexicalBlock(scope: !46, file: !3, line: 6, column: 12)
+!46 = distinct !DILexicalBlock(scope: !43, file: !3, line: 6, column: 3)
+!47 = !DILocation(line: 8, column: 7, scope: !45)
+!48 = distinct !DIAssignID()
+!49 = !DILocation(line: 9, column: 9, scope: !50)
+!50 = distinct !DILexicalBlock(scope: !45, file: !3, line: 9, column: 9)
+!51 = !DILocation(line: 9, column: 9, scope: !45)
+!52 = !DILocation(line: 10, column: 11, scope: !53)
+!53 = distinct !DILexicalBlock(scope: !54, file: !3, line: 10, column: 11)
+!54 = distinct !DILexicalBlock(scope: !50, file: !3, line: 9, column: 12)
+!55 = !DILocation(line: 10, column: 11, scope: !54)
+!56 = distinct !{!56, !42, !57, !58}
+!57 = !DILocation(line: 15, column: 3, scope: !43)
+!58 = !{!"llvm.loop.unroll.disable"}
+!59 = !DILocation(line: 12, column: 11, scope: !54)
+!60 = distinct !DIAssignID()
+!61 = !DILocation(line: 13, column: 5, scope: !54)
+!62 = !DILocation(line: 14, column: 5, scope: !45)
+!63 = !DILocation(line: 6, column: 3, scope: !46)
+!64 = !DISubprogram(name: "e", scope: !3, file: !3, line: 2, type: !65, spFlags: DISPFlagOptimized, retainedNodes: !4)
+!65 = !DISubroutineType(types: !66)
+!66 = !{null, null}