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