Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit b560ea7

Browse files
committed
PR32382: Fix emitting complex DWARF expressions.
The DWARF specification knows 3 kinds of non-empty simple location descriptions: 1. Register location descriptions - describe a variable in a register - consist of only a DW_OP_reg 2. Memory location descriptions - describe the address of a variable 3. Implicit location descriptions - describe the value of a variable - end with DW_OP_stack_value & friends The existing DwarfExpression code is pretty much ignorant of these restrictions. This used to not matter because we only emitted very short expressions that we happened to get right by accident. This patch makes DwarfExpression aware of the rules defined by the DWARF standard and now chooses the right kind of location description for each expression being emitted. This would have been an NFC commit (for the existing testsuite) if not for the way that clang describes captured block variables. Based on how the previous code in LLVM emitted locations, DW_OP_deref operations that should have come at the end of the expression are put at its beginning. Fixing this means changing the semantics of DIExpression, so this patch bumps the version number of DIExpression and implements a bitcode upgrade. There are two major changes in this patch: I had to fix the semantics of dbg.declare for describing function arguments. After this patch a dbg.declare always takes the *address* of a variable as the first argument, even if the argument is not an alloca. When lowering a DBG_VALUE, the decision of whether to emit a register location description or a memory location description depends on the MachineLocation — register machine locations may get promoted to memory locations based on their DIExpression. (Future) optimization passes that want to salvage implicit debug location for variables may do so by appending a DW_OP_stack_value. For example: DBG_VALUE, [RBP-8] --> DW_OP_fbreg -8 DBG_VALUE, RAX --> DW_OP_reg0 +0 DBG_VALUE, RAX, DIExpression(DW_OP_deref) --> DW_OP_reg0 +0 All testcases that were modified were regenerated from clang. I also added source-based testcases for each of these to the debuginfo-tests repository over the last week to make sure that no synchronized bugs slip in. The debuginfo-tests compile from source and run the debugger. https://bugs.llvm.org/show_bug.cgi?id=32382 <rdar://problem/31205000> Differential Revision: https://reviews.llvm.org/D31439 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300522 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent cc56be2 commit b560ea7

37 files changed

+381
-178
lines changed

docs/LangRef.rst

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4380,7 +4380,7 @@ referenced LLVM variable relates to the source language variable.
43804380

43814381
The current supported vocabulary is limited:
43824382

4383-
- ``DW_OP_deref`` dereferences the working expression.
4383+
- ``DW_OP_deref`` dereferences the top of the expression stack.
43844384
- ``DW_OP_plus, 93`` adds ``93`` to the working expression.
43854385
- ``DW_OP_LLVM_fragment, 16, 8`` specifies the offset and size (``16`` and ``8``
43864386
here, respectively) of the variable fragment from the working expression. Note
@@ -4396,12 +4396,17 @@ DIExpression nodes that contain a ``DW_OP_stack_value`` operator are standalone
43964396
location descriptions that describe constant values. This form is used to
43974397
describe global constants that have been optimized away. All other expressions
43984398
are modifiers to another location: A debug intrinsic ties a location and a
4399-
DIExpression together. Contrary to DWARF expressions, a DIExpression always
4400-
describes the *value* of a source variable and never its *address*. In DWARF
4401-
terminology, a DIExpression can always be considered an implicit location
4402-
description regardless whether it contains a ``DW_OP_stack_value`` or not.
4399+
DIExpression together.
44034400

4404-
.. code-block:: text
4401+
DWARF specifies three kinds of simple location descriptions: Register, memory,
4402+
and implicit location descriptions. Register and memory location descriptions
4403+
describe the *location* of a source variable (in the sense that a debugger might
4404+
modify its value), whereas implicit locations describe merely the *value* of a
4405+
source variable. DIExpressions also follow this model: A DIExpression that
4406+
doesn't have a trailing ``DW_OP_stack_value`` will describe an *address* when
4407+
combined with a concrete location.
4408+
4409+
.. code-block:: llvm
44054410
44064411
!0 = !DIExpression(DW_OP_deref)
44074412
!1 = !DIExpression(DW_OP_plus, 3)

docs/SourceLevelDebugging.rst

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,11 +180,27 @@ provide debug information at various points in generated code.
180180
181181
void @llvm.dbg.declare(metadata, metadata, metadata)
182182
183-
This intrinsic provides information about a local element (e.g., variable).
184-
The first argument is metadata holding the alloca for the variable. The second
183+
This intrinsic provides information about a local element (e.g., variable). The
184+
first argument is metadata holding the alloca for the variable. The second
185185
argument is a `local variable <LangRef.html#dilocalvariable>`_ containing a
186186
description of the variable. The third argument is a `complex expression
187-
<LangRef.html#diexpression>`_.
187+
<LangRef.html#diexpression>`_. An `llvm.dbg.declare` instrinsic describes the
188+
*location* of a source variable.
189+
190+
.. code-block:: llvm
191+
192+
%i.addr = alloca i32, align 4
193+
call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !1, metadata !2), !dbg !3
194+
!1 = !DILocalVariable(name: "i", ...) ; int i
195+
!2 = !DIExpression()
196+
!3 = !DILocation(...)
197+
...
198+
%buffer = alloca [256 x i8], align 8
199+
; The address of i is buffer+64.
200+
call void @llvm.dbg.declare(metadata [256 x i8]* %buffer, metadata !1, metadata !2)
201+
!1 = !DILocalVariable(name: "i", ...) ; int i
202+
!2 = !DIExpression(DW_OP_plus, 64)
203+
188204
189205
``llvm.dbg.value``
190206
^^^^^^^^^^^^^^^^^^

include/llvm/CodeGen/MachineInstrBuilder.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,11 @@ MachineInstrBuilder BuildMI(MachineBasicBlock &BB,
413413
unsigned Reg, unsigned Offset,
414414
const MDNode *Variable, const MDNode *Expr);
415415

416+
/// Clone a DBG_VALUE whose value has been spilled to FrameIndex.
417+
MachineInstr *buildDbgValueForSpill(MachineBasicBlock &BB,
418+
MachineBasicBlock::iterator I,
419+
const MachineInstr &Orig, int FrameIndex);
420+
416421
inline unsigned getDefRegState(bool B) {
417422
return B ? RegState::Define : 0;
418423
}

include/llvm/IR/DebugInfoMetadata.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2232,6 +2232,9 @@ class DIExpression : public MDNode {
22322232
expr_op_iterator expr_op_end() const {
22332233
return expr_op_iterator(elements_end());
22342234
}
2235+
iterator_range<expr_op_iterator> expr_ops() const {
2236+
return {expr_op_begin(), expr_op_end()};
2237+
}
22352238
/// @}
22362239

22372240
bool isValid() const;
@@ -2240,7 +2243,7 @@ class DIExpression : public MDNode {
22402243
return MD->getMetadataID() == DIExpressionKind;
22412244
}
22422245

2243-
/// Is the first element a DW_OP_deref?.
2246+
/// Return whether the first element a DW_OP_deref.
22442247
bool startsWithDeref() const {
22452248
return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_deref;
22462249
}

lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2631,6 +2631,7 @@ Error BitcodeReader::globalCleanup() {
26312631

26322632
// Look for intrinsic functions which need to be upgraded at some point
26332633
for (Function &F : *TheModule) {
2634+
MDLoader->upgradeDebugIntrinsics(F);
26342635
Function *NewFn;
26352636
if (UpgradeIntrinsicFunction(&F, NewFn))
26362637
UpgradedIntrinsics[&F] = NewFn;

lib/Bitcode/Reader/MetadataLoader.cpp

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include "llvm/IR/Instruction.h"
5555
#include "llvm/IR/Instructions.h"
5656
#include "llvm/IR/Intrinsics.h"
57+
#include "llvm/IR/IntrinsicInst.h"
5758
#include "llvm/IR/LLVMContext.h"
5859
#include "llvm/IR/Module.h"
5960
#include "llvm/IR/ModuleSummaryIndex.h"
@@ -452,6 +453,7 @@ class MetadataLoader::MetadataLoaderImpl {
452453
bool StripTBAA = false;
453454
bool HasSeenOldLoopTags = false;
454455
bool NeedUpgradeToDIGlobalVariableExpression = false;
456+
bool NeedDeclareExpressionUpgrade = false;
455457

456458
/// True if metadata is being parsed for a module being ThinLTO imported.
457459
bool IsImporting = false;
@@ -511,6 +513,26 @@ class MetadataLoader::MetadataLoaderImpl {
511513
}
512514
}
513515

516+
/// Remove a leading DW_OP_deref from DIExpressions in a dbg.declare that
517+
/// describes a function argument.
518+
void upgradeDeclareExpressions(Function &F) {
519+
if (!NeedDeclareExpressionUpgrade)
520+
return;
521+
522+
for (auto &BB : F)
523+
for (auto &I : BB)
524+
if (auto *DDI = dyn_cast<DbgDeclareInst>(&I))
525+
if (auto *DIExpr = DDI->getExpression())
526+
if (DIExpr->startsWithDeref() &&
527+
dyn_cast_or_null<Argument>(DDI->getAddress())) {
528+
SmallVector<uint64_t, 8> Ops;
529+
Ops.append(std::next(DIExpr->elements_begin()),
530+
DIExpr->elements_end());
531+
auto *E = DIExpression::get(Context, Ops);
532+
DDI->setOperand(2, MetadataAsValue::get(Context, E));
533+
}
534+
}
535+
514536
void upgradeDebugInfo() {
515537
upgradeCUSubprograms();
516538
upgradeCUVariables();
@@ -565,6 +587,7 @@ class MetadataLoader::MetadataLoaderImpl {
565587

566588
unsigned size() const { return MetadataList.size(); }
567589
void shrinkTo(unsigned N) { MetadataList.shrinkTo(N); }
590+
void upgradeDebugIntrinsics(Function &F) { upgradeDeclareExpressions(F); }
568591
};
569592

570593
static Error error(const Twine &Message) {
@@ -1520,12 +1543,32 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
15201543
return error("Invalid record");
15211544

15221545
IsDistinct = Record[0] & 1;
1523-
bool HasOpFragment = Record[0] & 2;
1546+
uint64_t Version = Record[0] >> 1;
15241547
auto Elts = MutableArrayRef<uint64_t>(Record).slice(1);
1525-
if (!HasOpFragment)
1526-
if (unsigned N = Elts.size())
1527-
if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece)
1528-
Elts[N - 3] = dwarf::DW_OP_LLVM_fragment;
1548+
unsigned N = Elts.size();
1549+
// Perform various upgrades.
1550+
switch (Version) {
1551+
case 0:
1552+
if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece)
1553+
Elts[N - 3] = dwarf::DW_OP_LLVM_fragment;
1554+
LLVM_FALLTHROUGH;
1555+
case 1:
1556+
// Move DW_OP_deref to the end.
1557+
if (N && Elts[0] == dwarf::DW_OP_deref) {
1558+
auto End = Elts.end();
1559+
if (Elts.size() >= 3 && *std::prev(End, 3) == dwarf::DW_OP_LLVM_fragment)
1560+
End = std::prev(End, 3);
1561+
std::move(std::next(Elts.begin()), End, Elts.begin());
1562+
*std::prev(End) = dwarf::DW_OP_deref;
1563+
}
1564+
NeedDeclareExpressionUpgrade = true;
1565+
LLVM_FALLTHROUGH;
1566+
case 2:
1567+
// Up-to-date!
1568+
break;
1569+
default:
1570+
return error("Invalid record");
1571+
}
15291572

15301573
MetadataList.assignValue(
15311574
GET_OR_DISTINCT(DIExpression, (Context, makeArrayRef(Record).slice(1))),
@@ -1858,3 +1901,7 @@ bool MetadataLoader::isStrippingTBAA() { return Pimpl->isStrippingTBAA(); }
18581901

18591902
unsigned MetadataLoader::size() const { return Pimpl->size(); }
18601903
void MetadataLoader::shrinkTo(unsigned N) { return Pimpl->shrinkTo(N); }
1904+
1905+
void MetadataLoader::upgradeDebugIntrinsics(Function &F) {
1906+
return Pimpl->upgradeDebugIntrinsics(F);
1907+
}

lib/Bitcode/Reader/MetadataLoader.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ class MetadataLoader {
7979

8080
unsigned size() const;
8181
void shrinkTo(unsigned N);
82+
83+
/// Perform bitcode upgrades on llvm.dbg.* calls.
84+
void upgradeDebugIntrinsics(Function &F);
8285
};
8386
}
8487

lib/Bitcode/Writer/BitcodeWriter.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1771,9 +1771,8 @@ void ModuleBitcodeWriter::writeDIExpression(const DIExpression *N,
17711771
SmallVectorImpl<uint64_t> &Record,
17721772
unsigned Abbrev) {
17731773
Record.reserve(N->getElements().size() + 1);
1774-
1775-
const uint64_t HasOpFragmentFlag = 1 << 1;
1776-
Record.push_back((uint64_t)N->isDistinct() | HasOpFragmentFlag);
1774+
const uint64_t Version = 2 << 1;
1775+
Record.push_back((uint64_t)N->isDistinct() | Version);
17771776
Record.append(N->elements_begin(), N->elements_end());
17781777

17791778
Stream.EmitRecord(bitc::METADATA_EXPRESSION, Record, Abbrev);

lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -834,17 +834,17 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
834834
OS << " <- ";
835835

836836
// The second operand is only an offset if it's an immediate.
837-
bool Deref = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
838-
int64_t Offset = Deref ? MI->getOperand(1).getImm() : 0;
839-
837+
bool Deref = false;
838+
bool MemLoc = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
839+
int64_t Offset = MemLoc ? MI->getOperand(1).getImm() : 0;
840840
for (unsigned i = 0; i < Expr->getNumElements(); ++i) {
841841
uint64_t Op = Expr->getElement(i);
842842
if (Op == dwarf::DW_OP_LLVM_fragment) {
843843
// There can't be any operands after this in a valid expression
844844
break;
845845
} else if (Deref) {
846846
// We currently don't support extra Offsets or derefs after the first
847-
// one. Bail out early instead of emitting an incorrect comment
847+
// one. Bail out early instead of emitting an incorrect comment.
848848
OS << " [complex expression]";
849849
AP.OutStreamer->emitRawComment(OS.str());
850850
return true;
@@ -899,12 +899,12 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
899899
AP.OutStreamer->emitRawComment(OS.str());
900900
return true;
901901
}
902-
if (Deref)
902+
if (MemLoc || Deref)
903903
OS << '[';
904904
OS << PrintReg(Reg, AP.MF->getSubtarget().getRegisterInfo());
905905
}
906906

907-
if (Deref)
907+
if (MemLoc || Deref)
908908
OS << '+' << Offset << ']';
909909

910910
// NOTE: Want this comment at start of line, don't emit with AddComment.

lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -547,18 +547,19 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
547547
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
548548
for (auto &Fragment : DV.getFrameIndexExprs()) {
549549
unsigned FrameReg = 0;
550+
const DIExpression *Expr = Fragment.Expr;
550551
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
551552
int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg);
552-
DwarfExpr.addFragmentOffset(Fragment.Expr);
553+
DwarfExpr.addFragmentOffset(Expr);
553554
SmallVector<uint64_t, 8> Ops;
554555
Ops.push_back(dwarf::DW_OP_plus);
555556
Ops.push_back(Offset);
556-
Ops.push_back(dwarf::DW_OP_deref);
557-
Ops.append(Fragment.Expr->elements_begin(), Fragment.Expr->elements_end());
558-
DIExpressionCursor Expr(Ops);
559-
DwarfExpr.addMachineRegExpression(
560-
*Asm->MF->getSubtarget().getRegisterInfo(), Expr, FrameReg);
561-
DwarfExpr.addExpression(std::move(Expr));
557+
Ops.append(Expr->elements_begin(), Expr->elements_end());
558+
DIExpressionCursor Cursor(Ops);
559+
DwarfExpr.addMachineLocExpression(
560+
*Asm->MF->getSubtarget().getRegisterInfo(), Cursor,
561+
MachineLocation(FrameReg));
562+
DwarfExpr.addExpression(std::move(Cursor));
562563
}
563564
addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize());
564565

@@ -781,14 +782,13 @@ void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute,
781782
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
782783

783784
SmallVector<uint64_t, 8> Ops;
784-
if (Location.isIndirect()) {
785+
if (Location.isIndirect() && Location.getOffset()) {
785786
Ops.push_back(dwarf::DW_OP_plus);
786787
Ops.push_back(Location.getOffset());
787-
Ops.push_back(dwarf::DW_OP_deref);
788788
}
789789
DIExpressionCursor Cursor(Ops);
790790
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
791-
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
791+
if (!DwarfExpr.addMachineLocExpression(TRI, Cursor, Location))
792792
return;
793793
DwarfExpr.addExpression(std::move(Cursor));
794794

@@ -809,15 +809,14 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
809809
DwarfExpr.addFragmentOffset(DIExpr);
810810

811811
SmallVector<uint64_t, 8> Ops;
812-
if (Location.isIndirect()) {
812+
if (Location.isIndirect() && Location.getOffset()) {
813813
Ops.push_back(dwarf::DW_OP_plus);
814814
Ops.push_back(Location.getOffset());
815-
Ops.push_back(dwarf::DW_OP_deref);
816815
}
817816
Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
818817
DIExpressionCursor Cursor(Ops);
819818
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
820-
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
819+
if (!DwarfExpr.addMachineLocExpression(TRI, Cursor, Location))
821820
return;
822821
DwarfExpr.addExpression(std::move(Cursor));
823822

lib/CodeGen/AsmPrinter/DwarfDebug.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,18 +1517,15 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
15171517
DwarfExpr.addUnsignedConstant(Value.getInt());
15181518
} else if (Value.isLocation()) {
15191519
MachineLocation Location = Value.getLoc();
1520-
15211520
SmallVector<uint64_t, 8> Ops;
1522-
// FIXME: Should this condition be Location.isIndirect() instead?
1523-
if (Location.getOffset()) {
1521+
if (Location.isIndirect() && Location.getOffset()) {
15241522
Ops.push_back(dwarf::DW_OP_plus);
15251523
Ops.push_back(Location.getOffset());
1526-
Ops.push_back(dwarf::DW_OP_deref);
15271524
}
15281525
Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
15291526
DIExpressionCursor Cursor(Ops);
15301527
const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo();
1531-
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
1528+
if (!DwarfExpr.addMachineLocExpression(TRI, Cursor, Location))
15321529
return;
15331530
return DwarfExpr.addExpression(std::move(Cursor));
15341531
} else if (Value.isConstantFP()) {

0 commit comments

Comments
 (0)