Skip to content

Commit 08e7a8e

Browse files
committed
[KeyInstr][Clang] Add ApplyAtomGroup (llvm#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 76bc02d commit 08e7a8e

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
@@ -636,7 +648,27 @@ class CGDebugInfo {
636648
StringRef Category,
637649
StringRef FailureMsg);
638650

651+
/// Reset internal state.
652+
void completeFunction();
653+
654+
/// Add \p KeyInstruction and an optional \p Backup instruction to the
655+
/// current atom group, created using ApplyAtomGroup.
656+
void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
657+
llvm::Value *Backup);
658+
659+
/// Add \p KeyInstruction and an optional \p Backup instruction to the atom
660+
/// group \p Atom.
661+
void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
662+
llvm::Value *Backup, uint64_t Atom);
663+
639664
private:
665+
/// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
666+
/// Rank (lower nonzero rank is higher precedence). Does nothing if \p I
667+
/// has no DebugLoc, and chooses the atom group in which the instruction
668+
/// has the highest precedence if it's already in one.
669+
void addInstSourceAtomMetadata(llvm::Instruction *I, uint64_t Group,
670+
uint8_t Rank);
671+
640672
/// Emit call to llvm.dbg.declare for a variable declaration.
641673
/// Returns a pointer to the DILocalVariable associated with the
642674
/// llvm.dbg.declare, or nullptr otherwise.
@@ -853,6 +885,20 @@ class CGDebugInfo {
853885
}
854886
};
855887

888+
/// A scoped helper to set the current source atom group for
889+
/// CGDebugInfo::addInstToCurrentSourceAtom. A source atom is a source construct
890+
/// that is "interesting" for debug stepping purposes. We use an atom group
891+
/// number to track the instruction(s) that implement the functionality for the
892+
/// atom, plus backup instructions/source locations.
893+
class ApplyAtomGroup {
894+
uint64_t OriginalAtom = 0;
895+
CGDebugInfo *DI = nullptr;
896+
897+
public:
898+
ApplyAtomGroup(CGDebugInfo *DI);
899+
~ApplyAtomGroup();
900+
};
901+
856902
/// A scoped helper to set the current debug location to the specified
857903
/// location or preferred location of the specified Expr.
858904
class ApplyDebugLocation {

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3303,3 +3303,15 @@ CodeGenFunction::EmitPointerAuthAuth(const CGPointerAuthInfo &PointerAuth,
33033303
return EmitPointerAuthCommon(*this, PointerAuth, Pointer,
33043304
llvm::Intrinsic::ptrauth_auth);
33053305
}
3306+
3307+
void CodeGenFunction::addInstToCurrentSourceAtom(
3308+
llvm::Instruction *KeyInstruction, llvm::Value *Backup) {
3309+
if (CGDebugInfo *DI = getDebugInfo())
3310+
DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
3311+
}
3312+
3313+
void CodeGenFunction::addInstToSpecificSourceAtom(
3314+
llvm::Instruction *KeyInstruction, llvm::Value *Backup, uint64_t Atom) {
3315+
if (CGDebugInfo *DI = getDebugInfo())
3316+
DI->addInstToSpecificSourceAtom(KeyInstruction, Backup, Atom);
3317+
}

clang/lib/CodeGen/CodeGenFunction.h

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

1764+
/// See CGDebugInfo::addInstToCurrentSourceAtom.
1765+
void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
1766+
llvm::Value *Backup);
1767+
1768+
/// See CGDebugInfo::addInstToSpecificSourceAtom.
1769+
void addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
1770+
llvm::Value *Backup, uint64_t Atom);
1771+
17641772
private:
17651773
/// SwitchInsn - This is nearest current switch instruction. It is null if
17661774
/// current context is not in a switch.

0 commit comments

Comments
 (0)