Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 4 additions & 0 deletions clang/include/clang/Basic/DebugOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ DEBUGOPT(CodeViewCommandLine, 1, 0)
/// Whether emit extra debug info for sample pgo profile collection.
DEBUGOPT(DebugInfoForProfiling, 1, 0)

/// Whether to generate pseudo variables and their debug info for intermediate
/// pointer accesses.
DEBUGOPT(DebugInfoForPointerType, 1, 0)

/// Whether to emit .debug_gnu_pubnames section instead of .debug_pubnames.
DEBUGOPT(DebugNameTable, 2, 0)

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -1675,6 +1675,10 @@ defm debug_info_for_profiling : BoolFOption<"debug-info-for-profiling",
PosFlag<SetTrue, [], [ClangOption, CC1Option],
"Emit extra debug info to make sample profile more accurate">,
NegFlag<SetFalse>>;
def fdebug_info_for_pointer_type : Flag<["-"], "fdebug-info-for-pointer-type">,
Group<f_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Generate pseudo variables and their debug info for intermediate pointer accesses">,
MarshallingInfoFlag<CodeGenOpts<"DebugInfoForPointerType">>;
def fprofile_instr_generate : Flag<["-"], "fprofile-instr-generate">,
Group<f_Group>, Visibility<[ClangOption, CLOption]>,
HelpText<"Generate instrumented code to collect execution counts into default.profraw file (overridden by '=' form of option or LLVM_PROFILE_FILE env var)">;
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5636,6 +5636,31 @@ void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var,
Var->addDebugInfo(GVE);
}

void CGDebugInfo::EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty,
SourceLocation Loc) {
llvm::DIFile *Unit = getOrCreateFile(Loc);
unsigned Line = getLineNumber(Loc);
unsigned Column = getColumnNumber(Loc);
llvm::DILocalVariable *D = DBuilder.createAutoVariable(
LexicalBlockStack.back(), Alloca->getName(), getOrCreateFile(Loc), Line,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it generate a variable without name? I think name is useless here and just bloats the binary size.

getOrCreateType(Ty, Unit));
llvm::DILocation *DIL =
llvm::DILocation::get(CGM.getLLVMContext(), Line, Column,
LexicalBlockStack.back(), CurInlinedAt);
SmallVector<uint64_t> Expr;
DBuilder.insertDeclare(Alloca, D, DBuilder.createExpression(Expr), DIL,
Alloca->getParent());
}

llvm::MDNode *CGDebugInfo::GetPseudoVariableAnnotation() {
if (!PseudoVariableAnnotation)
PseudoVariableAnnotation =
llvm::MDNode::get(CGM.getLLVMContext(),
llvm::MDString::get(CGM.getLLVMContext(),
"fdebug-info-for-pointer-type"));
return PseudoVariableAnnotation;
}

void CGDebugInfo::EmitGlobalAlias(const llvm::GlobalValue *GV,
const GlobalDecl GD) {

Expand Down
13 changes: 13 additions & 0 deletions clang/lib/CodeGen/CGDebugInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ class CGDebugInfo {
/// The key is coroutine real parameters, value is DIVariable in LLVM IR.
Param2DILocTy ParamDbgMappings;

/// Cached object for GetPseudoVariableAnnotation().
llvm::MDNode *PseudoVariableAnnotation = nullptr;

/// Helper functions for getOrCreateType.
/// @{
/// Currently the checksum of an interface includes the number of
Expand Down Expand Up @@ -529,6 +532,16 @@ class CGDebugInfo {
/// Emit information about an external variable.
void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);

/// Emit debug information for a pseudo variable assigned to the value of an
/// intermediate expression, so that a performance counter can track the usage
/// of a specific expression of interest.
void EmitPseudoVariable(llvm::AllocaInst *Alloca, QualType Ty,
SourceLocation Loc);

/// Get the special annotation tag that indicates the instruction is
/// associated with EmitPseudoVariable.
llvm::MDNode *GetPseudoVariableAnnotation();

/// Emit information about global variable alias.
void EmitGlobalAlias(const llvm::GlobalValue *GV, const GlobalDecl Decl);

Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -793,6 +793,7 @@ void CodeGenFunction::EmitScalarInit(const Expr *init, const ValueDecl *D,
Qualifiers::ObjCLifetime lifetime = lvalue.getObjCLifetime();
if (!lifetime) {
llvm::Value *value = EmitScalarExpr(init);
value = UnemitPseudoVariable(value);
if (capturedByInit)
drillIntoBlockVariable(*this, lvalue, cast<VarDecl>(D));
EmitNullabilityCheck(lvalue, value, init->getExprLoc());
Expand Down
69 changes: 69 additions & 0 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -951,6 +951,39 @@ static llvm::Value *getArrayIndexingBound(CodeGenFunction &CGF,
return nullptr;
}

/// When a pseudo variable is created for %1, it generates these instructions
/// in sequence and return %2:
/// %pseudo = alloca Ty
/// call void @llvm.dbg.declare(metadata ptr %pseudo, metadata, metadata)
/// store Ty %1, ptr %pseudo
/// %2 = load ptr, ptr %pseudo
/// To undo, we detect and remove this sequence, and replace %2 back with %1.
llvm::Value *CodeGenFunction::UnemitPseudoVariable(llvm::Value *V) {
if (CGDebugInfo *DI = getDebugInfo()) {
if (llvm::LoadInst *Load = dyn_cast<llvm::LoadInst>(V)) {
if (llvm::MDNode *Tag =
Load->getMetadata(llvm::LLVMContext::MD_annotation)) {
if (Tag == DI->GetPseudoVariableAnnotation()) {
llvm::Value *PseudoVar = Load->getPointerOperand();
llvm::AllocaInst *Alloca = dyn_cast<llvm::AllocaInst>(PseudoVar);
llvm::StoreInst *Store =
dyn_cast_if_present<llvm::StoreInst>(Load->getPrevNode());
assert(Store && Store->getPointerOperand() == PseudoVar);
llvm::Value *OriginalValue = Store->getValueOperand();
V->replaceAllUsesWith(OriginalValue);
assert(Store->getPrevNode()->getPrevNode() == PseudoVar);
auto It = Load->getIterator();
for (int i = 0; i < 4; i++) {
(It--)->eraseFromParent();
}
return OriginalValue;
}
}
}
}
return V;
}

namespace {

/// \p StructAccessBase returns the base \p Expr of a field access. It returns
Expand Down Expand Up @@ -2015,6 +2048,40 @@ llvm::Value *CodeGenFunction::EmitLoadOfScalar(Address Addr, bool Volatile,
llvm::MDNode::get(getLLVMContext(), std::nullopt));
}

// if -g2 or above and -fdebug-info-for-pointer-type are enabled, emit
// additional debug info for loads in an intermediate expression, which allows
// a performance counter to deduce the type of the value being loaded, even if
// it does not correspond to a variable in the source code.
// Since there is no variable correspond to an intermediate expression, we
// create a pseudo variable for it and emit its debug info, as if the
// expression were written in SSA form.
if (CGM.getCodeGenOpts().getDebugInfo() >
llvm::codegenoptions::DebugLineTablesOnly &&
CGM.getCodeGenOpts().DebugInfoForPointerType) {
if (CGDebugInfo *DI = getDebugInfo()) {
// We only generate this debug info if loading from GEP, not from other
// cases such as loading a function argument.
if (isa<llvm::GetElementPtrInst>(Load->getOperand(0))) {
const llvm::DebugLoc &DebugLoc = Load->getDebugLoc();
llvm::AllocaInst *PseudoVar =
Builder.CreateAlloca(Load->getType(), nullptr,
Twine("pseudo_")
.concat(Twine(DebugLoc.getLine()))
.concat("_")
.concat(Twine(DebugLoc.getCol())));
DI->EmitPseudoVariable(PseudoVar, Ty, Loc);
Address PseudoVarAddr(PseudoVar, Load->getType(), Addr.getAlignment());
Builder.CreateStore(Load, PseudoVarAddr);
Load = Builder.CreateLoad(PseudoVarAddr);
// Set a special metadata tag to this instruction, in the case we need
// to revert it because there is already a destination variable for the
// load.
Load->setMetadata(llvm::LLVMContext::MD_annotation,
DI->GetPseudoVariableAnnotation());
}
}
}

return EmitFromMemory(Load, Ty);
}

Expand Down Expand Up @@ -5569,6 +5636,8 @@ LValue CodeGenFunction::EmitBinaryOperatorLValue(const BinaryOperator *E) {
}

RValue RV = EmitAnyExpr(E->getRHS());
if (isa<DeclRefExpr>(E->getLHS()) && RV.isScalar())
RV = RValue::get(UnemitPseudoVariable(RV.getScalarVal()));
LValue LV = EmitCheckedLValue(E->getLHS(), TCK_Store);
if (RV.isScalar())
EmitNullabilityCheck(LV, RV.getScalarVal(), E->getExprLoc());
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -3104,6 +3104,11 @@ class CodeGenFunction : public CodeGenTypeCache {
/// Get the record field index as represented in debug info.
unsigned getDebugInfoFIndex(const RecordDecl *Rec, unsigned FieldIndex);

/// When the result of EmitLoadOfScalar is immediately assigned to a declared
/// variable, the pseudo variable emitted for it (when the flag
/// -fdebug-info-for-pointer-type is specified) should be undone since there
/// is already a debug value emitted for the declared variable.
llvm::Value *UnemitPseudoVariable(llvm::Value *V);

//===--------------------------------------------------------------------===//
// Declaration Emission
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4256,6 +4256,9 @@ renderDebugOptions(const ToolChain &TC, const Driver &D, const llvm::Triple &T,
// decision should be made in the driver as well though.
llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning();

if (Args.hasArg(options::OPT_fdebug_info_for_pointer_type))
CmdArgs.push_back("-fdebug-info-for-pointer-type");

bool SplitDWARFInlining =
Args.hasFlag(options::OPT_fsplit_dwarf_inlining,
options::OPT_fno_split_dwarf_inlining, false);
Expand Down