Skip to content

[KeyInstr][Clang] Add ApplyAtomGroup #134632

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 101 additions & 1 deletion clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;
Expand Down Expand Up @@ -119,6 +121,97 @@ 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) {
addInstToSpecificSourceAtom(KeyInstruction, Backup,
KeyInstructionsInfo.CurrentAtom);
}

void CGDebugInfo::addInstToSpecificSourceAtom(llvm::Instruction *KeyInstruction,
llvm::Value *Backup,
uint64_t Group) {
if (!Group || !CGM.getCodeGenOpts().DebugKeyInstructions)
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::completeFunction() {
// Reset the atom group number tracker as the numbers are function-local.
KeyInstructionsInfo.NextAtom = 1;
KeyInstructionsInfo.HighestEmittedAtom = 0;
KeyInstructionsInfo.CurrentAtom = 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) {
Expand Down Expand Up @@ -174,8 +267,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() {
Expand Down
46 changes: 46 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -179,6 +181,16 @@ 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;
} KeyInstructionsInfo;

private:
/// Helper functions for getOrCreateType.
/// @{
/// Currently the checksum of an interface includes the number of
Expand Down Expand Up @@ -643,7 +655,27 @@ 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 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
/// 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.
Expand Down Expand Up @@ -860,6 +892,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 {
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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::addInstToSpecificSourceAtom(
llvm::Instruction *KeyInstruction, llvm::Value *Backup, uint64_t Atom) {
if (CGDebugInfo *DI = getDebugInfo())
DI->addInstToSpecificSourceAtom(KeyInstruction, Backup, Atom);
}
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1740,6 +1740,14 @@ class CodeGenFunction : public CodeGenTypeCache {
/// recently incremented counter.
uint64_t getCurrentProfileCount() { return PGO.getCurrentRegionCount(); }

/// See CGDebugInfo::addInstToCurrentSourceAtom.
void addInstToCurrentSourceAtom(llvm::Instruction *KeyInstruction,
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
/// current context is not in a switch.
Expand Down