Skip to content

Commit 9459c83

Browse files
authored
[KeyInstr][Clang] Add ApplyAtomGroup (#134632)
This is a scoped helper similar to ApplyDebugLocation that creates a new source location 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++. 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.
1 parent 878c976 commit 9459c83

File tree

4 files changed

+167
-1
lines changed

4 files changed

+167
-1
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "llvm/IR/Constants.h"
4444
#include "llvm/IR/DataLayout.h"
4545
#include "llvm/IR/DerivedTypes.h"
46+
#include "llvm/IR/Instruction.h"
4647
#include "llvm/IR/Instructions.h"
4748
#include "llvm/IR/Intrinsics.h"
4849
#include "llvm/IR/Metadata.h"
@@ -52,6 +53,7 @@
5253
#include "llvm/Support/SHA1.h"
5354
#include "llvm/Support/SHA256.h"
5455
#include "llvm/Support/TimeProfiler.h"
56+
#include <cstdint>
5557
#include <optional>
5658
using namespace clang;
5759
using namespace clang::CodeGen;
@@ -119,6 +121,97 @@ CGDebugInfo::~CGDebugInfo() {
119121
"Region stack mismatch, stack not empty!");
120122
}
121123

124+
void CGDebugInfo::addInstSourceAtomMetadata(llvm::Instruction *I,
125+
uint64_t Group, uint8_t Rank) {
126+
if (!I->getDebugLoc() || Group == 0 || !I->getDebugLoc()->getLine())
127+
return;
128+
129+
// Saturate the 3-bit rank.
130+
Rank = std::min<uint8_t>(Rank, 7);
131+
132+
const llvm::DebugLoc &DL = I->getDebugLoc();
133+
134+
// Each instruction can only be attributed to one source atom (a limitation of
135+
// the implementation). If this instruction is already part of a source atom,
136+
// pick the group in which it has highest precedence (lowest rank).
137+
if (DL.get()->getAtomGroup() && DL.get()->getAtomRank() &&
138+
DL.get()->getAtomRank() < Rank) {
139+
Group = DL.get()->getAtomGroup();
140+
Rank = DL.get()->getAtomRank();
141+
}
142+
143+
// Update the function-local watermark so we don't reuse this number for
144+
// another atom.
145+
KeyInstructionsInfo.HighestEmittedAtom =
146+
std::max(Group, KeyInstructionsInfo.HighestEmittedAtom);
147+
148+
// Apply the new DILocation to the instruction.
149+
llvm::DILocation *NewDL = llvm::DILocation::get(
150+
I->getContext(), DL.getLine(), DL.getCol(), DL.getScope(),
151+
DL.getInlinedAt(), DL.isImplicitCode(), Group, Rank);
152+
I->setDebugLoc(NewDL);
153+
};
154+
155+
void CGDebugInfo::addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
156+
llvm::Value *Backup) {
157+
addInstToSpecificSourceAtom(KeyInstruction, Backup,
158+
KeyInstructionsInfo.CurrentAtom);
159+
}
160+
161+
void CGDebugInfo::addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
162+
llvm::Value *Backup,
163+
uint64_t Group) {
164+
if (!Group || !CGM.getCodeGenOpts().DebugKeyInstructions)
165+
return;
166+
167+
addInstSourceAtomMetadata(KeyInstruction, Group, /*Rank=*/1);
168+
169+
llvm::Instruction *BackupI =
170+
llvm::dyn_cast_or_null<llvm::Instruction>(Backup);
171+
if (!BackupI)
172+
return;
173+
174+
// Add the backup instruction to the group.
175+
addInstSourceAtomMetadata(BackupI, Group, /*Rank=*/2);
176+
177+
// Look through chains of casts too, as they're probably going to evaporate.
178+
// FIXME: And other nops like zero length geps?
179+
// FIXME: Should use Cast->isNoopCast()?
180+
uint8_t Rank = 3;
181+
while (auto *Cast = dyn_cast<llvm::CastInst>(BackupI)) {
182+
BackupI = dyn_cast<llvm::Instruction>(Cast->getOperand(0));
183+
if (!BackupI)
184+
break;
185+
addInstSourceAtomMetadata(BackupI, Group, Rank++);
186+
}
187+
}
188+
189+
void CGDebugInfo::completeFunction() {
190+
// Reset the atom group number tracker as the numbers are function-local.
191+
KeyInstructionsInfo.NextAtom = 1;
192+
KeyInstructionsInfo.HighestEmittedAtom = 0;
193+
KeyInstructionsInfo.CurrentAtom = 0;
194+
}
195+
196+
ApplyAtomGroup::ApplyAtomGroup(CGDebugInfo *DI) : DI(DI) {
197+
if (!DI)
198+
return;
199+
OriginalAtom = DI->KeyInstructionsInfo.CurrentAtom;
200+
DI->KeyInstructionsInfo.CurrentAtom = DI->KeyInstructionsInfo.NextAtom++;
201+
}
202+
203+
ApplyAtomGroup::~ApplyAtomGroup() {
204+
if (!DI)
205+
return;
206+
207+
// We may not have used the group number at all.
208+
DI->KeyInstructionsInfo.NextAtom =
209+
std::min(DI->KeyInstructionsInfo.HighestEmittedAtom + 1,
210+
DI->KeyInstructionsInfo.NextAtom);
211+
212+
DI->KeyInstructionsInfo.CurrentAtom = OriginalAtom;
213+
}
214+
122215
ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
123216
SourceLocation TemporaryLocation)
124217
: CGF(&CGF) {
@@ -174,8 +267,15 @@ ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc)
174267
return;
175268
}
176269
OriginalLocation = CGF.Builder.getCurrentDebugLocation();
177-
if (Loc)
270+
if (Loc) {
271+
// Key Instructions: drop the atom group and rank to avoid accidentally
272+
// propagating it around.
273+
if (Loc->getAtomGroup())
274+
Loc = llvm::DILocation::get(Loc->getContext(), Loc.getLine(),
275+
Loc->getColumn(), Loc->getScope(),
276+
Loc->getInlinedAt(), Loc.isImplicitCode());
178277
CGF.Builder.SetCurrentDebugLocation(std::move(Loc));
278+
}
179279
}
180280

181281
ApplyDebugLocation::~ApplyDebugLocation() {

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ class CGBlockInfo;
5858
class CGDebugInfo {
5959
friend class ApplyDebugLocation;
6060
friend class SaveAndRestoreLocation;
61+
friend class ApplyAtomGroup;
62+
6163
CodeGenModule &CGM;
6264
const llvm::codegenoptions::DebugInfoKind DebugKind;
6365
bool DebugTypeExtRefs;
@@ -179,6 +181,16 @@ class CGDebugInfo {
179181
/// The key is coroutine real parameters, value is DIVariable in LLVM IR.
180182
Param2DILocTy ParamDbgMappings;
181183

184+
/// Key Instructions bookkeeping.
185+
/// Source atoms are identified by a {AtomGroup, InlinedAt} pair, meaning
186+
/// AtomGroup numbers can be repeated across different functions.
187+
struct {
188+
uint64_t NextAtom = 1;
189+
uint64_t HighestEmittedAtom = 0;
190+
uint64_t CurrentAtom = 0;
191+
} KeyInstructionsInfo;
192+
193+
private:
182194
/// Helper functions for getOrCreateType.
183195
/// @{
184196
/// Currently the checksum of an interface includes the number of
@@ -643,7 +655,27 @@ class CGDebugInfo {
643655
llvm::DILocation *CreateSyntheticInlineAt(llvm::DebugLoc Location,
644656
StringRef FuncName);
645657

658+
/// Reset internal state.
659+
void completeFunction();
660+
661+
/// Add \p KeyInstruction and an optional \p Backup instruction to the
662+
/// current atom group, created using ApplyAtomGroup.
663+
void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
664+
llvm::Value *Backup);
665+
666+
/// Add \p KeyInstruction and an optional \p Backup instruction to the atom
667+
/// group \p Atom.
668+
void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
669+
llvm::Value *Backup, uint64_t Atom);
670+
646671
private:
672+
/// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
673+
/// Rank (lower nonzero rank is higher precedence). Does nothing if \p I
674+
/// has no DebugLoc, and chooses the atom group in which the instruction
675+
/// has the highest precedence if it's already in one.
676+
void addInstSourceAtomMetadata(llvm::Instruction *I, uint64_t Group,
677+
uint8_t Rank);
678+
647679
/// Emit call to llvm.dbg.declare for a variable declaration.
648680
/// Returns a pointer to the DILocalVariable associated with the
649681
/// llvm.dbg.declare, or nullptr otherwise.
@@ -860,6 +892,20 @@ class CGDebugInfo {
860892
}
861893
};
862894

895+
/// A scoped helper to set the current source atom group for
896+
/// CGDebugInfo::addInstToCurrentSourceAtom. A source atom is a source construct
897+
/// that is "interesting" for debug stepping purposes. We use an atom group
898+
/// number to track the instruction(s) that implement the functionality for the
899+
/// atom, plus backup instructions/source locations.
900+
class ApplyAtomGroup {
901+
uint64_t OriginalAtom = 0;
902+
CGDebugInfo *DI = nullptr;
903+
904+
public:
905+
ApplyAtomGroup(CGDebugInfo *DI);
906+
~ApplyAtomGroup();
907+
};
908+
863909
/// A scoped helper to set the current debug location to the specified
864910
/// location or preferred location of the specified Expr.
865911
class ApplyDebugLocation {

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3326,3 +3326,15 @@ CodeGenFunction::EmitPointerAuthAuth(const CGPointerAuthInfo &PointerAuth,
33263326
return EmitPointerAuthCommon(*this, PointerAuth, Pointer,
33273327
llvm::Intrinsic::ptrauth_auth);
33283328
}
3329+
3330+
void CodeGenFunction::addInstToCurrentSourceAtom(
3331+
llvm::Instruction *KeyInstruction, llvm::Value *Backup) {
3332+
if (CGDebugInfo *DI = getDebugInfo())
3333+
DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
3334+
}
3335+
3336+
void CodeGenFunction::addInstToSpecificSourceAtom(
3337+
llvm::Instruction *KeyInstruction, llvm::Value *Backup, uint64_t Atom) {
3338+
if (CGDebugInfo *DI = getDebugInfo())
3339+
DI->addInstToSpecificSourceAtom(KeyInstruction, Backup, Atom);
3340+
}

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,6 +1740,14 @@ class CodeGenFunction : public CodeGenTypeCache {
17401740
/// recently incremented counter.
17411741
uint64_t getCurrentProfileCount() { return PGO.getCurrentRegionCount(); }
17421742

1743+
/// See CGDebugInfo::addInstToCurrentSourceAtom.
1744+
void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
1745+
llvm::Value *Backup);
1746+
1747+
/// See CGDebugInfo::addInstToSpecificSourceAtom.
1748+
void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
1749+
llvm::Value *Backup, uint64_t Atom);
1750+
17431751
private:
17441752
/// SwitchInsn - This is nearest current switch instruction. It is null if
17451753
/// current context is not in a switch.

0 commit comments

Comments
 (0)