https://github.com/OCHyams updated 
https://github.com/llvm/llvm-project/pull/134641

>From ae032c5dd3537662508d77bbb447808f52481f5d Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 1 Apr 2025 11:59:24 +0100
Subject: [PATCH 01/33] [KeyInstr][Clang] Add ApplyAtomGroup

This is a scoped helper similar to ApplyDebugLocation that creates a new source
atom group which instructions can be added to.

A source atom is a source construct that is "interesting" for debug stepping
purposes. We use an atom group number to track the instruction(s) that implement
the functionality for the atom, plus backup instructions/source locations.

---

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGDebugInfo.cpp   | 119 +++++++++++++++++++++++++++-
 clang/lib/CodeGen/CGDebugInfo.h     |  50 ++++++++++++
 clang/lib/CodeGen/CodeGenFunction.h |  14 ++++
 3 files changed, 182 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index 2a11eebf1b682..f4c5c57a38b3e 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -43,6 +43,7 @@
 #include "llvm/IR/Constants.h"
 #include "llvm/IR/DataLayout.h"
 #include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/Metadata.h"
@@ -52,6 +53,7 @@
 #include "llvm/Support/SHA1.h"
 #include "llvm/Support/SHA256.h"
 #include "llvm/Support/TimeProfiler.h"
+#include <cstdint>
 #include <optional>
 using namespace clang;
 using namespace clang::CodeGen;
@@ -119,6 +121,114 @@ CGDebugInfo::~CGDebugInfo() {
          "Region stack mismatch, stack not empty!");
 }
 
+void CGDebugInfo::addInstSourceAtomMetadata(llvm::Instruction *I,
+                                            uint64_t Group, uint8_t Rank) {
+  if (!I->getDebugLoc() || Group == 0 || !I->getDebugLoc()->getLine())
+    return;
+
+  // Saturate the 3-bit rank.
+  Rank = std::min<uint8_t>(Rank, 7);
+
+  const llvm::DebugLoc &DL = I->getDebugLoc();
+
+  // Each instruction can only be attributed to one source atom (a limitation 
of
+  // the implementation). If this instruction is already part of a source atom,
+  // pick the group in which it has highest precedence (lowest rank).
+  if (DL.get()->getAtomGroup() && DL.get()->getAtomRank() &&
+      DL.get()->getAtomRank() < Rank) {
+    Group = DL.get()->getAtomGroup();
+    Rank = DL.get()->getAtomRank();
+  }
+
+  // Update the function-local watermark so we don't reuse this number for
+  // another atom.
+  KeyInstructionsInfo.HighestEmittedAtom =
+      std::max(Group, KeyInstructionsInfo.HighestEmittedAtom);
+
+  // Apply the new DILocation to the instruction.
+  llvm::DILocation *NewDL = llvm::DILocation::get(
+      I->getContext(), DL.getLine(), DL.getCol(), DL.getScope(),
+      DL.getInlinedAt(), DL.isImplicitCode(), Group, Rank);
+  I->setDebugLoc(NewDL);
+};
+
+void CGDebugInfo::addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
+                                             llvm::Value *Backup) {
+  if (!CGM.getCodeGenOpts().DebugKeyInstructions)
+    return;
+
+  uint64_t Group = KeyInstructionsInfo.CurrentAtom;
+  if (!Group)
+    return;
+
+  addInstSourceAtomMetadata(KeyInstruction, Group, /*Rank=*/1);
+
+  llvm::Instruction *BackupI =
+      llvm::dyn_cast_or_null<llvm::Instruction>(Backup);
+  if (!BackupI)
+    return;
+
+  // Add the backup instruction to the group.
+  addInstSourceAtomMetadata(BackupI, Group, /*Rank=*/2);
+
+  // Look through chains of casts too, as they're probably going to evaporate.
+  // FIXME: And other nops like zero length geps?
+  // FIXME: Should use Cast->isNoopCast()?
+  uint8_t Rank = 3;
+  while (auto *Cast = dyn_cast<llvm::CastInst>(BackupI)) {
+    BackupI = dyn_cast<llvm::Instruction>(Cast->getOperand(0));
+    if (!BackupI)
+      break;
+    addInstSourceAtomMetadata(BackupI, Group, Rank++);
+  }
+}
+
+void CGDebugInfo::addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
+                                                  llvm::Value *Backup) {
+  if (KeyInstructionsInfo.RetAtomOverride) {
+    uint64_t CurrentAtom = KeyInstructionsInfo.CurrentAtom;
+    KeyInstructionsInfo.CurrentAtom = KeyInstructionsInfo.RetAtomOverride;
+    addInstToCurrentSourceAtom(Ret, Backup);
+    KeyInstructionsInfo.CurrentAtom = CurrentAtom;
+    KeyInstructionsInfo.RetAtomOverride = 0;
+  } else {
+    auto Grp = ApplyAtomGroup(this);
+    addInstToCurrentSourceAtom(Ret, Backup);
+  }
+}
+
+void CGDebugInfo::setRetInstSourceAtomOverride(uint64_t Group) {
+  assert(KeyInstructionsInfo.RetAtomOverride == 0);
+  KeyInstructionsInfo.RetAtomOverride = Group;
+}
+
+void CGDebugInfo::completeFunction() {
+  // Reset the atom group number tracker as the numbers are function-local.
+  KeyInstructionsInfo.NextAtom = 1;
+  KeyInstructionsInfo.HighestEmittedAtom = 0;
+  KeyInstructionsInfo.CurrentAtom = 0;
+  KeyInstructionsInfo.RetAtomOverride = 0;
+}
+
+ApplyAtomGroup::ApplyAtomGroup(CGDebugInfo *DI) : DI(DI) {
+  if (!DI)
+    return;
+  OriginalAtom = DI->KeyInstructionsInfo.CurrentAtom;
+  DI->KeyInstructionsInfo.CurrentAtom = DI->KeyInstructionsInfo.NextAtom++;
+}
+
+ApplyAtomGroup::~ApplyAtomGroup() {
+  if (!DI)
+    return;
+
+  // We may not have used the group number at all.
+  DI->KeyInstructionsInfo.NextAtom =
+      std::min(DI->KeyInstructionsInfo.HighestEmittedAtom + 1,
+               DI->KeyInstructionsInfo.NextAtom);
+
+  DI->KeyInstructionsInfo.CurrentAtom = OriginalAtom;
+}
+
 ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
                                        SourceLocation TemporaryLocation)
     : CGF(&CGF) {
@@ -174,8 +284,15 @@ ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction 
&CGF, llvm::DebugLoc Loc)
     return;
   }
   OriginalLocation = CGF.Builder.getCurrentDebugLocation();
-  if (Loc)
+  if (Loc) {
+    // Key Instructions: drop the atom group and rank to avoid accidentally
+    // propagating it around.
+    if (Loc->getAtomGroup())
+      Loc = llvm::DILocation::get(Loc->getContext(), Loc.getLine(),
+                                  Loc->getColumn(), Loc->getScope(),
+                                  Loc->getInlinedAt(), Loc.isImplicitCode());
     CGF.Builder.SetCurrentDebugLocation(std::move(Loc));
+  }
 }
 
 ApplyDebugLocation::~ApplyDebugLocation() {
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index b287ce7b92eee..d9081d9bb3ffb 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -58,6 +58,8 @@ class CGBlockInfo;
 class CGDebugInfo {
   friend class ApplyDebugLocation;
   friend class SaveAndRestoreLocation;
+  friend class ApplyAtomGroup;
+
   CodeGenModule &CGM;
   const llvm::codegenoptions::DebugInfoKind DebugKind;
   bool DebugTypeExtRefs;
@@ -179,6 +181,17 @@ class CGDebugInfo {
   /// The key is coroutine real parameters, value is DIVariable in LLVM IR.
   Param2DILocTy ParamDbgMappings;
 
+  /// Key Instructions bookkeeping.
+  /// Source atoms are identified by a {AtomGroup, InlinedAt} pair, meaning
+  /// AtomGroup numbers can be repeated across different functions.
+  struct {
+    uint64_t NextAtom = 1;
+    uint64_t HighestEmittedAtom = 0;
+    uint64_t CurrentAtom = 0;
+    uint64_t RetAtomOverride = 0;
+  } KeyInstructionsInfo;
+
+private:
   /// Helper functions for getOrCreateType.
   /// @{
   /// Currently the checksum of an interface includes the number of
@@ -643,7 +656,30 @@ class CGDebugInfo {
   llvm::DILocation *CreateSyntheticInlineAt(llvm::DebugLoc Location,
                                             StringRef FuncName);
 
+  /// Reset internal state.
+  void completeFunction();
+
+  /// Add \p KeyInstruction and an optional \p Backup instruction to the
+  /// current atom group, created using ApplyAtomGroup.
+  void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
+                                  llvm::Value *Backup);
+
+  /// Add \p Ret and an optional \p Backup instruction to the
+  /// saved override used for some ret instructions if it exists, or a new 
atom.
+  void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
+                                       llvm::Value *Backup);
+
+  /// Set an atom group override for use in addRetToOverrideOrNewSourceAtom.
+  void setRetInstSourceAtomOverride(uint64_t Group);
+
 private:
+  /// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
+  /// Rank (lower nonzero rank is higher precedence). Does nothing if \p I
+  /// has no DebugLoc, and chooses the atom group in which the instruction
+  /// has the highest precedence if it's already in one.
+  void addInstSourceAtomMetadata(llvm::Instruction *I, uint64_t Group,
+                                 uint8_t Rank);
+
   /// Emit call to llvm.dbg.declare for a variable declaration.
   /// Returns a pointer to the DILocalVariable associated with the
   /// llvm.dbg.declare, or nullptr otherwise.
@@ -860,6 +896,20 @@ class CGDebugInfo {
   }
 };
 
+/// A scoped helper to set the current source atom group for
+/// CGDebugInfo::addInstToCurrentSourceAtom. A source atom is a source 
construct
+/// that is "interesting" for debug stepping purposes. We use an atom group
+/// number to track the instruction(s) that implement the functionality for the
+/// atom, plus backup instructions/source locations.
+class ApplyAtomGroup {
+  uint64_t OriginalAtom = 0;
+  CGDebugInfo *DI = nullptr;
+
+public:
+  ApplyAtomGroup(CGDebugInfo *DI);
+  ~ApplyAtomGroup();
+};
+
 /// A scoped helper to set the current debug location to the specified
 /// location or preferred location of the specified Expr.
 class ApplyDebugLocation {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 603e38d763aa4..aec29d4ea61e8 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1740,6 +1740,20 @@ class CodeGenFunction : public CodeGenTypeCache {
   /// recently incremented counter.
   uint64_t getCurrentProfileCount() { return PGO.getCurrentRegionCount(); }
 
+  /// See CGDebugInfo::addInstToCurrentSourceAtom.
+  void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
+                                  llvm::Value *Backup) {
+    if (CGDebugInfo *DI = getDebugInfo())
+      DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
+  }
+
+  /// See CGDebugInfo::addRetToOverrideOrNewSourceAtom.
+  void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
+                                       llvm::Value *Backup) {
+    if (CGDebugInfo *DI = getDebugInfo())
+      DI->addRetToOverrideOrNewSourceAtom(Ret, Backup);
+  }
+
 private:
   /// SwitchInsn - This is nearest current switch instruction. It is null if
   /// current context is not in a switch.

>From 69995e53f547279c887b498a6597043a1d4a8be5 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 20 May 2025 17:09:56 +0100
Subject: [PATCH 02/33] fix rebase fallout (CGDebugInfo.h removed from this
 header)

---
 clang/lib/CodeGen/CodeGenFunction.cpp | 12 ++++++++++++
 clang/lib/CodeGen/CodeGenFunction.h   | 10 ++--------
 2 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index 4e79cdf0ef089..092346b627e6a 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -3326,3 +3326,15 @@ CodeGenFunction::EmitPointerAuthAuth(const 
CGPointerAuthInfo &PointerAuth,
   return EmitPointerAuthCommon(*this, PointerAuth, Pointer,
                                llvm::Intrinsic::ptrauth_auth);
 }
+
+void CodeGenFunction::addInstToCurrentSourceAtom(
+    llvm::Instruction *KeyInstruction, llvm::Value *Backup) {
+  if (CGDebugInfo *DI = getDebugInfo())
+    DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
+}
+
+void CodeGenFunction::addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
+                                                      llvm::Value *Backup) {
+  if (CGDebugInfo *DI = getDebugInfo())
+    DI->addRetToOverrideOrNewSourceAtom(Ret, Backup);
+}
\ No newline at end of file
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index aec29d4ea61e8..ecd0362dd6f15 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1742,17 +1742,11 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   /// See CGDebugInfo::addInstToCurrentSourceAtom.
   void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
-                                  llvm::Value *Backup) {
-    if (CGDebugInfo *DI = getDebugInfo())
-      DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
-  }
+                                  llvm::Value *Backup);
 
   /// See CGDebugInfo::addRetToOverrideOrNewSourceAtom.
   void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
-                                       llvm::Value *Backup) {
-    if (CGDebugInfo *DI = getDebugInfo())
-      DI->addRetToOverrideOrNewSourceAtom(Ret, Backup);
-  }
+                                       llvm::Value *Backup);
 
 private:
   /// SwitchInsn - This is nearest current switch instruction. It is null if

>From 8e7f643e9d6bef7a54f48c33c7938611fe86d497 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 20 May 2025 17:38:29 +0100
Subject: [PATCH 03/33] replace the ret-override mechanisms with
 addInstToSpecificSourceAtom

---
 clang/lib/CodeGen/CGDebugInfo.cpp     | 31 ++++++---------------------
 clang/lib/CodeGen/CGDebugInfo.h       | 12 ++++-------
 clang/lib/CodeGen/CodeGenFunction.cpp |  6 +++---
 clang/lib/CodeGen/CodeGenFunction.h   |  6 +++---
 4 files changed, 17 insertions(+), 38 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp 
b/clang/lib/CodeGen/CGDebugInfo.cpp
index f4c5c57a38b3e..1cc2c55a19f11 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -154,11 +154,14 @@ void 
CGDebugInfo::addInstSourceAtomMetadata(llvm::Instruction *I,
 
 void CGDebugInfo::addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
                                              llvm::Value *Backup) {
-  if (!CGM.getCodeGenOpts().DebugKeyInstructions)
-    return;
+  addInstToSpecificSourceAtom(KeyInstruction, Backup,
+                              KeyInstructionsInfo.CurrentAtom);
+}
 
-  uint64_t Group = KeyInstructionsInfo.CurrentAtom;
-  if (!Group)
+void CGDebugInfo::addInstToSpecificSourceAtom(llvm::Instruction 
*KeyInstruction,
+                                              llvm::Value *Backup,
+                                              uint64_t Group) {
+  if (!Group || !CGM.getCodeGenOpts().DebugKeyInstructions)
     return;
 
   addInstSourceAtomMetadata(KeyInstruction, Group, /*Rank=*/1);
@@ -183,31 +186,11 @@ void 
CGDebugInfo::addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
   }
 }
 
-void CGDebugInfo::addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
-                                                  llvm::Value *Backup) {
-  if (KeyInstructionsInfo.RetAtomOverride) {
-    uint64_t CurrentAtom = KeyInstructionsInfo.CurrentAtom;
-    KeyInstructionsInfo.CurrentAtom = KeyInstructionsInfo.RetAtomOverride;
-    addInstToCurrentSourceAtom(Ret, Backup);
-    KeyInstructionsInfo.CurrentAtom = CurrentAtom;
-    KeyInstructionsInfo.RetAtomOverride = 0;
-  } else {
-    auto Grp = ApplyAtomGroup(this);
-    addInstToCurrentSourceAtom(Ret, Backup);
-  }
-}
-
-void CGDebugInfo::setRetInstSourceAtomOverride(uint64_t Group) {
-  assert(KeyInstructionsInfo.RetAtomOverride == 0);
-  KeyInstructionsInfo.RetAtomOverride = Group;
-}
-
 void CGDebugInfo::completeFunction() {
   // Reset the atom group number tracker as the numbers are function-local.
   KeyInstructionsInfo.NextAtom = 1;
   KeyInstructionsInfo.HighestEmittedAtom = 0;
   KeyInstructionsInfo.CurrentAtom = 0;
-  KeyInstructionsInfo.RetAtomOverride = 0;
 }
 
 ApplyAtomGroup::ApplyAtomGroup(CGDebugInfo *DI) : DI(DI) {
diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index d9081d9bb3ffb..10739194fd70f 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -188,7 +188,6 @@ class CGDebugInfo {
     uint64_t NextAtom = 1;
     uint64_t HighestEmittedAtom = 0;
     uint64_t CurrentAtom = 0;
-    uint64_t RetAtomOverride = 0;
   } KeyInstructionsInfo;
 
 private:
@@ -664,13 +663,10 @@ class CGDebugInfo {
   void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
                                   llvm::Value *Backup);
 
-  /// Add \p Ret and an optional \p Backup instruction to the
-  /// saved override used for some ret instructions if it exists, or a new 
atom.
-  void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
-                                       llvm::Value *Backup);
-
-  /// Set an atom group override for use in addRetToOverrideOrNewSourceAtom.
-  void setRetInstSourceAtomOverride(uint64_t Group);
+  /// Add \p KeyInstruction and an optional \p Backup instruction to the atom
+  /// group \p Atom.
+  void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
+                                   llvm::Value *Backup, uint64_t Atom);
 
 private:
   /// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index 092346b627e6a..30bcf782c71e4 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -3333,8 +3333,8 @@ void CodeGenFunction::addInstToCurrentSourceAtom(
     DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
 }
 
-void CodeGenFunction::addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
-                                                      llvm::Value *Backup) {
+void CodeGenFunction::addInstToSpecificSourceAtom(
+    llvm::Instruction *KeyInstruction, llvm::Value *Backup, uint64_t Atom) {
   if (CGDebugInfo *DI = getDebugInfo())
-    DI->addRetToOverrideOrNewSourceAtom(Ret, Backup);
+    DI->addInstToSpecificSourceAtom(KeyInstruction, Backup, Atom);
 }
\ No newline at end of file
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index ecd0362dd6f15..1743f558b37e9 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1744,9 +1744,9 @@ class CodeGenFunction : public CodeGenTypeCache {
   void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
                                   llvm::Value *Backup);
 
-  /// See CGDebugInfo::addRetToOverrideOrNewSourceAtom.
-  void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
-                                       llvm::Value *Backup);
+  /// See CGDebugInfo::addInstToSpecificSourceAtom.
+  void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
+                                   llvm::Value *Backup, uint64_t Atom);
 
 private:
   /// SwitchInsn - This is nearest current switch instruction. It is null if

>From ca03a49ab660472728ea3b3e951bf319b8f24f92 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 20 May 2025 17:43:23 +0100
Subject: [PATCH 04/33] whitespace

---
 clang/lib/CodeGen/CodeGenFunction.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index 30bcf782c71e4..2256cc08e2212 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -3337,4 +3337,4 @@ void CodeGenFunction::addInstToSpecificSourceAtom(
     llvm::Instruction *KeyInstruction, llvm::Value *Backup, uint64_t Atom) {
   if (CGDebugInfo *DI = getDebugInfo())
     DI->addInstToSpecificSourceAtom(KeyInstruction, Backup, Atom);
-}
\ No newline at end of file
+}

>From 8534d6e34772867640665bfa3ad3547babd1a12d Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 1 Apr 2025 14:50:41 +0100
Subject: [PATCH 05/33] [KeyInstr][Clang] Scalar init atom

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGDecl.cpp                  |  1 +
 clang/lib/CodeGen/CGExpr.cpp                  |  2 ++
 .../DebugInfo/KeyInstructions/init-scalar.c   | 19 +++++++++++++++++++
 3 files changed, 22 insertions(+)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/init-scalar.c

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 4a8f7f6a42ecb..d02f2ad09d2f1 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1925,6 +1925,7 @@ void CodeGenFunction::EmitAutoVarInit(const 
AutoVarEmission &emission) {
 
   const VarDecl &D = *emission.Variable;
   auto DL = ApplyDebugLocation::CreateDefaultArtificial(*this, 
D.getLocation());
+  ApplyAtomGroup Grp(getDebugInfo());
   QualType type = D.getType();
 
   // If this local has an initializer, emit it now.
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 708002a7f9ab3..1e426586620a2 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -2222,6 +2222,8 @@ void CodeGenFunction::EmitStoreOfScalar(llvm::Value 
*Value, Address Addr,
   }
 
   llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
+  addInstToCurrentSourceAtom(Store, Value);
+
   if (isNontemporal) {
     llvm::MDNode *Node =
         llvm::MDNode::get(Store->getContext(),
diff --git a/clang/test/DebugInfo/KeyInstructions/init-scalar.c 
b/clang/test/DebugInfo/KeyInstructions/init-scalar.c
new file mode 100644
index 0000000000000..c212c2a4fd623
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/init-scalar.c
@@ -0,0 +1,19 @@
+// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+void a() {
+// CHECK: store i32 0, ptr %A{{.*}}, !dbg [[G1R1:!.*]]
+    int A = 0;
+// CHECK: %add = add {{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: store i32 %add, ptr %B, align 4, !dbg [[G2R1:!.*]]
+    int B = 2 * A + 1;
+// CHECK-TODO: ret{{.*}}, !dbg [[G3R1:!.*]]
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK-TODO: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)

>From 2935186830de115687e4841e0d4c3fba4161a177 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 10:21:18 +0100
Subject: [PATCH 06/33] use %clang_cc1 in test

---
 clang/test/DebugInfo/KeyInstructions/init-scalar.c | 6 ++----
 1 file changed, 2 insertions(+), 4 deletions(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/init-scalar.c 
b/clang/test/DebugInfo/KeyInstructions/init-scalar.c
index c212c2a4fd623..a86c029e47e8c 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-scalar.c
+++ b/clang/test/DebugInfo/KeyInstructions/init-scalar.c
@@ -1,7 +1,7 @@
-// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - \
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
-// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- \
+// RUN: %clang_cc1 -gkey-instructions -x c %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 void a() {
@@ -10,10 +10,8 @@ void a() {
 // CHECK: %add = add {{.*}}, !dbg [[G2R2:!.*]]
 // CHECK: store i32 %add, ptr %B, align 4, !dbg [[G2R1:!.*]]
     int B = 2 * A + 1;
-// CHECK-TODO: ret{{.*}}, !dbg [[G3R1:!.*]]
 }
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
 // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
-// CHECK-TODO: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)

>From fb714455f4123a40342c472b16dc940d55cd9bdb Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 1 Apr 2025 15:40:58 +0100
Subject: [PATCH 07/33] [KeyInstr][Clang] Agg init atom

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGDecl.cpp                  |  2 ++
 .../DebugInfo/KeyInstructions/init-agg.cpp    | 22 +++++++++++++++++++
 2 files changed, 24 insertions(+)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/init-agg.cpp

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index d02f2ad09d2f1..8d43d531f6043 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1270,6 +1270,8 @@ void CodeGenFunction::emitStoresForConstant(const VarDecl 
&D, Address Loc,
                            createUnnamedGlobalForMemcpyFrom(
                                CGM, D, Builder, constant, Loc.getAlignment()),
                            SizeVal, isVolatile);
+  addInstToCurrentSourceAtom(I, nullptr);
+
   if (IsAutoInit)
     I->addAnnotationMetadata("auto-init");
 }
diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
new file mode 100644
index 0000000000000..b96256b532f3e
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
@@ -0,0 +1,22 @@
+
+// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+// The implicit-check-not is important; we don't want the GEPs created for the
+// store locations to be included in the atom group.
+
+int g;
+void a() {
+// CHECK: _Z1av()
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
+    int A[] = { 1, 2, 3 };
+// CHECK: store i32 1, ptr %{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK: store i32 2, ptr %{{.*}}, !dbg [[G2R1]]
+// CHECK: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: store i32 %0, ptr %{{.*}}, !dbg [[G2R1]]
+    int B[] = { 1, 2, g };
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)

>From 253508197cdd0b6ed1c36fc32d1db38cfa428110 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 1 Apr 2025 16:45:47 +0100
Subject: [PATCH 08/33] shouldUseBZeroPlusStoresToInitialize

---
 clang/lib/CodeGen/CGDecl.cpp                      |  3 +++
 clang/test/DebugInfo/KeyInstructions/init-agg.cpp | 12 +++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 8d43d531f6043..bb13c31f8f5e4 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -945,6 +945,7 @@ void 
CodeGenFunction::emitStoresForInitAfterBZero(llvm::Constant *Init,
       isa<llvm::ConstantVector>(Init) || isa<llvm::BlockAddress>(Init) ||
       isa<llvm::ConstantExpr>(Init)) {
     auto *I = Builder.CreateStore(Init, Loc, isVolatile);
+    addInstToCurrentSourceAtom(I, nullptr);
     if (IsAutoInit)
       I->addAnnotationMetadata("auto-init");
     return;
@@ -1200,6 +1201,8 @@ void CodeGenFunction::emitStoresForConstant(const VarDecl 
&D, Address Loc,
   if (shouldUseBZeroPlusStoresToInitialize(constant, ConstantSize)) {
     auto *I = Builder.CreateMemSet(Loc, llvm::ConstantInt::get(CGM.Int8Ty, 0),
                                    SizeVal, isVolatile);
+    addInstToCurrentSourceAtom(I, nullptr);
+
     if (IsAutoInit)
       I->addAnnotationMetadata("auto-init");
 
diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
index b96256b532f3e..854af3237ed98 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
@@ -1,22 +1,32 @@
 
-// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - \
+// RUN: %clang -gkey-instructions %s -gmlt -gno-column-info -S -emit-llvm -o - 
\
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 // The implicit-check-not is important; we don't want the GEPs created for the
 // store locations to be included in the atom group.
 
 int g;
+char gc;
 void a() {
 // CHECK: _Z1av()
 // CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
     int A[] = { 1, 2, 3 };
+
 // CHECK: store i32 1, ptr %{{.*}}, !dbg [[G2R1:!.*]]
 // CHECK: store i32 2, ptr %{{.*}}, !dbg [[G2R1]]
 // CHECK: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
 // CHECK: store i32 %0, ptr %{{.*}}, !dbg [[G2R1]]
     int B[] = { 1, 2, g };
+
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK: store i8 97{{.*}}, !dbg [[G3R1]]
+// CHECK: store i8 98{{.*}}, !dbg [[G3R1]]
+// CHECK: store i8 99{{.*}}, !dbg [[G3R1]]
+// CHECK: store i8 100{{.*}}, !dbg [[G3R1]]
+    char big[65536] = { 'a', 'b', 'c', 'd' };
 }
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
 // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
\ No newline at end of file

>From 1171d504c557c81d0d905940dda9b80d98c2f9dc Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Tue, 1 Apr 2025 17:08:43 +0100
Subject: [PATCH 09/33] [KeyInstr] init-agg pattern

---
 clang/lib/CodeGen/CGDecl.cpp                      | 1 +
 clang/test/DebugInfo/KeyInstructions/init-agg.cpp | 7 +++++--
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index bb13c31f8f5e4..47d963123021b 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1227,6 +1227,7 @@ void CodeGenFunction::emitStoresForConstant(const VarDecl 
&D, Address Loc,
     }
     auto *I = Builder.CreateMemSet(
         Loc, llvm::ConstantInt::get(CGM.Int8Ty, Value), SizeVal, isVolatile);
+    addInstToCurrentSourceAtom(I, nullptr);
     if (IsAutoInit)
       I->addAnnotationMetadata("auto-init");
     return;
diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
index 854af3237ed98..e2f12d73a4ecd 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
@@ -6,7 +6,6 @@
 // store locations to be included in the atom group.
 
 int g;
-char gc;
 void a() {
 // CHECK: _Z1av()
 // CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
@@ -24,9 +23,13 @@ void a() {
 // CHECK: store i8 99{{.*}}, !dbg [[G3R1]]
 // CHECK: store i8 100{{.*}}, !dbg [[G3R1]]
     char big[65536] = { 'a', 'b', 'c', 'd' };
+
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[G4R1:!.*]]
+    char arr[] = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, };
 }
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
 // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
-// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
\ No newline at end of file
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)

>From a7fa7b7d0b90b377e427183b1824ac4cd1403f4a Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 2 Apr 2025 09:54:30 +0100
Subject: [PATCH 10/33] [KeyInstr][Clang] Init pattern atom

---
 clang/lib/CodeGen/CGDecl.cpp                      | 1 +
 clang/test/DebugInfo/KeyInstructions/init-agg.cpp | 6 +++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 47d963123021b..18135384021e8 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1189,6 +1189,7 @@ void CodeGenFunction::emitStoresForConstant(const VarDecl 
&D, Address Loc,
                           Ty->isPtrOrPtrVectorTy() || Ty->isFPOrFPVectorTy();
   if (canDoSingleStore) {
     auto *I = Builder.CreateStore(constant, Loc, isVolatile);
+    addInstToCurrentSourceAtom(I, nullptr);
     if (IsAutoInit)
       I->addAnnotationMetadata("auto-init");
     return;
diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
index e2f12d73a4ecd..f0cc67e659d95 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
@@ -1,5 +1,5 @@
 
-// RUN: %clang -gkey-instructions %s -gmlt -gno-column-info -S -emit-llvm -o - 
\
+// RUN: %clang -gkey-instructions %s -gmlt -gno-column-info -S -emit-llvm -o - 
-ftrivial-auto-var-init=pattern \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 // The implicit-check-not is important; we don't want the GEPs created for the
@@ -26,6 +26,9 @@ void a() {
 
 // CHECK: call void @llvm.memset{{.*}}, !dbg [[G4R1:!.*]]
     char arr[] = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, };
+
+// CHECK: store i8 -86, ptr %uninit{{.*}}, !dbg [[G5R1:!.*]], !annotation
+    char uninit; // -ftrivial-auto-var-init=pattern
 }
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -33,3 +36,4 @@ void a() {
 // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
 // CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
 // CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)

>From 17837fd9abb03cc08f85be13f1fea586bf194dfb Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 11:24:57 +0100
Subject: [PATCH 11/33] use %clang_cc1

---
 clang/test/DebugInfo/KeyInstructions/init-agg.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
index f0cc67e659d95..e5025e51c1df3 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
@@ -1,5 +1,5 @@
 
-// RUN: %clang -gkey-instructions %s -gmlt -gno-column-info -S -emit-llvm -o - 
-ftrivial-auto-var-init=pattern \
+// RUN: %clang_cc1 -gkey-instructions %s -debug-info-kind=line-tables-only 
-gno-column-info -emit-llvm -o - -ftrivial-auto-var-init=pattern \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 // The implicit-check-not is important; we don't want the GEPs created for the

>From 16e88e1e81bd7519d79002117040d2d9bbdb0424 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 11:49:48 +0100
Subject: [PATCH 12/33] test nits

---
 .../DebugInfo/KeyInstructions/init-agg.cpp     | 18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
index e5025e51c1df3..d3310b68429bc 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
@@ -8,20 +8,25 @@
 int g;
 void a() {
 // CHECK: _Z1av()
-// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK: call void @llvm.memcpy{{.*}}%A, {{.*}}@__const._Z1av.A{{.*}}, !dbg 
[[G1R1:!.*]]
     int A[] = { 1, 2, 3 };
 
+// CHECK: call void @llvm.memcpy{{.*}}%B, {{.*}}@__const._Z1av.B{{.*}}, !dbg 
[[G2R1:!.*]]
 // CHECK: store i32 1, ptr %{{.*}}, !dbg [[G2R1:!.*]]
 // CHECK: store i32 2, ptr %{{.*}}, !dbg [[G2R1]]
 // CHECK: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
 // CHECK: store i32 %0, ptr %{{.*}}, !dbg [[G2R1]]
     int B[] = { 1, 2, g };
 
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G3R1:!.*]]
-// CHECK: store i8 97{{.*}}, !dbg [[G3R1]]
-// CHECK: store i8 98{{.*}}, !dbg [[G3R1]]
-// CHECK: store i8 99{{.*}}, !dbg [[G3R1]]
-// CHECK: store i8 100{{.*}}, !dbg [[G3R1]]
+// CHECK:      call void @llvm.memset{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK-NEXT: %1 = getelementptr {{.*}}, ptr %big, i32 0, i32 0, !dbg 
[[LINE30:!.*]]
+// CHECK-NEXT: store i8 97, ptr %1{{.*}}, !dbg [[G3R1]]
+// CHECK-NEXT: %2 = getelementptr {{.*}}, ptr %big, i32 0, i32 1, !dbg 
[[LINE30]]
+// CHECK-NEXT: store i8 98, ptr %2{{.*}} !dbg [[G3R1]]
+// CHECK-NEXT: %3 = getelementptr {{.*}}, ptr %big, i32 0, i32 2, !dbg 
[[LINE30]]
+// CHECK-NEXT: store i8 99, ptr %3{{.*}} !dbg [[G3R1]]
+// CHECK-NEXT: %4 = getelementptr {{.*}}, ptr %big, i32 0, i32 3, !dbg 
[[LINE30]]
+// CHECK: store i8 100, ptr %4{{.*}} !dbg [[G3R1]]
     char big[65536] = { 'a', 'b', 'c', 'd' };
 
 // CHECK: call void @llvm.memset{{.*}}, !dbg [[G4R1:!.*]]
@@ -35,5 +40,6 @@ void a() {
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
 // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
 // CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[LINE30]] = !DILocation(line: 30, scope: ![[#]])
 // CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
 // CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)

>From ed55fe5f266013b56ffe474f5a71d803b8068e15 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 14:36:21 +0100
Subject: [PATCH 13/33] improve test a bit more

---
 .../DebugInfo/KeyInstructions/init-agg.cpp    | 31 ++++++++++---------
 1 file changed, 17 insertions(+), 14 deletions(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
index d3310b68429bc..5446aae155d63 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.cpp
@@ -11,25 +11,27 @@ void a() {
 // CHECK: call void @llvm.memcpy{{.*}}%A, {{.*}}@__const._Z1av.A{{.*}}, !dbg 
[[G1R1:!.*]]
     int A[] = { 1, 2, 3 };
 
-// CHECK: call void @llvm.memcpy{{.*}}%B, {{.*}}@__const._Z1av.B{{.*}}, !dbg 
[[G2R1:!.*]]
-// CHECK: store i32 1, ptr %{{.*}}, !dbg [[G2R1:!.*]]
-// CHECK: store i32 2, ptr %{{.*}}, !dbg [[G2R1]]
-// CHECK: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
-// CHECK: store i32 %0, ptr %{{.*}}, !dbg [[G2R1]]
+// CHECK:      call void @llvm.memcpy{{.*}}%B, {{.*}}@__const._Z1av.B{{.*}}, 
!dbg [[G2R1:!.*]]
+// CHECK-NEXT: store i32 1, ptr %B{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK-NEXT: %arrayinit.element = getelementptr {{.*}}, ptr %B, i64 1, !dbg 
[[B_LINE:!.*]]
+// CHECK-NEXT: store i32 2, ptr %arrayinit.element{{.*}}, !dbg [[G2R1]]
+// CHECK-NEXT: %arrayinit.element1 = getelementptr {{.*}}, ptr %B, i64 2, !dbg 
[[B_LINE]]
+// CHECK-NEXT: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK-NEXT: store i32 %0, ptr %arrayinit.element1{{.*}}, !dbg [[G2R1]]
     int B[] = { 1, 2, g };
 
-// CHECK:      call void @llvm.memset{{.*}}, !dbg [[G3R1:!.*]]
-// CHECK-NEXT: %1 = getelementptr {{.*}}, ptr %big, i32 0, i32 0, !dbg 
[[LINE30:!.*]]
+// CHECK:      call void @llvm.memset{{.*}}%big{{.*}} !dbg [[G3R1:!.*]]
+// CHECK-NEXT: %1 = getelementptr {{.*}}, ptr %big, i32 0, i32 0, !dbg 
[[big_LINE:!.*]]
 // CHECK-NEXT: store i8 97, ptr %1{{.*}}, !dbg [[G3R1]]
-// CHECK-NEXT: %2 = getelementptr {{.*}}, ptr %big, i32 0, i32 1, !dbg 
[[LINE30]]
-// CHECK-NEXT: store i8 98, ptr %2{{.*}} !dbg [[G3R1]]
-// CHECK-NEXT: %3 = getelementptr {{.*}}, ptr %big, i32 0, i32 2, !dbg 
[[LINE30]]
-// CHECK-NEXT: store i8 99, ptr %3{{.*}} !dbg [[G3R1]]
-// CHECK-NEXT: %4 = getelementptr {{.*}}, ptr %big, i32 0, i32 3, !dbg 
[[LINE30]]
+// CHECK-NEXT: %2 = getelementptr {{.*}}, ptr %big, i32 0, i32 1, !dbg 
[[big_LINE]]
+// CHECK-NEXT: store i8 98, ptr %2{{.*}}, !dbg [[G3R1]]
+// CHECK-NEXT: %3 = getelementptr {{.*}}, ptr %big, i32 0, i32 2, !dbg 
[[big_LINE]]
+// CHECK-NEXT: store i8 99, ptr %3{{.*}}, !dbg [[G3R1]]
+// CHECK-NEXT: %4 = getelementptr {{.*}}, ptr %big, i32 0, i32 3, !dbg 
[[big_LINE]]
 // CHECK: store i8 100, ptr %4{{.*}} !dbg [[G3R1]]
     char big[65536] = { 'a', 'b', 'c', 'd' };
 
-// CHECK: call void @llvm.memset{{.*}}, !dbg [[G4R1:!.*]]
+// CHECK: call void @llvm.memset{{.*}}%arr{{.*}}, !dbg [[G4R1:!.*]]
     char arr[] = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, };
 
 // CHECK: store i8 -86, ptr %uninit{{.*}}, !dbg [[G5R1:!.*]], !annotation
@@ -38,8 +40,9 @@ void a() {
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[B_LINE]] = !DILocation(line: 21, scope: ![[#]])
 // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
 // CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
-// CHECK: [[LINE30]] = !DILocation(line: 30, scope: ![[#]])
+// CHECK: [[big_LINE]] = !DILocation(line: 32, scope: ![[#]])
 // CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
 // CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)

>From 76da803ee981898895061e5f9057c4e7a9de2921 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 2 Apr 2025 17:42:48 +0100
Subject: [PATCH 14/33] [KeyInstr][Clang] Static variable init atom

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGDecl.cpp                         |  4 +++-
 clang/test/DebugInfo/KeyInstructions/init-static.cpp | 12 ++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/init-static.cpp

diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 18135384021e8..f4549ab3033b2 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -429,8 +429,10 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D,
   bool isCudaSharedVar = getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
                          D.hasAttr<CUDASharedAttr>();
   // If this value has an initializer, emit it.
-  if (D.getInit() && !isCudaSharedVar)
+  if (D.getInit() && !isCudaSharedVar) {
+    ApplyAtomGroup Grp(getDebugInfo());
     var = AddInitializerToStaticVarDecl(D, var);
+  }
 
   var->setAlignment(alignment.getAsAlign());
 
diff --git a/clang/test/DebugInfo/KeyInstructions/init-static.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-static.cpp
new file mode 100644
index 0000000000000..82e14b59df5e5
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/init-static.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang -gkey-instructions %s -gmlt -gcolumn-info -S -emit-llvm -o -\
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+void g(int *a) {
+    // CHECK: %2 = load ptr, ptr %a.addr{{.*}}, !dbg [[G1R2:!.*]]
+    // CHECK: store ptr %2, ptr @_ZZ1gPiE1b{{.*}}, !dbg [[G1R1:!.*]]
+    static int &b = *a;
+}
+
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+

>From 4e082dd8397a469b8af9c69964405ec0e1f0701a Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 14:41:31 +0100
Subject: [PATCH 15/33] cc1

---
 clang/test/DebugInfo/KeyInstructions/init-static.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/init-static.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-static.cpp
index 82e14b59df5e5..745303a3c9d58 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-static.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-static.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -gkey-instructions %s -gmlt -gcolumn-info -S -emit-llvm -o -\
+// RUN: %clang_cc1 -gkey-instructions %s -debug-info-kind=line-tables-only 
-emit-llvm -o -\
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 void g(int *a) {

>From 3b4ca1b09a659e575e022109fd8c607c9df3864f Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 2 Apr 2025 18:01:48 +0100
Subject: [PATCH 16/33] [KeyInstr][Clang] Assignment atom group

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGExpr.cpp                    | 9 +++++++++
 clang/test/DebugInfo/KeyInstructions/assign.cpp | 9 +++++++++
 2 files changed, 18 insertions(+)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/assign.cpp

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 1e426586620a2..9681fd9325fa7 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -5985,6 +5985,15 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const 
BinaryOperator *E) {
 
   assert(E->getOpcode() == BO_Assign && "unexpected binary l-value");
 
+  // This covers both LHS and RHS expressions, though nested RHS
+  // expressions may get subsequently separately grouped.
+  // FIXME(OCH): Not clear yet if we've got fine enough control
+  // to pick and choose when we need to. Currently looks ok:
+  // a = b = c  -> Two atoms.
+  // x = new(1) -> One atom (for both addr store and value store).
+  // Complex and agg assignment -> One atom.
+  ApplyAtomGroup Grp(getDebugInfo());
+
   // Note that in all of these cases, __block variables need the RHS
   // evaluated first just in case the variable gets moved by the RHS.
 
diff --git a/clang/test/DebugInfo/KeyInstructions/assign.cpp 
b/clang/test/DebugInfo/KeyInstructions/assign.cpp
new file mode 100644
index 0000000000000..b09137430156f
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/assign.cpp
@@ -0,0 +1,9 @@
+// RUN: %clang -gkey-instructions %s -gmlt -gcolumn-info -S -emit-llvm -o - 
-Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+unsigned long long g;
+void fun() { g = 0; }
+
+// CHECK: store i64 0, ptr @g{{.*}}, !dbg [[G1R1:!.*]]
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)

>From b6274d2afefac7c4546ba5b295b01ce2a3fa74d9 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 2 Apr 2025 18:27:59 +0100
Subject: [PATCH 17/33] [KeyInstr][Clang] Multiple assignment  (x = y = z)

---
 clang/lib/CodeGen/CGExprScalar.cpp             |  1 +
 .../test/DebugInfo/KeyInstructions/assign.cpp  | 18 ++++++++++++++++--
 2 files changed, 17 insertions(+), 2 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 5d618658bc615..1cc5c147c595b 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -5067,6 +5067,7 @@ llvm::Value 
*CodeGenFunction::EmitWithOriginalRHSBitfieldAssignment(
 }
 
 Value *ScalarExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   bool Ignore = TestAndClearIgnoreResultAssign();
 
   Value *RHS;
diff --git a/clang/test/DebugInfo/KeyInstructions/assign.cpp 
b/clang/test/DebugInfo/KeyInstructions/assign.cpp
index b09137430156f..d50062d21935b 100644
--- a/clang/test/DebugInfo/KeyInstructions/assign.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/assign.cpp
@@ -2,8 +2,22 @@
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 unsigned long long g;
-void fun() { g = 0; }
-
+void fun() {
 // CHECK: store i64 0, ptr @g{{.*}}, !dbg [[G1R1:!.*]]
+    g = 0;
+
+// Treat the two assignments as two atoms.
+//
+// FIXME: Because of the atomGroup implementation the load can only be
+// associated with one of the two stores, despite being a good backup
+// loction for both.
+// CHECK-NEXT: %0 = load i64, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G2R1:!.*]]
+    g = g = g;
+}
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)

>From 0ce86c40443015f1f84d7e75dc60cf3e6fe6f7fa Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 11:05:29 +0100
Subject: [PATCH 18/33] Compound assign

---
 clang/lib/CodeGen/CGExprScalar.cpp            |  2 ++
 .../DebugInfo/KeyInstructions/assign-scalar.c | 34 +++++++++++++++++++
 .../test/DebugInfo/KeyInstructions/assign.cpp | 13 ++++++-
 3 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/assign-scalar.c

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 1cc5c147c595b..366393dbdaf15 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -898,6 +898,7 @@ class ScalarExprEmitter
     return result;                                                             
\
   }                                                                            
\
   Value *VisitBin##OP##Assign(const CompoundAssignOperator *E) {               
\
+    ApplyAtomGroup Grp(CGF.getDebugInfo());                                    
\
     return EmitCompoundAssign(E, &ScalarExprEmitter::Emit##OP);                
\
   }
   HANDLEBINOP(Mul)
@@ -5850,6 +5851,7 @@ LValue CodeGenFunction::EmitObjCIsaExpr(const ObjCIsaExpr 
*E) {
 
 LValue CodeGenFunction::EmitCompoundAssignmentLValue(
                                             const CompoundAssignOperator *E) {
+  ApplyAtomGroup Grp(getDebugInfo());
   ScalarExprEmitter Scalar(*this);
   Value *Result = nullptr;
   switch (E->getOpcode()) {
diff --git a/clang/test/DebugInfo/KeyInstructions/assign-scalar.c 
b/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
new file mode 100644
index 0000000000000..1e08195b06eb5
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
@@ -0,0 +1,34 @@
+// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - -Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- -Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+unsigned long long g;
+void fun() {
+// CHECK: store i64 0, ptr @g{{.*}}, !dbg [[G1R1:!.*]]
+    g = 0;
+
+// Treat the two assignments as two atoms.
+//
+// FIXME: Because of the atomGroup implementation the load can only be
+// associated with one of the two stores, despite being a good backup
+// loction for both.
+// CHECK-NEXT: %0 = load i64, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G2R1:!.*]]
+    g = g = g;
+
+// Compound assignment.
+// CHECK: %1 = load i64, ptr @g
+// CHECK: %add = add i64 %1, 50, !dbg [[G4R2:!.*]]
+// CHECK: store i64 %add, ptr @g{{.*}}, !dbg [[G4R1:!.*]]
+    g += 50;
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
diff --git a/clang/test/DebugInfo/KeyInstructions/assign.cpp 
b/clang/test/DebugInfo/KeyInstructions/assign.cpp
index d50062d21935b..1e08195b06eb5 100644
--- a/clang/test/DebugInfo/KeyInstructions/assign.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/assign.cpp
@@ -1,4 +1,7 @@
-// RUN: %clang -gkey-instructions %s -gmlt -gcolumn-info -S -emit-llvm -o - 
-Wno-unused-variable \
+// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - -Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- -Wno-unused-variable \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 unsigned long long g;
@@ -15,9 +18,17 @@ void fun() {
 // CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G3R1:!.*]]
 // CHECK-NEXT: store i64 %0, ptr @g{{.*}}, !dbg [[G2R1:!.*]]
     g = g = g;
+
+// Compound assignment.
+// CHECK: %1 = load i64, ptr @g
+// CHECK: %add = add i64 %1, 50, !dbg [[G4R2:!.*]]
+// CHECK: store i64 %add, ptr @g{{.*}}, !dbg [[G4R1:!.*]]
+    g += 50;
 }
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
 // CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
 // CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)

>From 1ccc74bc5b36e1444f0c646320dd756dfb134b89 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 11:12:26 +0100
Subject: [PATCH 19/33] Pre/Post Inc/Dec

---
 clang/lib/CodeGen/CGExprScalar.cpp                 |  1 +
 .../test/DebugInfo/KeyInstructions/assign-scalar.c | 14 ++++++++++++++
 2 files changed, 15 insertions(+)

diff --git a/clang/lib/CodeGen/CGExprScalar.cpp 
b/clang/lib/CodeGen/CGExprScalar.cpp
index 366393dbdaf15..b9eb12efd6670 100644
--- a/clang/lib/CodeGen/CGExprScalar.cpp
+++ b/clang/lib/CodeGen/CGExprScalar.cpp
@@ -3015,6 +3015,7 @@ class OMPLastprivateConditionalUpdateRAII {
 llvm::Value *
 ScalarExprEmitter::EmitScalarPrePostIncDec(const UnaryOperator *E, LValue LV,
                                            bool isInc, bool isPre) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   OMPLastprivateConditionalUpdateRAII OMPRegion(CGF, E);
   QualType type = E->getSubExpr()->getType();
   llvm::PHINode *atomicPHI = nullptr;
diff --git a/clang/test/DebugInfo/KeyInstructions/assign-scalar.c 
b/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
index 1e08195b06eb5..1f1fe8fda39e6 100644
--- a/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
+++ b/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
@@ -24,6 +24,16 @@ void fun() {
 // CHECK: %add = add i64 %1, 50, !dbg [[G4R2:!.*]]
 // CHECK: store i64 %add, ptr @g{{.*}}, !dbg [[G4R1:!.*]]
     g += 50;
+
+// Pre/Post Inc/Dec.
+// CHECK: %2 = load i64, ptr @g
+// CHECK: %inc = add i64 %2, 1, !dbg [[G5R2:!.*]]
+// CHECK: store i64 %inc, ptr @g{{.*}}, !dbg [[G5R1:!.*]]
+    ++g;
+// CHECK: %3 = load i64, ptr @g
+// CHECK: %dec = add i64 %3, -1, !dbg [[G6R2:!.*]]
+// CHECK: store i64 %dec, ptr @g{{.*}}, !dbg [[G6R1:!.*]]
+    g--;
 }
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -32,3 +42,7 @@ void fun() {
 // CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
 // CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
 // CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[G5R2]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 2)
+// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
+// CHECK: [[G6R2]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 2)
+// CHECK: [[G6R1]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 1)

>From 99c0f3a69161ee2a92e063a60fe082e40e89e20f Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 11:27:18 +0100
Subject: [PATCH 20/33] Rename test & run C & C++

---
 .../test/DebugInfo/KeyInstructions/init-agg.c | 41 +++++++++++++++++++
 1 file changed, 41 insertions(+)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/init-agg.c

diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.c 
b/clang/test/DebugInfo/KeyInstructions/init-agg.c
new file mode 100644
index 0000000000000..ad298715286cd
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.c
@@ -0,0 +1,41 @@
+
+// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gno-column-info -S 
-emit-llvm -o - -ftrivial-auto-var-init=pattern \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -gno-column-info -S -emit-llvm 
-o - -ftrivial-auto-var-init=pattern \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+// The implicit-check-not is important; we don't want the GEPs created for the
+// store locations to be included in the atom group.
+
+int g;
+void a() {
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
+    int A[] = { 1, 2, 3 };
+
+// CHECK: store i32 1, ptr %{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK: store i32 2, ptr %{{.*}}, !dbg [[G2R1]]
+// CHECK: %0 = load i32, ptr @g{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: store i32 %0, ptr %{{.*}}, !dbg [[G2R1]]
+    int B[] = { 1, 2, g };
+
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK: store i8 97{{.*}}, !dbg [[G3R1]]
+// CHECK: store i8 98{{.*}}, !dbg [[G3R1]]
+// CHECK: store i8 99{{.*}}, !dbg [[G3R1]]
+// CHECK: store i8 100{{.*}}, !dbg [[G3R1]]
+    char big[65536] = { 'a', 'b', 'c', 'd' };
+
+// CHECK: call void @llvm.memset{{.*}}, !dbg [[G4R1:!.*]]
+    char arr[] = { 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 
42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, };
+
+// CHECK: store i8 -86, ptr %uninit{{.*}}, !dbg [[G5R1:!.*]], !annotation
+    char uninit; // -ftrivial-auto-var-init=pattern
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)

>From 6f0135b3afce0539c406feee562dfb27dccb367a Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 14:55:20 +0100
Subject: [PATCH 21/33] %cc1 and rename a .cpp -> c test

---
 clang/test/DebugInfo/KeyInstructions/assign-scalar.c          | 4 ++--
 clang/test/DebugInfo/KeyInstructions/{assign.cpp => assign.c} | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)
 rename clang/test/DebugInfo/KeyInstructions/{assign.cpp => assign.c} (85%)

diff --git a/clang/test/DebugInfo/KeyInstructions/assign-scalar.c 
b/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
index 1f1fe8fda39e6..903402b6d698c 100644
--- a/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
+++ b/clang/test/DebugInfo/KeyInstructions/assign-scalar.c
@@ -1,7 +1,7 @@
-// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
-// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 unsigned long long g;
diff --git a/clang/test/DebugInfo/KeyInstructions/assign.cpp 
b/clang/test/DebugInfo/KeyInstructions/assign.c
similarity index 85%
rename from clang/test/DebugInfo/KeyInstructions/assign.cpp
rename to clang/test/DebugInfo/KeyInstructions/assign.c
index 1e08195b06eb5..d2ce2dceed2f8 100644
--- a/clang/test/DebugInfo/KeyInstructions/assign.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/assign.c
@@ -1,7 +1,7 @@
-// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
-// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 unsigned long long g;

>From fd282a63fd709cdcdcdc2dacef58144dbf9b15c1 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 13:36:59 +0100
Subject: [PATCH 22/33] [KeyInstr] Complex assignment atoms

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGExprComplex.cpp           | 10 ++++-
 .../test/DebugInfo/KeyInstructions/complex.c  | 40 +++++++++++++++++++
 2 files changed, 48 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/complex.c

diff --git a/clang/lib/CodeGen/CGExprComplex.cpp 
b/clang/lib/CodeGen/CGExprComplex.cpp
index f556594f4a9ec..600f61f1b325f 100644
--- a/clang/lib/CodeGen/CGExprComplex.cpp
+++ b/clang/lib/CodeGen/CGExprComplex.cpp
@@ -461,8 +461,12 @@ void ComplexExprEmitter::EmitStoreOfComplex(ComplexPairTy 
Val, LValue lvalue,
   Address RealPtr = CGF.emitAddrOfRealComponent(Ptr, lvalue.getType());
   Address ImagPtr = CGF.emitAddrOfImagComponent(Ptr, lvalue.getType());
 
-  Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
-  Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
+  auto *R =
+      Builder.CreateStore(Val.first, RealPtr, lvalue.isVolatileQualified());
+  CGF.addInstToCurrentSourceAtom(R, Val.first);
+  auto *I =
+      Builder.CreateStore(Val.second, ImagPtr, lvalue.isVolatileQualified());
+  CGF.addInstToCurrentSourceAtom(I, Val.second);
 }
 
 
@@ -1209,6 +1213,7 @@ LValue ComplexExprEmitter::
 EmitCompoundAssignLValue(const CompoundAssignOperator *E,
           ComplexPairTy (ComplexExprEmitter::*Func)(const BinOpInfo&),
                          RValue &Val) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   TestAndClearIgnoreReal();
   TestAndClearIgnoreImag();
   QualType LHSTy = E->getLHS()->getType();
@@ -1356,6 +1361,7 @@ LValue ComplexExprEmitter::EmitBinAssignLValue(const 
BinaryOperator *E,
 }
 
 ComplexPairTy ComplexExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   ComplexPairTy Val;
   LValue LV = EmitBinAssignLValue(E, Val);
 
diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c 
b/clang/test/DebugInfo/KeyInstructions/complex.c
new file mode 100644
index 0000000000000..b97314e815bdc
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/complex.c
@@ -0,0 +1,40 @@
+
+// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - -Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- -Wno-unused-variable \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+_Complex float ci;
+void test() {
+// CHECK: %ci.real = load float, ptr @ci{{.*}}, !dbg [[G1R2:!.*]]
+// CHECK: %ci.imag = load float, ptr getelementptr inbounds nuw ({ float, 
float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G1R2]]
+// CHECK: store float %ci.real, ptr %lc.realp{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK: store float %ci.imag, ptr %lc.imagp{{.*}}, !dbg [[G1R1]]
+  _Complex float lc = ci;
+
+// CHECK: %ci.real1 = load float, ptr @ci{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: %ci.imag2 = load float, ptr getelementptr inbounds nuw ({ float, 
float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R2]]
+// CHECK: store float %ci.real1, ptr @ci{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK: store float %ci.imag2, ptr getelementptr inbounds nuw ({ float, 
float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G2R1]]
+  ci = ci;
+
+// CHECK: %add.r = fadd float %ci.real5, %ci.real3, !dbg [[G3R2:!.*]]
+// CHECK: %add.i = fadd float %ci.imag6, %ci.imag4, !dbg [[G3R2]]
+// CHECK: store float %add.r, ptr @ci{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK: store float %add.i, ptr getelementptr inbounds nuw ({ float, float 
}, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G3R1]]
+  ci += ci;
+
+// CHECK: %add = fadd float %0, %1, !dbg [[G4R2:!.*]]
+// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, 
ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1:!.*]]
+  __imag ci = __imag ci + __imag ci;
+}
+
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)

>From 03a0a1cef3049e16e6f8802275b07e4e49014ad6 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 14:58:42 +0100
Subject: [PATCH 23/33] cc1

---
 clang/test/DebugInfo/KeyInstructions/complex.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c 
b/clang/test/DebugInfo/KeyInstructions/complex.c
index b97314e815bdc..f922e5ff71a58 100644
--- a/clang/test/DebugInfo/KeyInstructions/complex.c
+++ b/clang/test/DebugInfo/KeyInstructions/complex.c
@@ -1,8 +1,8 @@
 
-// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gcolumn-info -S -emit-llvm 
-o - -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
-// RUN: %clang -gkey-instructions -x c %s -gmlt -gcolumn-info -S -emit-llvm -o 
- -Wno-unused-variable \
+// RUN: %clang_cc1 -gkey-instructions -x c %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 _Complex float ci;

>From 4ca985019d3884907185a89bda6aed2cc7050135 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 15:09:04 +0100
Subject: [PATCH 24/33] whitespace

---
 clang/test/DebugInfo/KeyInstructions/complex.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/complex.c 
b/clang/test/DebugInfo/KeyInstructions/complex.c
index f922e5ff71a58..ff8557afb91e7 100644
--- a/clang/test/DebugInfo/KeyInstructions/complex.c
+++ b/clang/test/DebugInfo/KeyInstructions/complex.c
@@ -1,4 +1,3 @@
-
 // RUN: %clang_cc1 -gkey-instructions -x c++ %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 

>From 46ccd7a165bde6ad72f785551bf57cc7fb590378 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 15:15:39 +0100
Subject: [PATCH 25/33] [KeyInstr][Clang] Aggregate init + copy

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGExprAgg.cpp                 |  3 ++-
 clang/test/DebugInfo/KeyInstructions/agg.c      | 12 ++++++++++++
 clang/test/DebugInfo/KeyInstructions/init-agg.c |  2 ++
 3 files changed, 16 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/agg.c

diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index e6f18505a7d4d..c683b2a38225d 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -2393,7 +2393,8 @@ void CodeGenFunction::EmitAggregateCopy(LValue Dest, 
LValue Src, QualType Ty,
     }
   }
 
-  auto Inst = Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, isVolatile);
+  auto *Inst = Builder.CreateMemCpy(DestPtr, SrcPtr, SizeVal, isVolatile);
+  addInstToCurrentSourceAtom(Inst, nullptr);
 
   // Determine the metadata to describe the position of any padding in this
   // memcpy, as well as the TBAA tags for the members of the struct, in case
diff --git a/clang/test/DebugInfo/KeyInstructions/agg.c 
b/clang/test/DebugInfo/KeyInstructions/agg.c
new file mode 100644
index 0000000000000..5990859a5b548
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/agg.c
@@ -0,0 +1,12 @@
+
+// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+typedef struct { int a, b, c; } Struct;
+void fun(Struct a) {
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg  [[G1R1:!.*]]
+  Struct b = a;
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+
diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.c 
b/clang/test/DebugInfo/KeyInstructions/init-agg.c
index ad298715286cd..dc3ccaedc57b5 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.c
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.c
@@ -9,6 +9,8 @@
 // store locations to be included in the atom group.
 
 int g;
+typedef struct { int a, b, c; } Struct;
+Struct g2;
 void a() {
 // CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
     int A[] = { 1, 2, 3 };

>From 738d294f757ffeeb4a2ec26cd1f1214b5669c656 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 16:00:26 +0100
Subject: [PATCH 26/33] [KeyInstr][Clang] Agg copy atom

---
 clang/lib/CodeGen/CGExprAgg.cpp            |  1 +
 clang/lib/CodeGen/CodeGenFunction.h        |  1 +
 clang/test/DebugInfo/KeyInstructions/agg.c | 11 ++++++++---
 3 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index c683b2a38225d..cad6731173700 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -1332,6 +1332,7 @@ static bool isBlockVarRef(const Expr *E) {
 }
 
 void AggExprEmitter::VisitBinAssign(const BinaryOperator *E) {
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   // For an assignment to work, the value on the right has
   // to be compatible with the value on the left.
   assert(CGF.getContext().hasSameUnqualifiedType(E->getLHS()->getType(),
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 1743f558b37e9..47ed4e051ca47 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3035,6 +3035,7 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   /// Emit an aggregate assignment.
   void EmitAggregateAssign(LValue Dest, LValue Src, QualType EltTy) {
+    ApplyAtomGroup Grp(getDebugInfo());
     bool IsVolatile = hasVolatileMember(EltTy);
     EmitAggregateCopy(Dest, Src, EltTy, AggValueSlot::MayOverlap, IsVolatile);
   }
diff --git a/clang/test/DebugInfo/KeyInstructions/agg.c 
b/clang/test/DebugInfo/KeyInstructions/agg.c
index 5990859a5b548..177e1ea8b9fc1 100644
--- a/clang/test/DebugInfo/KeyInstructions/agg.c
+++ b/clang/test/DebugInfo/KeyInstructions/agg.c
@@ -1,12 +1,17 @@
+// RUN: %clang -gkey-instructions -x c++ %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
-// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - \
+// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o -  \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 typedef struct { int a, b, c; } Struct;
 void fun(Struct a) {
-// CHECK: call void @llvm.memcpy{{.*}}, !dbg  [[G1R1:!.*]]
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
   Struct b = a;
+
+// CHECK: call void @llvm.memcpy{{.*}}, !dbg [[G2R1:!.*]]
+  b = a;
 }
 
 // CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
-
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)

>From 35092c0b650a6e782549d813483d738f5788283f Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 15:16:33 +0100
Subject: [PATCH 27/33] move ApplyAtomGroup into CodeGenFunction.h
 (CGDebugInfo.h no longer included)

---
 clang/lib/CodeGen/CGDebugInfo.h     | 14 --------------
 clang/lib/CodeGen/CodeGenFunction.h | 14 ++++++++++++++
 2 files changed, 14 insertions(+), 14 deletions(-)

diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h
index 10739194fd70f..79d031acbf19e 100644
--- a/clang/lib/CodeGen/CGDebugInfo.h
+++ b/clang/lib/CodeGen/CGDebugInfo.h
@@ -892,20 +892,6 @@ class CGDebugInfo {
   }
 };
 
-/// A scoped helper to set the current source atom group for
-/// CGDebugInfo::addInstToCurrentSourceAtom. A source atom is a source 
construct
-/// that is "interesting" for debug stepping purposes. We use an atom group
-/// number to track the instruction(s) that implement the functionality for the
-/// atom, plus backup instructions/source locations.
-class ApplyAtomGroup {
-  uint64_t OriginalAtom = 0;
-  CGDebugInfo *DI = nullptr;
-
-public:
-  ApplyAtomGroup(CGDebugInfo *DI);
-  ~ApplyAtomGroup();
-};
-
 /// A scoped helper to set the current debug location to the specified
 /// location or preferred location of the specified Expr.
 class ApplyDebugLocation {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 47ed4e051ca47..78d71fc822bcb 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -258,6 +258,20 @@ template <> struct DominatingValue<RValue> {
   }
 };
 
+/// A scoped helper to set the current source atom group for
+/// CGDebugInfo::addInstToCurrentSourceAtom. A source atom is a source 
construct
+/// that is "interesting" for debug stepping purposes. We use an atom group
+/// number to track the instruction(s) that implement the functionality for the
+/// atom, plus backup instructions/source locations.
+class ApplyAtomGroup {
+  uint64_t OriginalAtom = 0;
+  CGDebugInfo *DI = nullptr;
+
+public:
+  ApplyAtomGroup(CGDebugInfo *DI);
+  ~ApplyAtomGroup();
+};
+
 /// CodeGenFunction - This class organizes the per-function state that is used
 /// while generating LLVM code.
 class CodeGenFunction : public CodeGenTypeCache {

>From a9c75894442b8a6c5ffe8d9330958153f33c2502 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 15:19:13 +0100
Subject: [PATCH 28/33] cc1

---
 clang/test/DebugInfo/KeyInstructions/agg.c      | 4 ++--
 clang/test/DebugInfo/KeyInstructions/init-agg.c | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/agg.c 
b/clang/test/DebugInfo/KeyInstructions/agg.c
index 177e1ea8b9fc1..06c9ebbb63369 100644
--- a/clang/test/DebugInfo/KeyInstructions/agg.c
+++ b/clang/test/DebugInfo/KeyInstructions/agg.c
@@ -1,7 +1,7 @@
-// RUN: %clang -gkey-instructions -x c++ %s -gmlt -S -emit-llvm -o - \
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
-// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o -  \
+// RUN: %clang_cc1 -gkey-instructions -x c %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 typedef struct { int a, b, c; } Struct;
diff --git a/clang/test/DebugInfo/KeyInstructions/init-agg.c 
b/clang/test/DebugInfo/KeyInstructions/init-agg.c
index dc3ccaedc57b5..de1f247bb2722 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-agg.c
+++ b/clang/test/DebugInfo/KeyInstructions/init-agg.c
@@ -1,8 +1,8 @@
 
-// RUN: %clang -gkey-instructions -x c++ %s -gmlt -gno-column-info -S 
-emit-llvm -o - -ftrivial-auto-var-init=pattern \
+// RUN: %clang_cc1 -gkey-instructions -x c++ %s 
-debug-info-kind=line-tables-only -gno-column-info -emit-llvm -o - 
-ftrivial-auto-var-init=pattern \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
-// RUN: %clang -gkey-instructions -x c %s -gmlt -gno-column-info -S -emit-llvm 
-o - -ftrivial-auto-var-init=pattern \
+// RUN: %clang_cc1 -gkey-instructions -x c %s 
-debug-info-kind=line-tables-only -gno-column-info -emit-llvm -o - 
-ftrivial-auto-var-init=pattern \
 // RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
 
 // The implicit-check-not is important; we don't want the GEPs created for the

>From 2fc4653e3e2bd825114b8081df06696c0f2b6b43 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 17:00:09 +0100
Subject: [PATCH 29/33] [KeyInstr][Clang] Member initalization atom

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/CGClass.cpp                 |  1 +
 .../DebugInfo/KeyInstructions/init-member.cpp | 22 +++++++++++++++++++
 2 files changed, 23 insertions(+)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/init-member.cpp

diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp
index 6beb2bccfeae0..251b059c256f6 100644
--- a/clang/lib/CodeGen/CGClass.cpp
+++ b/clang/lib/CodeGen/CGClass.cpp
@@ -1338,6 +1338,7 @@ void CodeGenFunction::EmitCtorPrologue(const 
CXXConstructorDecl *CD,
     assert(!Member->isBaseInitializer());
     assert(Member->isAnyMemberInitializer() &&
            "Delegating initializer on non-delegating constructor");
+    ApplyAtomGroup Grp(getDebugInfo());
     CM.addMemberInitializer(Member);
   }
   CM.finish();
diff --git a/clang/test/DebugInfo/KeyInstructions/init-member.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-member.cpp
new file mode 100644
index 0000000000000..60949bd8a604a
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/init-member.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s
+
+struct B {
+  float y;
+};
+
+class Cls {
+  public:
+    int x = 1;
+    B b = {5.f};
+};
+
+void fun() {
+  Cls c;
+}
+
+// CHECK: store i32 1, ptr %x{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK: store float 5.000000e+00, ptr %y{{.*}}, !dbg [[G2R1:!.*]]
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)

>From 58f7f4d5dc33d81e0726c6dc332dd2842f821efb Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 15:25:17 +0100
Subject: [PATCH 30/33] cc1

---
 clang/test/DebugInfo/KeyInstructions/init-member.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/init-member.cpp 
b/clang/test/DebugInfo/KeyInstructions/init-member.cpp
index 60949bd8a604a..5ccefd4064421 100644
--- a/clang/test/DebugInfo/KeyInstructions/init-member.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/init-member.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - \
+// RUN: %clang_cc1 -gkey-instructions %s -debug-info-kind=line-tables-only 
-emit-llvm -o - \
 // RUN: | FileCheck %s
 
 struct B {

>From d099e89b6de4363cf271e90cd12b61661a0eb51d Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Thu, 3 Apr 2025 17:31:32 +0100
Subject: [PATCH 31/33] [KeyInstr][Clang] Catch variable init atom

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.

The Clang-side work is demoed here:
https://github.com/llvm/llvm-project/pull/130943
---
 clang/lib/CodeGen/ItaniumCXXABI.cpp           |  1 +
 .../DebugInfo/KeyInstructions/try-catch.cpp   | 20 +++++++++++++++++++
 2 files changed, 21 insertions(+)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/try-catch.cpp

diff --git a/clang/lib/CodeGen/ItaniumCXXABI.cpp 
b/clang/lib/CodeGen/ItaniumCXXABI.cpp
index faa07024a6052..1041ae84dbdf1 100644
--- a/clang/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/clang/lib/CodeGen/ItaniumCXXABI.cpp
@@ -5055,6 +5055,7 @@ void ItaniumCXXABI::emitBeginCatch(CodeGenFunction &CGF,
 
   // Emit the local.
   CodeGenFunction::AutoVarEmission var = CGF.EmitAutoVarAlloca(*CatchParam);
+  ApplyAtomGroup Grp(CGF.getDebugInfo());
   InitCatchParam(CGF, *CatchParam, var.getObjectAddress(CGF), 
S->getBeginLoc());
   CGF.EmitAutoVarCleanups(var);
 }
diff --git a/clang/test/DebugInfo/KeyInstructions/try-catch.cpp 
b/clang/test/DebugInfo/KeyInstructions/try-catch.cpp
new file mode 100644
index 0000000000000..3d1080aca2f07
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/try-catch.cpp
@@ -0,0 +1,20 @@
+// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - -fexceptions \
+// RUN: | FileCheck %s
+
+void except() {
+  // FIXME(OCH): Should `store i32 32, ptr %exception` be key?
+  throw 32;
+}
+
+void attempt() {
+  try { except(); }
+// CHECK: catch:
+// CHECK: %4 = call ptr @__cxa_begin_catch(ptr %exn)
+// CHECK: %5 = load i32{{.*}}, !dbg [[G1R2:!.*]]
+// CHECK: store i32 %5, ptr %e{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK: call void @__cxa_end_catch()
+  catch (int e) { }
+}
+
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)

>From 54eca7132d6ed37a9a5f8eaeb3ed8b024870138a Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Wed, 21 May 2025 15:30:39 +0100
Subject: [PATCH 32/33] cc1

---
 clang/test/DebugInfo/KeyInstructions/try-catch.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/DebugInfo/KeyInstructions/try-catch.cpp 
b/clang/test/DebugInfo/KeyInstructions/try-catch.cpp
index 3d1080aca2f07..d2b458f361e11 100644
--- a/clang/test/DebugInfo/KeyInstructions/try-catch.cpp
+++ b/clang/test/DebugInfo/KeyInstructions/try-catch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang -gkey-instructions %s -gmlt -S -emit-llvm -o - -fexceptions \
+// RUN: %clang_cc1 -gkey-instructions %s -debug-info-kind=line-tables-only 
-emit-llvm -o - -fexceptions -fcxx-exceptions \
 // RUN: | FileCheck %s
 
 void except() {

>From 46e356a3b8e14d7a689582a43aff99b0f9319584 Mon Sep 17 00:00:00 2001
From: Orlando Cazalet-Hyams <orlando.hy...@sony.com>
Date: Fri, 23 May 2025 10:15:42 +0100
Subject: [PATCH 33/33] [KeyInstr][Clang] If stmt atom (#134642)

This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.

RFC:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668

The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.
---
 clang/lib/CodeGen/CodeGenFunction.cpp     | 10 +++++
 clang/lib/CodeGen/CodeGenFunction.h       |  5 +++
 clang/test/DebugInfo/KeyInstructions/if.c | 46 +++++++++++++++++++++++
 3 files changed, 61 insertions(+)
 create mode 100644 clang/test/DebugInfo/KeyInstructions/if.c

diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp 
b/clang/lib/CodeGen/CodeGenFunction.cpp
index 2256cc08e2212..0356952f4f291 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2118,6 +2118,8 @@ void CodeGenFunction::EmitBranchOnBoolExpr(
 
   llvm::Instruction *BrInst = Builder.CreateCondBr(CondV, TrueBlock, 
FalseBlock,
                                                    Weights, Unpredictable);
+  addInstToNewSourceAtom(BrInst, CondV);
+
   switch (HLSLControlFlowAttr) {
   case HLSLControlFlowHintAttr::Microsoft_branch:
   case HLSLControlFlowHintAttr::Microsoft_flatten: {
@@ -3338,3 +3340,11 @@ void CodeGenFunction::addInstToSpecificSourceAtom(
   if (CGDebugInfo *DI = getDebugInfo())
     DI->addInstToSpecificSourceAtom(KeyInstruction, Backup, Atom);
 }
+
+void CodeGenFunction::addInstToNewSourceAtom(llvm::Instruction *KeyInstruction,
+                                             llvm::Value *Backup) {
+  if (CGDebugInfo *DI = getDebugInfo()) {
+    ApplyAtomGroup Grp(getDebugInfo());
+    DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
+  }
+}
\ No newline at end of file
diff --git a/clang/lib/CodeGen/CodeGenFunction.h 
b/clang/lib/CodeGen/CodeGenFunction.h
index 78d71fc822bcb..92e9ab8156ad2 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -1762,6 +1762,11 @@ class CodeGenFunction : public CodeGenTypeCache {
   void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
                                    llvm::Value *Backup, uint64_t Atom);
 
+  /// Add \p KeyInstruction and an optional \p Backup instruction to a new atom
+  /// group (See ApplyAtomGroup for more info).
+  void addInstToNewSourceAtom(llvm::Instruction *KeyInstruction,
+                              llvm::Value *Backup);
+
 private:
   /// SwitchInsn - This is nearest current switch instruction. It is null if
   /// current context is not in a switch.
diff --git a/clang/test/DebugInfo/KeyInstructions/if.c 
b/clang/test/DebugInfo/KeyInstructions/if.c
new file mode 100644
index 0000000000000..df7d10d6ee7b8
--- /dev/null
+++ b/clang/test/DebugInfo/KeyInstructions/if.c
@@ -0,0 +1,46 @@
+// RUN: %clang_cc1 -gkey-instructions -x c++ -std=c++17 %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank --check-prefixes=CHECK,CHECK-CXX
+
+// RUN: %clang_cc1 -gkey-instructions -x c %s 
-debug-info-kind=line-tables-only -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not 
atomRank
+
+int g;
+void a(int A) {
+// The branch is a key instruction, with the condition being its backup.
+// CHECK: entry:
+// CHECK: %tobool = icmp ne i32 %0, 0{{.*}}, !dbg [[G1R2:!.*]]
+// CHECK: br i1 %tobool, label %if.then, label %if.end{{.*}}, !dbg [[G1R1:!.*]]
+    if (A)
+        ;
+
+// The assignment in the if gets a distinct source atom group.
+// CHECK: if.end:
+// CHECK: %1 = load i32, ptr %A.addr{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: store i32 %1, ptr @g{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK: %tobool1 = icmp ne i32 %1, 0{{.*}}, !dbg [[G3R2:!.*]]
+// CHECK: br i1 %tobool1, label %if.then2, label %if.end3{{.*}}, !dbg 
[[G3R1:!.*]]
+    if ((g = A))
+        ;
+
+#ifdef __cplusplus
+// The assignment in the if gets a distinct source atom group.
+// CHECK-CXX: if.end3:
+// CHECK-CXX: %2 = load i32, ptr %A.addr{{.*}}, !dbg [[G4R2:!.*]]
+// CHECK-CXX: store i32 %2, ptr %B{{.*}}, !dbg [[G4R1:!.*]]
+// CHECK-CXX: %tobool4 = icmp ne i32 %3, 0{{.*}}, !dbg [[G5R2:!.*]]
+// CHECK-CXX: br i1 %tobool4, label %if.then5, label %if.end6{{.*}}, !dbg 
[[G5R1:!.*]]
+    if (int B = A; B)
+        ;
+#endif
+}
+
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK-CXX: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
+// CHECK-CXX: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK-CXX: [[G5R2]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 2)
+// CHECK-CXX: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to