Skip to content

Commit 856f99e

Browse files
committed
[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: #130943
1 parent 7132dd3 commit 856f99e

File tree

3 files changed

+182
-1
lines changed

3 files changed

+182
-1
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 118 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,114 @@ 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+
if (!CGM.getCodeGenOpts().DebugKeyInstructions)
158+
return;
159+
160+
uint64_t Group = KeyInstructionsInfo.CurrentAtom;
161+
if (!Group)
162+
return;
163+
164+
addInstSourceAtomMetadata(KeyInstruction, Group, /*Rank=*/1);
165+
166+
llvm::Instruction *BackupI =
167+
llvm::dyn_cast_or_null<llvm::Instruction>(Backup);
168+
if (!BackupI)
169+
return;
170+
171+
// Add the backup instruction to the group.
172+
addInstSourceAtomMetadata(BackupI, Group, /*Rank=*/2);
173+
174+
// Look through chains of casts too, as they're probably going to evaporate.
175+
// FIXME: And other nops like zero length geps?
176+
// FIXME: Should use Cast->isNoopCast()?
177+
uint8_t Rank = 3;
178+
while (auto *Cast = dyn_cast<llvm::CastInst>(BackupI)) {
179+
BackupI = dyn_cast<llvm::Instruction>(Cast->getOperand(0));
180+
if (!BackupI)
181+
break;
182+
addInstSourceAtomMetadata(BackupI, Group, Rank++);
183+
}
184+
}
185+
186+
void CGDebugInfo::addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
187+
llvm::Value *Backup) {
188+
if (KeyInstructionsInfo.RetAtomOverride) {
189+
uint64_t CurrentAtom = KeyInstructionsInfo.CurrentAtom;
190+
KeyInstructionsInfo.CurrentAtom = KeyInstructionsInfo.RetAtomOverride;
191+
addInstToCurrentSourceAtom(Ret, Backup);
192+
KeyInstructionsInfo.CurrentAtom = CurrentAtom;
193+
KeyInstructionsInfo.RetAtomOverride = 0;
194+
} else {
195+
auto Grp = ApplyAtomGroup(this);
196+
addInstToCurrentSourceAtom(Ret, Backup);
197+
}
198+
}
199+
200+
void CGDebugInfo::setRetInstSourceAtomOverride(uint64_t Group) {
201+
assert(KeyInstructionsInfo.RetAtomOverride == 0);
202+
KeyInstructionsInfo.RetAtomOverride = Group;
203+
}
204+
205+
void CGDebugInfo::completeFunction() {
206+
// Reset the atom group number tracker as the numbers are function-local.
207+
KeyInstructionsInfo.NextAtom = 1;
208+
KeyInstructionsInfo.HighestEmittedAtom = 0;
209+
KeyInstructionsInfo.CurrentAtom = 0;
210+
KeyInstructionsInfo.RetAtomOverride = 0;
211+
}
212+
213+
ApplyAtomGroup::ApplyAtomGroup(CGDebugInfo *DI) : DI(DI) {
214+
if (!DI)
215+
return;
216+
OriginalAtom = DI->KeyInstructionsInfo.CurrentAtom;
217+
DI->KeyInstructionsInfo.CurrentAtom = DI->KeyInstructionsInfo.NextAtom++;
218+
}
219+
220+
ApplyAtomGroup::~ApplyAtomGroup() {
221+
if (!DI)
222+
return;
223+
224+
// We may not have used the group number at all.
225+
DI->KeyInstructionsInfo.NextAtom =
226+
std::min(DI->KeyInstructionsInfo.HighestEmittedAtom + 1,
227+
DI->KeyInstructionsInfo.NextAtom);
228+
229+
DI->KeyInstructionsInfo.CurrentAtom = OriginalAtom;
230+
}
231+
122232
ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF,
123233
SourceLocation TemporaryLocation)
124234
: CGF(&CGF) {
@@ -174,8 +284,15 @@ ApplyDebugLocation::ApplyDebugLocation(CodeGenFunction &CGF, llvm::DebugLoc Loc)
174284
return;
175285
}
176286
OriginalLocation = CGF.Builder.getCurrentDebugLocation();
177-
if (Loc)
287+
if (Loc) {
288+
// Key Instructions: drop the atom group and rank to avoid accidentally
289+
// propagating it around.
290+
if (Loc->getAtomGroup())
291+
Loc = llvm::DILocation::get(Loc->getContext(), Loc.getLine(),
292+
Loc->getColumn(), Loc->getScope(),
293+
Loc->getInlinedAt(), Loc.isImplicitCode());
178294
CGF.Builder.SetCurrentDebugLocation(std::move(Loc));
295+
}
179296
}
180297

181298
ApplyDebugLocation::~ApplyDebugLocation() {

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 50 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,17 @@ 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+
uint64_t RetAtomOverride = 0;
192+
} KeyInstructionsInfo;
193+
194+
private:
182195
/// Helper functions for getOrCreateType.
183196
/// @{
184197
/// Currently the checksum of an interface includes the number of
@@ -636,7 +649,30 @@ class CGDebugInfo {
636649
StringRef Category,
637650
StringRef FailureMsg);
638651

652+
/// Reset internal state.
653+
void completeFunction();
654+
655+
/// Add \p KeyInstruction and an optional \p Backup instruction to the
656+
/// current atom group, created using ApplyAtomGroup.
657+
void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
658+
llvm::Value *Backup);
659+
660+
/// Add \p Ret and an optional \p Backup instruction to the
661+
/// saved override used for some ret instructions if it exists, or a new atom.
662+
void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
663+
llvm::Value *Backup);
664+
665+
/// Set an atom group override for use in addRetToOverrideOrNewSourceAtom.
666+
void setRetInstSourceAtomOverride(uint64_t Group);
667+
639668
private:
669+
/// Amend \p I's DebugLoc with \p Group (its source atom group) and \p
670+
/// Rank (lower nonzero rank is higher precedence). Does nothing if \p I
671+
/// has no DebugLoc, and chooses the atom group in which the instruction
672+
/// has the highest precedence if it's already in one.
673+
void addInstSourceAtomMetadata(llvm::Instruction *I, uint64_t Group,
674+
uint8_t Rank);
675+
640676
/// Emit call to llvm.dbg.declare for a variable declaration.
641677
/// Returns a pointer to the DILocalVariable associated with the
642678
/// llvm.dbg.declare, or nullptr otherwise.
@@ -853,6 +889,20 @@ class CGDebugInfo {
853889
}
854890
};
855891

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

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1761,6 +1761,20 @@ 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+
if (CGDebugInfo *DI = getDebugInfo())
1768+
DI->addInstToCurrentSourceAtom(KeyInstruction, Backup);
1769+
}
1770+
1771+
/// See CGDebugInfo::addRetToOverrideOrNewSourceAtom.
1772+
void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
1773+
llvm::Value *Backup) {
1774+
if (CGDebugInfo *DI = getDebugInfo())
1775+
DI->addRetToOverrideOrNewSourceAtom(Ret, Backup);
1776+
}
1777+
17641778
private:
17651779
/// SwitchInsn - This is nearest current switch instruction. It is null if
17661780
/// current context is not in a switch.

0 commit comments

Comments
 (0)