diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp index 2a11eebf1b682..1cc2c55a19f11 100644 --- a/clang/lib/CodeGen/CGDebugInfo.cpp +++ b/clang/lib/CodeGen/CGDebugInfo.cpp @@ -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" @@ -52,6 +53,7 @@ #include "llvm/Support/SHA1.h" #include "llvm/Support/SHA256.h" #include "llvm/Support/TimeProfiler.h" +#include #include using namespace clang; using namespace clang::CodeGen; @@ -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(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(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(BackupI)) { + BackupI = dyn_cast(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) { @@ -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() { diff --git a/clang/lib/CodeGen/CGDebugInfo.h b/clang/lib/CodeGen/CGDebugInfo.h index b287ce7b92eee..10739194fd70f 100644 --- a/clang/lib/CodeGen/CGDebugInfo.h +++ b/clang/lib/CodeGen/CGDebugInfo.h @@ -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; @@ -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 @@ -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. @@ -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 { diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 4e79cdf0ef089..2256cc08e2212 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -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); +} diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 603e38d763aa4..1743f558b37e9 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -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.