Skip to content

Commit 104ece5

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. More general info in the RFC: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 And some Clang-specific details here: llvm#130943
1 parent f248da7 commit 104ece5

File tree

2 files changed

+165
-1
lines changed

2 files changed

+165
-1
lines changed

clang/lib/CodeGen/CGDebugInfo.cpp

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

181299
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,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,26 @@ class CGDebugInfo {
636649
StringRef Category,
637650
StringRef FailureMsg);
638651

652+
// TODO(OCH): comment.
653+
void completeFunction();
654+
655+
// TODO(OCH): Add comment.
656+
void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
657+
llvm::Value *Backup, uint8_t KeyInstRank = 1);
658+
// TODO(OCH): Add comment.
659+
void addRetToOverrideOrNewSourceAtom(llvm::ReturnInst *Ret,
660+
llvm::Value *Backup,
661+
uint8_t KeyInstRank = 1);
662+
void setRetInstSourceAtomOverride(uint64_t Group);
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 {

0 commit comments

Comments
 (0)