Skip to content

[rebranch] Cherry-pick debug info entry value fixes #7311

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
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
17 changes: 17 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,23 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
return VariableDie;
}

if (const std::optional<DbgVariableEntryValue> &EntryValueVar =
DV.getEntryValue()) {
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
// Emit each expression as: EntryValue(Register) <other ops> <Fragment>.
for (auto [Register, Expr] : EntryValueVar->getEntryValuesInfo()) {
DwarfExpr.addFragmentOffset(&Expr);
DIExpressionCursor Cursor(Expr.getElements());
DwarfExpr.beginEntryValueExpression(Cursor);
DwarfExpr.addMachineRegExpression(
*Asm->MF->getSubtarget().getRegisterInfo(), Cursor, Register);
DwarfExpr.addExpression(std::move(Cursor));
}
addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize());
return VariableDie;
}

// .. else use frame index.
if (!DV.hasFrameIndexExprs())
return VariableDie;
Expand Down
15 changes: 5 additions & 10 deletions llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1572,21 +1572,16 @@ void DwarfDebug::collectVariableInfoFromMFTable(
cast<DILocalVariable>(Var.first), Var.second);
if (VI.inStackSlot())
RegVar->initializeMMI(VI.Expr, VI.getStackSlot());
else {
MachineLocation MLoc(VI.getEntryValueRegister(), /*IsIndirect*/ true);
auto LocEntry = DbgValueLocEntry(MLoc);
RegVar->initializeDbgValue(DbgValueLoc(VI.Expr, LocEntry));
}
else
RegVar->initializeEntryValue(VI.getEntryValueRegister(), *VI.Expr);
LLVM_DEBUG(dbgs() << "Created DbgVariable for " << VI.Var->getName()
<< "\n");

if (DbgVariable *DbgVar = MFVars.lookup(Var)) {
if (DbgVar->getValueLoc())
LLVM_DEBUG(dbgs() << "Dropping repeated entry value debug info for "
"variable "
<< VI.Var->getName() << "\n");
else
if (DbgVar->hasFrameIndexExprs())
DbgVar->addMMIEntry(*RegVar);
else
DbgVar->getEntryValue()->addExpr(VI.getEntryValueRegister(), *VI.Expr);
} else if (InfoHolder.addScopeVariable(Scope, RegVar.get())) {
MFVars.insert({Var, RegVar.get()});
ConcreteEntities.push_back(std::move(RegVar));
Expand Down
74 changes: 70 additions & 4 deletions llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,64 @@ class DbgEntity {
}
};

/// Helper class to model a DbgVariable whose location is derived from an
/// EntryValue.
/// TODO: split the current implementation of `DbgVariable` into a class per
/// variant of location that it can represent, and make `DbgVariableEntryValue`
/// a subclass.
class DbgVariableEntryValue {
struct EntryValueInfo {
MCRegister Reg;
const DIExpression &Expr;

/// Operator enabling sorting based on fragment offset.
bool operator<(const EntryValueInfo &Other) const {
return getFragmentOffsetInBits() < Other.getFragmentOffsetInBits();
}

private:
uint64_t getFragmentOffsetInBits() const {
std::optional<DIExpression::FragmentInfo> Fragment =
Expr.getFragmentInfo();
return Fragment ? Fragment->OffsetInBits : 0;
}
};

std::set<EntryValueInfo> EntryValues;

public:
DbgVariableEntryValue(MCRegister Reg, const DIExpression &Expr) {
addExpr(Reg, Expr);
};

// Add the pair Reg, Expr to the list of entry values describing the variable.
// If multiple expressions are added, it is the callers responsibility to
// ensure they are all non-overlapping fragments.
void addExpr(MCRegister Reg, const DIExpression &Expr) {
std::optional<const DIExpression *> NonVariadicExpr =
DIExpression::convertToNonVariadicExpression(&Expr);
assert(NonVariadicExpr && *NonVariadicExpr);

EntryValues.insert({Reg, **NonVariadicExpr});
}

/// Returns the set of EntryValueInfo.
const std::set<EntryValueInfo> &getEntryValuesInfo() const {
return EntryValues;
}
};

//===----------------------------------------------------------------------===//
/// This class is used to track local variable information.
///
/// Variables can be created from allocas, in which case they're generated from
/// the MMI table. Such variables can have multiple expressions and frame
/// indices.
///
/// Variables can be created from the entry value of registers, in which case
/// they're generated from the MMI table. Such variables can have either a
/// single expression or multiple *fragment* expressions.
///
/// Variables can be created from \c DBG_VALUE instructions. Those whose
/// location changes over time use \a DebugLocListIndex, while those with a
/// single location use \a ValueLoc and (optionally) a single entry of \a Expr.
Expand All @@ -128,6 +179,8 @@ class DbgVariable : public DbgEntity {
mutable SmallVector<FrameIndexExpr, 1>
FrameIndexExprs; /// Frame index + expression.

std::optional<DbgVariableEntryValue> EntryValue;

public:
/// Construct a DbgVariable.
///
Expand All @@ -136,10 +189,13 @@ class DbgVariable : public DbgEntity {
DbgVariable(const DILocalVariable *V, const DILocation *IA)
: DbgEntity(V, IA, DbgVariableKind) {}

bool isInitialized() const {
return !FrameIndexExprs.empty() || ValueLoc || EntryValue;
}

/// Initialize from the MMI table.
void initializeMMI(const DIExpression *E, int FI) {
assert(FrameIndexExprs.empty() && "Already initialized?");
assert(!ValueLoc.get() && "Already initialized?");
assert(!isInitialized() && "Already initialized?");

assert((!E || E->isValid()) && "Expected valid expression");
assert(FI != std::numeric_limits<int>::max() && "Expected valid index");
Expand All @@ -149,8 +205,7 @@ class DbgVariable : public DbgEntity {

// Initialize variable's location.
void initializeDbgValue(DbgValueLoc Value) {
assert(FrameIndexExprs.empty() && "Already initialized?");
assert(!ValueLoc && "Already initialized?");
assert(!isInitialized() && "Already initialized?");
assert(!Value.getExpression()->isFragment() && "Fragments not supported.");

ValueLoc = std::make_unique<DbgValueLoc>(Value);
Expand All @@ -159,6 +214,17 @@ class DbgVariable : public DbgEntity {
FrameIndexExprs.push_back({0, E});
}

void initializeEntryValue(MCRegister Reg, const DIExpression &Expr) {
assert(!isInitialized() && "Already initialized?");
EntryValue = DbgVariableEntryValue(Reg, Expr);
}

const std::optional<DbgVariableEntryValue> &getEntryValue() const {
return EntryValue;
}

std::optional<DbgVariableEntryValue> &getEntryValue() { return EntryValue; }

/// Initialize from a DBG_VALUE instruction.
void initializeDbgValue(const MachineInstr *DbgValue);

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/AsmPrinter/DwarfExpression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,7 @@ void DwarfExpression::beginEntryValueExpression(

SavedLocationKind = LocationKind;
LocationKind = Register;
LocationFlags |= EntryValue;
IsEmittingEntryValue = true;
enableTemporaryBuffer();
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,8 @@ bool IRTranslator::translateIfEntryValueArgument(
if (!PhysReg)
return false;

// Append an op deref to account for the fact that this is a dbg_declare.
Expr = DIExpression::append(Expr, dwarf::DW_OP_deref);
MF->setVariableDbgInfo(DebugInst.getVariable(), Expr, *PhysReg,
DebugInst.getDebugLoc());
return true;
Expand Down
58 changes: 38 additions & 20 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5845,26 +5845,6 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
if (!Op)
return false;

// If the expression refers to the entry value of an Argument, use the
// corresponding livein physical register. As per the Verifier, this is only
// allowed for swiftasync Arguments.
if (Op->isReg() && Expr->isEntryValue()) {
assert(Arg->hasAttribute(Attribute::AttrKind::SwiftAsync));
auto OpReg = Op->getReg();
for (auto [PhysReg, VirtReg] : FuncInfo.RegInfo->liveins())
if (OpReg == VirtReg || OpReg == PhysReg) {
SDDbgValue *SDV = DAG.getVRegDbgValue(
Variable, Expr, PhysReg,
Kind != FuncArgumentDbgValueKind::Value /*is indirect*/, DL,
SDNodeOrder);
DAG.AddDbgValue(SDV, false /*treat as dbg.declare byval parameter*/);
return true;
}
LLVM_DEBUG(dbgs() << "Dropping dbg.value: expression is entry_value but "
"couldn't find a physical register\n");
return true;
}

assert(Variable->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
MachineInstr *NewMI = nullptr;
Expand Down Expand Up @@ -5953,6 +5933,41 @@ static const CallBase *FindPreallocatedCall(const Value *PreallocatedSetup) {
llvm_unreachable("expected corresponding call to preallocated setup/arg");
}

/// If DI is a debug value with an EntryValue expression, lower it using the
/// corresponding physical register of the associated Argument value
/// (guaranteed to exist by the verifier).
bool SelectionDAGBuilder::visitEntryValueDbgValue(const DbgValueInst &DI) {
DILocalVariable *Variable = DI.getVariable();
DIExpression *Expr = DI.getExpression();
if (!Expr->isEntryValue() || !hasSingleElement(DI.getValues()))
return false;

// These properties are guaranteed by the verifier.
Argument *Arg = cast<Argument>(DI.getValue(0));
assert(Arg->hasAttribute(Attribute::AttrKind::SwiftAsync));

auto ArgIt = FuncInfo.ValueMap.find(Arg);
if (ArgIt == FuncInfo.ValueMap.end()) {
LLVM_DEBUG(
dbgs() << "Dropping dbg.value: expression is entry_value but "
"couldn't find an associated register for the Argument\n");
return true;
}
Register ArgVReg = ArgIt->getSecond();

for (auto [PhysReg, VirtReg] : FuncInfo.RegInfo->liveins())
if (ArgVReg == VirtReg || ArgVReg == PhysReg) {
SDDbgValue *SDV =
DAG.getVRegDbgValue(Variable, Expr, PhysReg, false /*IsIndidrect*/,
DI.getDebugLoc(), SDNodeOrder);
DAG.AddDbgValue(SDV, false /*treat as dbg.declare byval parameter*/);
return true;
}
LLVM_DEBUG(dbgs() << "Dropping dbg.value: expression is entry_value but "
"couldn't find a physical register\n");
return true;
}

/// Lower the call to the specified intrinsic function.
void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
unsigned Intrinsic) {
Expand Down Expand Up @@ -6284,6 +6299,9 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
DIExpression *Expression = DI.getExpression();
dropDanglingDebugInfo(Variable, Expression);

if (visitEntryValueDbgValue(DI))
return;

if (DI.isKillLocation()) {
handleKillDebugValue(Variable, Expression, DI.getDebugLoc(), SDNodeOrder);
return;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,8 @@ class SelectionDAGBuilder {

void visitInlineAsm(const CallBase &Call,
const BasicBlock *EHPadBB = nullptr);

bool visitEntryValueDbgValue(const DbgValueInst &I);
void visitIntrinsicCall(const CallInst &I, unsigned Intrinsic);
void visitTargetIntrinsic(const CallInst &I, unsigned Intrinsic);
void visitConstrainedFPIntrinsic(const ConstrainedFPIntrinsic &FPI);
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,8 @@ static bool processIfEntryValueDbgDeclare(FunctionLoweringInfo &FuncInfo,
// Find the corresponding livein physical register to this argument.
for (auto [PhysReg, VirtReg] : FuncInfo.RegInfo->liveins())
if (VirtReg == ArgVReg) {
// Append an op deref to account for the fact that this is a dbg_declare.
Expr = DIExpression::append(Expr, dwarf::DW_OP_deref);
FuncInfo.MF->setVariableDbgInfo(Var, Expr, PhysReg, DbgLoc);
LLVM_DEBUG(dbgs() << "processDbgDeclare: setVariableDbgInfo Var=" << *Var
<< ", Expr=" << *Expr << ", MCRegister=" << PhysReg
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Coroutines/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,5 @@ add_llvm_component_library(LLVMCoroutines
Scalar
Support
TransformUtils
TargetParser
)
6 changes: 3 additions & 3 deletions llvm/lib/Transforms/Coroutines/CoroFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1879,7 +1879,7 @@ static void insertSpills(const FrameDataInfo &FrameData, coro::Shape &Shape) {
// This dbg.declare is for the main function entry point. It
// will be deleted in all coro-split functions.
coro::salvageDebugInfo(ArgToAllocaMap, DDI, Shape.OptimizeFrame,
true /*IsEntryPoint*/);
false /*UseEntryValue*/);
}
}

Expand Down Expand Up @@ -2819,7 +2819,7 @@ static void collectFrameAlloca(AllocaInst *AI, coro::Shape &Shape,

void coro::salvageDebugInfo(
SmallDenseMap<Argument *, AllocaInst *, 4> &ArgToAllocaMap,
DbgVariableIntrinsic *DVI, bool OptimizeFrame, bool IsEntryPoint) {
DbgVariableIntrinsic *DVI, bool OptimizeFrame, bool UseEntryValue) {
Function *F = DVI->getFunction();
IRBuilder<> Builder(F->getContext());
auto InsertPt = F->getEntryBlock().getFirstInsertionPt();
Expand Down Expand Up @@ -2878,7 +2878,7 @@ void coro::salvageDebugInfo(
// For the EntryPoint funclet, don't use EntryValues. This funclet can be
// inlined, which would remove the guarantee that this intrinsic targets an
// Argument.
if (IsSwiftAsyncArg && !IsEntryPoint && !Expr->isEntryValue())
if (IsSwiftAsyncArg && UseEntryValue && !Expr->isEntryValue())
Expr = DIExpression::prepend(Expr, DIExpression::EntryValue);

// If the coroutine frame is an Argument, store it in an alloca to improve
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/Transforms/Coroutines/CoroSplit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -701,9 +701,13 @@ void CoroCloner::salvageDebugInfo() {
SmallVector<DbgVariableIntrinsic *, 8> Worklist =
collectDbgVariableIntrinsics(*NewF);
SmallDenseMap<Argument *, AllocaInst *, 4> ArgToAllocaMap;

// Only 64-bit ABIs have a register we can refer to with the entry value.
bool UseEntryValue =
llvm::Triple(OrigF.getParent()->getTargetTriple()).isArch64Bit();
for (DbgVariableIntrinsic *DVI : Worklist)
coro::salvageDebugInfo(ArgToAllocaMap, DVI, Shape.OptimizeFrame,
false /*IsEntryPoint*/);
UseEntryValue);

// Remove all salvaged dbg.declare intrinsics that became
// either unreachable or stale due to the CoroSplit transformation.
Expand Down Expand Up @@ -1989,7 +1993,7 @@ splitCoroutine(Function &F, SmallVectorImpl<Function *> &Clones,
SmallDenseMap<Argument *, AllocaInst *, 4> ArgToAllocaMap;
for (auto *DDI : collectDbgVariableIntrinsics(F))
coro::salvageDebugInfo(ArgToAllocaMap, DDI, Shape.OptimizeFrame,
true /*IsEntryPoint*/);
false /*UseEntryValue*/);

return Shape;
}
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/CodeGen/AArch64/dbg-declare-swift-async.ll
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
; RUN: llc -O0 -fast-isel=false -global-isel=false -stop-after=finalize-isel %s -o - | FileCheck %s

; CHECK: void @foo
; CHECK-NEXT: dbg.declare(metadata {{.*}}, metadata ![[VAR:.*]], metadata ![[EXPR:.*]]), !dbg ![[LOC:.*]]
; CHECK-NEXT: dbg.declare(metadata {{.*}}, metadata ![[VAR:.*]], metadata !DIExpression([[EXPR:.*]])), !dbg ![[LOC:.*]]
; CHECK: entry_values:
; CHECK-NEXT: entry-value-register: '$x22', debug-info-variable: '![[VAR]]', debug-info-expression: '![[EXPR]]',
; CHECK-NEXT: entry-value-register: '$x22', debug-info-variable: '![[VAR]]', debug-info-expression: '!DIExpression([[EXPR]], DW_OP_deref)',
; CHECK-NEXT: debug-info-location: '![[LOC]]
; CHECK-NEXT: entry-value-register: '$x22', debug-info-variable: '![[VAR]]', debug-info-expression: '![[EXPR]]'
; CHECK-NEXT: entry-value-register: '$x22', debug-info-variable: '![[VAR]]', debug-info-expression: '!DIExpression([[EXPR]], DW_OP_deref)'
; CHECK-NEXT: debug-info-location: '![[LOC]]

; CHECK-NOT: DBG_VALUE
Expand Down
Loading