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
This commit is contained in:
Adrian Prantl 2017-04-18 01:21:53 +00:00
parent cc56be2830
commit b560ea777b
37 changed files with 383 additions and 180 deletions

View File

@ -4380,7 +4380,7 @@ referenced LLVM variable relates to the source language variable.
The current supported vocabulary is limited:
- ``DW_OP_deref`` dereferences the working expression.
- ``DW_OP_deref`` dereferences the top of the expression stack.
- ``DW_OP_plus, 93`` adds ``93`` to the working expression.
- ``DW_OP_LLVM_fragment, 16, 8`` specifies the offset and size (``16`` and ``8``
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
location descriptions that describe constant values. This form is used to
describe global constants that have been optimized away. All other expressions
are modifiers to another location: A debug intrinsic ties a location and a
DIExpression together. Contrary to DWARF expressions, a DIExpression always
describes the *value* of a source variable and never its *address*. In DWARF
terminology, a DIExpression can always be considered an implicit location
description regardless whether it contains a ``DW_OP_stack_value`` or not.
DIExpression together.
.. code-block:: text
DWARF specifies three kinds of simple location descriptions: Register, memory,
and implicit location descriptions. Register and memory location descriptions
describe the *location* of a source variable (in the sense that a debugger might
modify its value), whereas implicit locations describe merely the *value* of a
source variable. DIExpressions also follow this model: A DIExpression that
doesn't have a trailing ``DW_OP_stack_value`` will describe an *address* when
combined with a concrete location.
.. code-block:: llvm
!0 = !DIExpression(DW_OP_deref)
!1 = !DIExpression(DW_OP_plus, 3)

View File

@ -180,11 +180,27 @@ provide debug information at various points in generated code.
void @llvm.dbg.declare(metadata, metadata, metadata)
This intrinsic provides information about a local element (e.g., variable).
The first argument is metadata holding the alloca for the variable. The second
This intrinsic provides information about a local element (e.g., variable). The
first argument is metadata holding the alloca for the variable. The second
argument is a `local variable <LangRef.html#dilocalvariable>`_ containing a
description of the variable. The third argument is a `complex expression
<LangRef.html#diexpression>`_.
<LangRef.html#diexpression>`_. An `llvm.dbg.declare` instrinsic describes the
*location* of a source variable.
.. code-block:: llvm
%i.addr = alloca i32, align 4
call void @llvm.dbg.declare(metadata i32* %i.addr, metadata !1, metadata !2), !dbg !3
!1 = !DILocalVariable(name: "i", ...) ; int i
!2 = !DIExpression()
!3 = !DILocation(...)
...
%buffer = alloca [256 x i8], align 8
; The address of i is buffer+64.
call void @llvm.dbg.declare(metadata [256 x i8]* %buffer, metadata !1, metadata !2)
!1 = !DILocalVariable(name: "i", ...) ; int i
!2 = !DIExpression(DW_OP_plus, 64)
``llvm.dbg.value``
^^^^^^^^^^^^^^^^^^

View File

@ -413,6 +413,11 @@ MachineInstrBuilder BuildMI(MachineBasicBlock &BB,
unsigned Reg, unsigned Offset,
const MDNode *Variable, const MDNode *Expr);
/// Clone a DBG_VALUE whose value has been spilled to FrameIndex.
MachineInstr *buildDbgValueForSpill(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const MachineInstr &Orig, int FrameIndex);
inline unsigned getDefRegState(bool B) {
return B ? RegState::Define : 0;
}

View File

@ -2232,6 +2232,9 @@ public:
expr_op_iterator expr_op_end() const {
return expr_op_iterator(elements_end());
}
iterator_range<expr_op_iterator> expr_ops() const {
return {expr_op_begin(), expr_op_end()};
}
/// @}
bool isValid() const;
@ -2240,7 +2243,7 @@ public:
return MD->getMetadataID() == DIExpressionKind;
}
/// Is the first element a DW_OP_deref?.
/// Return whether the first element a DW_OP_deref.
bool startsWithDeref() const {
return getNumElements() > 0 && getElement(0) == dwarf::DW_OP_deref;
}

View File

@ -2631,6 +2631,7 @@ Error BitcodeReader::globalCleanup() {
// Look for intrinsic functions which need to be upgraded at some point
for (Function &F : *TheModule) {
MDLoader->upgradeDebugIntrinsics(F);
Function *NewFn;
if (UpgradeIntrinsicFunction(&F, NewFn))
UpgradedIntrinsics[&F] = NewFn;

View File

@ -54,6 +54,7 @@
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSummaryIndex.h"
@ -452,6 +453,7 @@ class MetadataLoader::MetadataLoaderImpl {
bool StripTBAA = false;
bool HasSeenOldLoopTags = false;
bool NeedUpgradeToDIGlobalVariableExpression = false;
bool NeedDeclareExpressionUpgrade = false;
/// True if metadata is being parsed for a module being ThinLTO imported.
bool IsImporting = false;
@ -511,6 +513,26 @@ class MetadataLoader::MetadataLoaderImpl {
}
}
/// Remove a leading DW_OP_deref from DIExpressions in a dbg.declare that
/// describes a function argument.
void upgradeDeclareExpressions(Function &F) {
if (!NeedDeclareExpressionUpgrade)
return;
for (auto &BB : F)
for (auto &I : BB)
if (auto *DDI = dyn_cast<DbgDeclareInst>(&I))
if (auto *DIExpr = DDI->getExpression())
if (DIExpr->startsWithDeref() &&
dyn_cast_or_null<Argument>(DDI->getAddress())) {
SmallVector<uint64_t, 8> Ops;
Ops.append(std::next(DIExpr->elements_begin()),
DIExpr->elements_end());
auto *E = DIExpression::get(Context, Ops);
DDI->setOperand(2, MetadataAsValue::get(Context, E));
}
}
void upgradeDebugInfo() {
upgradeCUSubprograms();
upgradeCUVariables();
@ -565,6 +587,7 @@ public:
unsigned size() const { return MetadataList.size(); }
void shrinkTo(unsigned N) { MetadataList.shrinkTo(N); }
void upgradeDebugIntrinsics(Function &F) { upgradeDeclareExpressions(F); }
};
static Error error(const Twine &Message) {
@ -1520,12 +1543,32 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
return error("Invalid record");
IsDistinct = Record[0] & 1;
bool HasOpFragment = Record[0] & 2;
uint64_t Version = Record[0] >> 1;
auto Elts = MutableArrayRef<uint64_t>(Record).slice(1);
if (!HasOpFragment)
if (unsigned N = Elts.size())
if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece)
Elts[N - 3] = dwarf::DW_OP_LLVM_fragment;
unsigned N = Elts.size();
// Perform various upgrades.
switch (Version) {
case 0:
if (N >= 3 && Elts[N - 3] == dwarf::DW_OP_bit_piece)
Elts[N - 3] = dwarf::DW_OP_LLVM_fragment;
LLVM_FALLTHROUGH;
case 1:
// Move DW_OP_deref to the end.
if (N && Elts[0] == dwarf::DW_OP_deref) {
auto End = Elts.end();
if (Elts.size() >= 3 && *std::prev(End, 3) == dwarf::DW_OP_LLVM_fragment)
End = std::prev(End, 3);
std::move(std::next(Elts.begin()), End, Elts.begin());
*std::prev(End) = dwarf::DW_OP_deref;
}
NeedDeclareExpressionUpgrade = true;
LLVM_FALLTHROUGH;
case 2:
// Up-to-date!
break;
default:
return error("Invalid record");
}
MetadataList.assignValue(
GET_OR_DISTINCT(DIExpression, (Context, makeArrayRef(Record).slice(1))),
@ -1858,3 +1901,7 @@ bool MetadataLoader::isStrippingTBAA() { return Pimpl->isStrippingTBAA(); }
unsigned MetadataLoader::size() const { return Pimpl->size(); }
void MetadataLoader::shrinkTo(unsigned N) { return Pimpl->shrinkTo(N); }
void MetadataLoader::upgradeDebugIntrinsics(Function &F) {
return Pimpl->upgradeDebugIntrinsics(F);
}

View File

@ -79,6 +79,9 @@ public:
unsigned size() const;
void shrinkTo(unsigned N);
/// Perform bitcode upgrades on llvm.dbg.* calls.
void upgradeDebugIntrinsics(Function &F);
};
}

View File

@ -1771,9 +1771,8 @@ void ModuleBitcodeWriter::writeDIExpression(const DIExpression *N,
SmallVectorImpl<uint64_t> &Record,
unsigned Abbrev) {
Record.reserve(N->getElements().size() + 1);
const uint64_t HasOpFragmentFlag = 1 << 1;
Record.push_back((uint64_t)N->isDistinct() | HasOpFragmentFlag);
const uint64_t Version = 2 << 1;
Record.push_back((uint64_t)N->isDistinct() | Version);
Record.append(N->elements_begin(), N->elements_end());
Stream.EmitRecord(bitc::METADATA_EXPRESSION, Record, Abbrev);

View File

@ -834,9 +834,9 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
OS << " <- ";
// The second operand is only an offset if it's an immediate.
bool Deref = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
int64_t Offset = Deref ? MI->getOperand(1).getImm() : 0;
bool Deref = false;
bool MemLoc = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
int64_t Offset = MemLoc ? MI->getOperand(1).getImm() : 0;
for (unsigned i = 0; i < Expr->getNumElements(); ++i) {
uint64_t Op = Expr->getElement(i);
if (Op == dwarf::DW_OP_LLVM_fragment) {
@ -844,7 +844,7 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
break;
} else if (Deref) {
// We currently don't support extra Offsets or derefs after the first
// one. Bail out early instead of emitting an incorrect comment
// one. Bail out early instead of emitting an incorrect comment.
OS << " [complex expression]";
AP.OutStreamer->emitRawComment(OS.str());
return true;
@ -899,12 +899,12 @@ static bool emitDebugValueComment(const MachineInstr *MI, AsmPrinter &AP) {
AP.OutStreamer->emitRawComment(OS.str());
return true;
}
if (Deref)
if (MemLoc || Deref)
OS << '[';
OS << PrintReg(Reg, AP.MF->getSubtarget().getRegisterInfo());
}
if (Deref)
if (MemLoc || Deref)
OS << '+' << Offset << ']';
// NOTE: Want this comment at start of line, don't emit with AddComment.

View File

@ -547,18 +547,19 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
for (auto &Fragment : DV.getFrameIndexExprs()) {
unsigned FrameReg = 0;
const DIExpression *Expr = Fragment.Expr;
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
int Offset = TFI->getFrameIndexReference(*Asm->MF, Fragment.FI, FrameReg);
DwarfExpr.addFragmentOffset(Fragment.Expr);
DwarfExpr.addFragmentOffset(Expr);
SmallVector<uint64_t, 8> Ops;
Ops.push_back(dwarf::DW_OP_plus);
Ops.push_back(Offset);
Ops.push_back(dwarf::DW_OP_deref);
Ops.append(Fragment.Expr->elements_begin(), Fragment.Expr->elements_end());
DIExpressionCursor Expr(Ops);
DwarfExpr.addMachineRegExpression(
*Asm->MF->getSubtarget().getRegisterInfo(), Expr, FrameReg);
DwarfExpr.addExpression(std::move(Expr));
Ops.append(Expr->elements_begin(), Expr->elements_end());
DIExpressionCursor Cursor(Ops);
DwarfExpr.addMachineLocExpression(
*Asm->MF->getSubtarget().getRegisterInfo(), Cursor,
MachineLocation(FrameReg));
DwarfExpr.addExpression(std::move(Cursor));
}
addBlock(*VariableDie, dwarf::DW_AT_location, DwarfExpr.finalize());
@ -781,14 +782,13 @@ void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute,
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
SmallVector<uint64_t, 8> Ops;
if (Location.isIndirect()) {
if (Location.isIndirect() && Location.getOffset()) {
Ops.push_back(dwarf::DW_OP_plus);
Ops.push_back(Location.getOffset());
Ops.push_back(dwarf::DW_OP_deref);
}
DIExpressionCursor Cursor(Ops);
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
if (!DwarfExpr.addMachineLocExpression(TRI, Cursor, Location))
return;
DwarfExpr.addExpression(std::move(Cursor));
@ -809,15 +809,14 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
DwarfExpr.addFragmentOffset(DIExpr);
SmallVector<uint64_t, 8> Ops;
if (Location.isIndirect()) {
if (Location.isIndirect() && Location.getOffset()) {
Ops.push_back(dwarf::DW_OP_plus);
Ops.push_back(Location.getOffset());
Ops.push_back(dwarf::DW_OP_deref);
}
Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
DIExpressionCursor Cursor(Ops);
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
if (!DwarfExpr.addMachineLocExpression(TRI, Cursor, Location))
return;
DwarfExpr.addExpression(std::move(Cursor));

View File

@ -1517,18 +1517,15 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
DwarfExpr.addUnsignedConstant(Value.getInt());
} else if (Value.isLocation()) {
MachineLocation Location = Value.getLoc();
SmallVector<uint64_t, 8> Ops;
// FIXME: Should this condition be Location.isIndirect() instead?
if (Location.getOffset()) {
if (Location.isIndirect() && Location.getOffset()) {
Ops.push_back(dwarf::DW_OP_plus);
Ops.push_back(Location.getOffset());
Ops.push_back(dwarf::DW_OP_deref);
}
Ops.append(DIExpr->elements_begin(), DIExpr->elements_end());
DIExpressionCursor Cursor(Ops);
const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo();
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
if (!DwarfExpr.addMachineLocExpression(TRI, Cursor, Location))
return;
return DwarfExpr.addExpression(std::move(Cursor));
} else if (Value.isConstantFP()) {

View File

@ -23,9 +23,12 @@
using namespace llvm;
void DwarfExpression::addReg(int DwarfReg, const char *Comment) {
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
if (DwarfReg < 32) {
emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment);
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
assert((LocationKind == Unknown || LocationKind == Register) &&
"location description already locked down");
LocationKind = Register;
if (DwarfReg < 32) {
emitOp(dwarf::DW_OP_reg0 + DwarfReg, Comment);
} else {
emitOp(dwarf::DW_OP_regx, Comment);
emitUnsigned(DwarfReg);
@ -34,6 +37,7 @@ void DwarfExpression::addReg(int DwarfReg, const char *Comment) {
void DwarfExpression::addBReg(int DwarfReg, int Offset) {
assert(DwarfReg >= 0 && "invalid negative dwarf register number");
assert(LocationKind != Register && "location description already locked down");
if (DwarfReg < 32) {
emitOp(dwarf::DW_OP_breg0 + DwarfReg);
} else {
@ -156,18 +160,23 @@ void DwarfExpression::addStackValue() {
}
void DwarfExpression::addSignedConstant(int64_t Value) {
assert(LocationKind == Implicit || LocationKind == Unknown);
LocationKind = Implicit;
emitOp(dwarf::DW_OP_consts);
emitSigned(Value);
addStackValue();
}
void DwarfExpression::addUnsignedConstant(uint64_t Value) {
assert(LocationKind == Implicit || LocationKind == Unknown);
LocationKind = Implicit;
emitOp(dwarf::DW_OP_constu);
emitUnsigned(Value);
addStackValue();
}
void DwarfExpression::addUnsignedConstant(const APInt &Value) {
assert(LocationKind == Implicit || LocationKind == Unknown);
LocationKind = Implicit;
unsigned Size = Value.getBitWidth();
const uint64_t *Data = Value.getRawData();
@ -178,15 +187,20 @@ void DwarfExpression::addUnsignedConstant(const APInt &Value) {
addUnsignedConstant(*Data++);
if (Offset == 0 && Size <= 64)
break;
addOpPiece(std::min(Size-Offset, 64u), Offset);
addStackValue();
addOpPiece(std::min(Size - Offset, 64u), Offset);
Offset += 64;
}
}
bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
bool DwarfExpression::addMachineLocExpression(const TargetRegisterInfo &TRI,
DIExpressionCursor &ExprCursor,
unsigned MachineReg,
MachineLocation Loc,
unsigned FragmentOffsetInBits) {
if (Loc.isIndirect())
LocationKind = Memory;
unsigned MachineReg = Loc.getReg();
auto Fragment = ExprCursor.getFragmentInfo();
if (!addMachineReg(TRI, MachineReg, Fragment ? Fragment->SizeInBits : ~1U))
return false;
@ -206,7 +220,7 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
}
// Handle simple register locations.
if (!HasComplexExpression) {
if (LocationKind != Memory && !HasComplexExpression) {
for (auto &Reg : DwarfRegs) {
if (Reg.DwarfRegNo >= 0)
addReg(Reg.DwarfRegNo, Reg.Comment);
@ -216,62 +230,58 @@ bool DwarfExpression::addMachineRegExpression(const TargetRegisterInfo &TRI,
return true;
}
// FIXME:
// Don't emit locations that cannot be expressed without DW_OP_stack_value.
assert(DwarfRegs.size() == 1);
auto Reg = DwarfRegs[0];
bool FBReg = isFrameRegister(TRI, MachineReg);
bool FBReg = isFrameRegister(TRI, MachineReg);
int SignedOffset = 0;
assert(Reg.Size == 0 && "subregister has same size as superregister");
// Pattern-match combinations for which more efficient representations exist.
switch (Op->getOp()) {
default: {
if (FBReg)
addFBReg(0);
else
addReg(Reg.DwarfRegNo, 0);
break;
}
case dwarf::DW_OP_plus:
case dwarf::DW_OP_minus: {
// [DW_OP_reg,Offset,DW_OP_plus, DW_OP_deref] --> [DW_OP_breg, Offset].
// [DW_OP_reg,Offset,DW_OP_minus,DW_OP_deref] --> [DW_OP_breg,-Offset].
auto N = ExprCursor.peekNext();
if (N && N->getOp() == dwarf::DW_OP_deref) {
int Offset = Op->getArg(0);
int SignedOffset = (Op->getOp() == dwarf::DW_OP_plus) ? Offset : -Offset;
if (FBReg)
addFBReg(SignedOffset);
else
addBReg(Reg.DwarfRegNo, SignedOffset);
ExprCursor.consume(2);
break;
}
addReg(Reg.DwarfRegNo, 0);
break;
}
case dwarf::DW_OP_deref:
// [DW_OP_reg,DW_OP_deref] --> [DW_OP_breg].
if (FBReg)
addFBReg(0);
else
addBReg(Reg.DwarfRegNo, 0);
// [Reg, Offset, DW_OP_plus] --> [DW_OP_breg, Offset].
// [Reg, Offset, DW_OP_minus] --> [DW_OP_breg, -Offset].
// If Reg is a subregister we need to mask it out before subtracting.
if (Op && ((Op->getOp() == dwarf::DW_OP_plus) ||
(Op->getOp() == dwarf::DW_OP_minus && !SubRegisterSizeInBits))) {
int Offset = Op->getArg(0);
SignedOffset = (Op->getOp() == dwarf::DW_OP_plus) ? Offset : -Offset;
ExprCursor.take();
break;
}
if (FBReg)
addFBReg(SignedOffset);
else
addBReg(Reg.DwarfRegNo, SignedOffset);
DwarfRegs.clear();
return true;
}
/// Assuming a well-formed expression, match "DW_OP_deref* DW_OP_LLVM_fragment?".
static bool isMemoryLocation(DIExpressionCursor ExprCursor) {
while (ExprCursor) {
auto Op = ExprCursor.take();
switch (Op->getOp()) {
case dwarf::DW_OP_deref:
case dwarf::DW_OP_LLVM_fragment:
break;
default:
return false;
}
}
return true;
}
void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
unsigned FragmentOffsetInBits) {
// If we need to mask out a subregister, do it now, unless the next
// operation would emit an OpPiece anyway.
auto N = ExprCursor.peek();
if (SubRegisterSizeInBits && N && (N->getOp() != dwarf::DW_OP_LLVM_fragment))
maskSubRegister();
while (ExprCursor) {
auto Op = ExprCursor.take();
// If we need to mask out a subregister, do it now, unless the next
// operation would emit an OpPiece anyway.
if (SubRegisterSizeInBits && Op->getOp() != dwarf::DW_OP_LLVM_fragment)
maskSubRegister();
switch (Op->getOp()) {
case dwarf::DW_OP_LLVM_fragment: {
unsigned SizeInBits = Op->getArg(1);
@ -281,50 +291,74 @@ void DwarfExpression::addExpression(DIExpressionCursor &&ExprCursor,
// location.
assert(OffsetInBits >= FragmentOffset && "fragment offset not added?");
// If \a addMachineReg already emitted DW_OP_piece operations to represent
// If addMachineReg already emitted DW_OP_piece operations to represent
// a super-register by splicing together sub-registers, subtract the size
// of the pieces that was already emitted.
SizeInBits -= OffsetInBits - FragmentOffset;
// If \a addMachineReg requested a DW_OP_bit_piece to stencil out a
// If addMachineReg requested a DW_OP_bit_piece to stencil out a
// sub-register that is smaller than the current fragment's size, use it.
if (SubRegisterSizeInBits)
SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits);
// Emit a DW_OP_stack_value for implicit location descriptions.
if (LocationKind == Implicit)
addStackValue();
// Emit the DW_OP_piece.
addOpPiece(SizeInBits, SubRegisterOffsetInBits);
setSubRegisterPiece(0, 0);
break;
// Reset the location description kind.
LocationKind = Unknown;
return;
}
case dwarf::DW_OP_plus:
assert(LocationKind != Register);
emitOp(dwarf::DW_OP_plus_uconst);
emitUnsigned(Op->getArg(0));
break;
case dwarf::DW_OP_minus:
// There is no OP_minus_uconst.
assert(LocationKind != Register);
// There is no DW_OP_minus_uconst.
emitOp(dwarf::DW_OP_constu);
emitUnsigned(Op->getArg(0));
emitOp(dwarf::DW_OP_minus);
break;
case dwarf::DW_OP_deref:
emitOp(dwarf::DW_OP_deref);
case dwarf::DW_OP_deref: {
assert(LocationKind != Register);
if (LocationKind != Memory && isMemoryLocation(ExprCursor))
// Turning this into a memory location description makes the deref
// implicit.
LocationKind = Memory;
else
emitOp(dwarf::DW_OP_deref);
break;
}
case dwarf::DW_OP_constu:
assert(LocationKind != Register);
emitOp(dwarf::DW_OP_constu);
emitUnsigned(Op->getArg(0));
break;
case dwarf::DW_OP_stack_value:
addStackValue();
assert(LocationKind == Unknown || LocationKind == Implicit);
LocationKind = Implicit;
break;
case dwarf::DW_OP_swap:
assert(LocationKind != Register);
emitOp(dwarf::DW_OP_swap);
break;
case dwarf::DW_OP_xderef:
assert(LocationKind != Register);
emitOp(dwarf::DW_OP_xderef);
break;
default:
llvm_unreachable("unhandled opcode found in expression");
}
}
if (LocationKind == Implicit)
// Turn this into an implicit location description.
addStackValue();
}
/// add masking operations to stencil out a subregister.

View File

@ -16,6 +16,7 @@
#include "llvm/IR/DebugInfo.h"
#include "llvm/Support/DataTypes.h"
#include "llvm/MC/MachineLocation.h"
namespace llvm {
@ -102,6 +103,9 @@ protected:
unsigned SubRegisterSizeInBits = 0;
unsigned SubRegisterOffsetInBits = 0;
/// The kind of location description being produced.
enum { Unknown = 0, Register, Memory, Implicit } LocationKind = Unknown;
/// Push a DW_OP_piece / DW_OP_bit_piece for emitting later, if one is needed
/// to represent a subregister.
void setSubRegisterPiece(unsigned SizeInBits, unsigned OffsetInBits) {
@ -109,6 +113,8 @@ protected:
SubRegisterOffsetInBits = OffsetInBits;
}
void setMemoryLocationKind();
/// Add masking operations to stencil out a subregister.
void maskSubRegister();
@ -122,7 +128,8 @@ protected:
/// current function.
virtual bool isFrameRegister(const TargetRegisterInfo &TRI, unsigned MachineReg) = 0;
/// Emit a DW_OP_reg operation.
/// Emit a DW_OP_reg operation. Note that this is only legal inside a DWARF
/// register location description.
void addReg(int DwarfReg, const char *Comment = nullptr);
/// Emit a DW_OP_breg operation.
void addBReg(int DwarfReg, int Offset);
@ -194,8 +201,8 @@ public:
/// fragment inside the entire variable.
/// \return false if no DWARF register exists
/// for MachineReg.
bool addMachineRegExpression(const TargetRegisterInfo &TRI,
DIExpressionCursor &Expr, unsigned MachineReg,
bool addMachineLocExpression(const TargetRegisterInfo &TRI,
DIExpressionCursor &Expr, MachineLocation Loc,
unsigned FragmentOffsetInBits = 0);
/// Emit all remaining operations in the DIExpressionCursor.
///

View File

@ -474,10 +474,9 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
SmallVector<uint64_t, 9> Ops;
if (Location.isIndirect()) {
if (Location.isIndirect() && Location.getOffset()) {
Ops.push_back(dwarf::DW_OP_plus);
Ops.push_back(Location.getOffset());
Ops.push_back(dwarf::DW_OP_deref);
}
// If we started with a pointer to the __Block_byref... struct, then
// the first thing we need to do is dereference the pointer (DW_OP_deref).
@ -506,7 +505,7 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
DIExpressionCursor Cursor(Ops);
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
if (!DwarfExpr.addMachineLocExpression(TRI, Cursor, Location))
return;
DwarfExpr.addExpression(std::move(Cursor));

View File

@ -888,20 +888,10 @@ void InlineSpiller::spillAroundUses(unsigned Reg) {
// Debug values are not allowed to affect codegen.
if (MI->isDebugValue()) {
// Modify DBG_VALUE now that the value is in a spill slot.
bool IsIndirect = MI->isIndirectDebugValue();
uint64_t Offset = IsIndirect ? MI->getOperand(1).getImm() : 0;
const MDNode *Var = MI->getDebugVariable();
const MDNode *Expr = MI->getDebugExpression();
DebugLoc DL = MI->getDebugLoc();
DEBUG(dbgs() << "Modifying debug info due to spill:" << "\t" << *MI);
MachineBasicBlock *MBB = MI->getParent();
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
BuildMI(*MBB, MBB->erase(MI), DL, TII.get(TargetOpcode::DBG_VALUE))
.addFrameIndex(StackSlot)
.addImm(Offset)
.addMetadata(Var)
.addMetadata(Expr);
DEBUG(dbgs() << "Modifying debug info due to spill:\t" << *MI);
buildDbgValueForSpill(*MBB, MI, *MI, StackSlot);
MBB->erase(MI);
continue;
}

View File

@ -2351,3 +2351,31 @@ MachineInstrBuilder llvm::BuildMI(MachineBasicBlock &BB,
BB.insert(I, MI);
return MachineInstrBuilder(MF, MI);
}
MachineInstr *llvm::buildDbgValueForSpill(MachineBasicBlock &BB,
MachineBasicBlock::iterator I,
const MachineInstr &Orig,
int FrameIndex) {
const MDNode *Var = Orig.getDebugVariable();
auto *Expr = cast_or_null<DIExpression>(Orig.getDebugExpression());
bool IsIndirect = Orig.isIndirectDebugValue();
uint64_t Offset = IsIndirect ? Orig.getOperand(1).getImm() : 0;
DebugLoc DL = Orig.getDebugLoc();
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
// If the DBG_VALUE already was a memory location, add an extra
// DW_OP_deref. Otherwise just turning this from a register into a
// memory/indirect location is sufficient.
if (IsIndirect) {
SmallVector<uint64_t, 8> Ops;
Ops.push_back(dwarf::DW_OP_deref);
if (Expr)
Ops.append(Expr->elements_begin(), Expr->elements_end());
Expr = DIExpression::get(Expr->getContext(), Ops);
}
return BuildMI(BB, I, DL, Orig.getDesc())
.addFrameIndex(FrameIndex)
.addImm(Offset)
.addMetadata(Var)
.addMetadata(Expr);
}

View File

@ -304,19 +304,7 @@ void RAFast::spillVirtReg(MachineBasicBlock::iterator MI,
LiveDbgValueMap[LRI->VirtReg];
for (unsigned li = 0, le = LRIDbgValues.size(); li != le; ++li) {
MachineInstr *DBG = LRIDbgValues[li];
const MDNode *Var = DBG->getDebugVariable();
const MDNode *Expr = DBG->getDebugExpression();
bool IsIndirect = DBG->isIndirectDebugValue();
uint64_t Offset = IsIndirect ? DBG->getOperand(1).getImm() : 0;
DebugLoc DL = DBG->getDebugLoc();
assert(cast<DILocalVariable>(Var)->isValidLocationForIntrinsic(DL) &&
"Expected inlined-at fields to agree");
MachineInstr *NewDV =
BuildMI(*MBB, MI, DL, TII->get(TargetOpcode::DBG_VALUE))
.addFrameIndex(FI)
.addImm(Offset)
.addMetadata(Var)
.addMetadata(Expr);
MachineInstr *NewDV = buildDbgValueForSpill(*MBB, MI, *DBG, FI);
assert(NewDV->getParent() == MBB && "dangling parent pointer");
(void)NewDV;
DEBUG(dbgs() << "Inserting debug info due to spill:" << "\n" << *NewDV);

View File

@ -550,7 +550,7 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack(
// Replace alloc with the new location.
replaceDbgDeclare(Arg, BasePointer, BasePointer->getNextNode(), DIB,
/*Deref=*/true, -Offset);
/*Deref=*/false, -Offset);
Arg->replaceAllUsesWith(NewArg);
IRB.SetInsertPoint(cast<Instruction>(NewArg)->getNextNode());
IRB.CreateMemCpy(Off, Arg, Size, Arg->getParamAlignment());
@ -565,7 +565,7 @@ Value *SafeStack::moveStaticAllocasToUnsafeStack(
if (Size == 0)
Size = 1; // Don't create zero-sized stack objects.
replaceDbgDeclareForAlloca(AI, BasePointer, DIB, /*Deref=*/true, -Offset);
replaceDbgDeclareForAlloca(AI, BasePointer, DIB, /*Deref=*/false, -Offset);
replaceDbgValueForAlloca(AI, BasePointer, DIB, -Offset);
// Replace uses of the alloca with the new location.
@ -655,7 +655,7 @@ void SafeStack::moveDynamicAllocasToUnsafeStack(
if (AI->hasName() && isa<Instruction>(NewAI))
NewAI->takeName(AI);
replaceDbgDeclareForAlloca(AI, NewAI, DIB, /*Deref=*/true);
replaceDbgDeclareForAlloca(AI, NewAI, DIB, /*Deref=*/false);
AI->replaceAllUsesWith(NewAI);
AI->eraseFromParent();
}

View File

@ -1164,9 +1164,11 @@ bool FastISel::selectIntrinsicCall(const IntrinsicInst *II) {
"Expected inlined-at fields to agree");
if (Op->isReg()) {
Op->setIsDebug(true);
// A dbg.declare describes the address of a source variable, so lower it
// into an indirect DBG_VALUE.
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::DBG_VALUE), false, Op->getReg(), 0,
DI->getVariable(), DI->getExpression());
TII.get(TargetOpcode::DBG_VALUE), /*IsIndirect*/ true,
Op->getReg(), 0, DI->getVariable(), DI->getExpression());
} else
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
TII.get(TargetOpcode::DBG_VALUE))

View File

@ -4674,7 +4674,7 @@ static unsigned getUnderlyingArgReg(const SDValue &N) {
/// At the end of instruction selection, they will be inserted to the entry BB.
bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
const Value *V, DILocalVariable *Variable, DIExpression *Expr,
DILocation *DL, int64_t Offset, bool IsIndirect, const SDValue &N) {
DILocation *DL, int64_t Offset, bool IsDbgDeclare, const SDValue &N) {
const Argument *Arg = dyn_cast<Argument>(V);
if (!Arg)
return false;
@ -4688,6 +4688,7 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
if (!Variable->getScope()->getSubprogram()->describes(MF.getFunction()))
return false;
bool IsIndirect = false;
Optional<MachineOperand> Op;
// Some arguments' frame index is recorded during argument lowering.
if (int FI = FuncInfo.getArgumentFrameIndex(Arg))
@ -4701,15 +4702,19 @@ bool SelectionDAGBuilder::EmitFuncArgumentDbgValue(
if (PR)
Reg = PR;
}
if (Reg)
if (Reg) {
Op = MachineOperand::CreateReg(Reg, false);
IsIndirect = IsDbgDeclare;
}
}
if (!Op) {
// Check if ValueMap has reg number.
DenseMap<const Value *, unsigned>::iterator VMI = FuncInfo.ValueMap.find(V);
if (VMI != FuncInfo.ValueMap.end())
if (VMI != FuncInfo.ValueMap.end()) {
Op = MachineOperand::CreateReg(VMI->second, false);
IsIndirect = IsDbgDeclare;
}
}
if (!Op && N.getNode())
@ -4955,8 +4960,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
} else if (isa<Argument>(Address)) {
// Address is an argument, so try to emit its dbg value using
// virtual register info from the FuncInfo.ValueMap.
EmitFuncArgumentDbgValue(Address, Variable, Expression, dl, 0, false,
N);
EmitFuncArgumentDbgValue(Address, Variable, Expression, dl, 0, true, N);
return nullptr;
} else {
SDV = DAG.getDbgValue(Variable, Expression, N.getNode(), N.getResNo(),
@ -4966,7 +4970,7 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
} else {
// If Address is an argument then try to emit its dbg value using
// virtual register info from the FuncInfo.ValueMap.
if (!EmitFuncArgumentDbgValue(Address, Variable, Expression, dl, 0, false,
if (!EmitFuncArgumentDbgValue(Address, Variable, Expression, dl, 0, true,
N)) {
// If variable is pinned by a alloca in dominating bb then
// use StaticAllocaMap.

View File

@ -928,7 +928,7 @@ private:
/// instruction selection, they will be inserted to the entry BB.
bool EmitFuncArgumentDbgValue(const Value *V, DILocalVariable *Variable,
DIExpression *Expr, DILocation *DL,
int64_t Offset, bool IsIndirect,
int64_t Offset, bool IsDbgDeclare,
const SDValue &N);
/// Return the next block after MBB, or nullptr if there is none.

View File

@ -2586,7 +2586,7 @@ void FunctionStackPoisoner::processStaticAllocas() {
Value *NewAllocaPtr = IRB.CreateIntToPtr(
IRB.CreateAdd(LocalStackBase, ConstantInt::get(IntptrTy, Desc.Offset)),
AI->getType());
replaceDbgDeclareForAlloca(AI, NewAllocaPtr, DIB, /*Deref=*/true);
replaceDbgDeclareForAlloca(AI, NewAllocaPtr, DIB, /*Deref=*/false);
AI->replaceAllUsesWith(NewAllocaPtr);
}

View File

@ -1227,13 +1227,9 @@ bool llvm::LowerDbgDeclare(Function &F) {
// This is a call by-value or some other instruction that
// takes a pointer to the variable. Insert a *value*
// intrinsic that describes the alloca.
SmallVector<uint64_t, 1> NewDIExpr;
auto *DIExpr = DDI->getExpression();
NewDIExpr.push_back(dwarf::DW_OP_deref);
NewDIExpr.append(DIExpr->elements_begin(), DIExpr->elements_end());
DIB.insertDbgValueIntrinsic(AI, 0, DDI->getVariable(),
DIB.createExpression(NewDIExpr),
DDI->getDebugLoc(), CI);
DDI->getExpression(), DDI->getDebugLoc(),
CI);
}
}
DDI->eraseFromParent();

View File

@ -0,0 +1,36 @@
; RUN: llvm-dis -o - %s.bc | FileCheck %s
%class.A = type { i32, i32, i32, i32 }
define void @_Z3fooi(%class.A* sret %agg.result) #0 !dbg !3 {
; CHECK: call void @llvm.dbg.declare({{.*}}, metadata ![[EXPR:[0-9]+]]), !dbg
; CHECK: ![[EXPR]] = !DIExpression()
call void @llvm.dbg.declare(metadata %class.A* %agg.result, metadata !13, metadata !16), !dbg !17
ret void, !dbg !17
}
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1
attributes #0 = { ssp }
attributes #1 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!2}
!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug)
!1 = !DIFile(filename: "a.cc", directory: "/tmp")
!2 = !{i32 1, !"Debug Info Version", i32 3}
!3 = distinct !DISubprogram(name: "foo", linkageName: "_Z3fooi", scope: !1, file: !1, line: 4, type: !4, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !0)
!4 = !DISubroutineType(types: !5)
!5 = !{!6}
!6 = !DICompositeType(tag: DW_TAG_class_type, name: "A", scope: !0, file: !1, line: 2, size: 128, align: 32, elements: !7)
!7 = !{!8, !10, !11, !12}
!8 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !1, file: !1, line: 2, baseType: !9, size: 32, align: 32)
!9 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
!10 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !1, file: !1, line: 2, baseType: !9, size: 32, align: 32, offset: 32)
!11 = !DIDerivedType(tag: DW_TAG_member, name: "z", scope: !1, file: !1, line: 2, baseType: !9, size: 32, align: 32, offset: 64)
!12 = !DIDerivedType(tag: DW_TAG_member, name: "o", scope: !1, file: !1, line: 2, baseType: !9, size: 32, align: 32, offset: 96)
!13 = !DILocalVariable(name: "my_a", scope: !14, file: !1, line: 9, type: !15)
!14 = distinct !DILexicalBlock(scope: !3, file: !1, line: 4, column: 14)
!15 = !DIDerivedType(tag: DW_TAG_reference_type, file: !1, baseType: !6)
!16 = !DIExpression(DW_OP_deref)
!17 = !DILocation(line: 9, column: 5, scope: !3)

Binary file not shown.

View File

@ -0,0 +1,27 @@
; RUN: llvm-dis -o - %s.bc | FileCheck %s
!llvm.dbg.cu = !{!1}
!llvm.module.flags = !{!20, !21}
!0 = distinct !DIGlobalVariable(name: "g", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true)
!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang (llvm/trunk 288154)", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !4)
!2 = !DIFile(filename: "a.c", directory: "/")
!3 = !{}
!4 = !{!10, !11, !12, !13}
!5 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
; DW_OP_deref should be moved to the back of the expression.
;
; CHECK: !DIExpression(DW_OP_plus, 0, DW_OP_deref, DW_OP_LLVM_fragment, 8, 32)
!6 = !DIExpression(DW_OP_deref, DW_OP_plus, 0, DW_OP_LLVM_fragment, 8, 32)
; CHECK: !DIExpression(DW_OP_plus, 0, DW_OP_deref)
!7 = !DIExpression(DW_OP_deref, DW_OP_plus, 0)
; CHECK: !DIExpression(DW_OP_plus, 1, DW_OP_deref)
!8 = !DIExpression(DW_OP_plus, 1, DW_OP_deref)
; CHECK: !DIExpression(DW_OP_deref)
!9 = !DIExpression(DW_OP_deref)
!10 = !DIGlobalVariableExpression(var: !0, expr: !6)
!11 = !DIGlobalVariableExpression(var: !0, expr: !7)
!12 = !DIGlobalVariableExpression(var: !0, expr: !8)
!13 = !DIGlobalVariableExpression(var: !0, expr: !9)
!20 = !{i32 2, !"Dwarf Version", i32 4}
!21 = !{i32 2, !"Debug Info Version", i32 3}

Binary file not shown.

View File

@ -13,7 +13,7 @@ _ZN7Vector39NormalizeEv.exit: ; preds = %1, %0
; and SelectionDAGISel crashes. It should definitely not
; crash. Drop the dbg_value instead.
; CHECK-NOT: "matrix"
tail call void @llvm.dbg.declare(metadata %class.Matrix3.0.6.10* %agg.result, metadata !45, metadata !DIExpression(DW_OP_deref))
tail call void @llvm.dbg.declare(metadata %class.Matrix3.0.6.10* %agg.result, metadata !45, metadata !DIExpression())
%2 = getelementptr inbounds %class.Matrix3.0.6.10, %class.Matrix3.0.6.10* %agg.result, i32 0, i32 0, i32 8
ret void
}

View File

@ -13,7 +13,7 @@
; Check that the location of the ASAN instrumented __block variable is
; correct.
; CHECK: !DIExpression(DW_OP_deref, DW_OP_plus, 8, DW_OP_deref, DW_OP_plus, 24)
; CHECK: !DIExpression(DW_OP_plus, 8, DW_OP_deref, DW_OP_plus, 24)
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"

View File

@ -1,9 +1,17 @@
; RUN: llc -O0 -fast-isel=false < %s | FileCheck %s
; RUN: llc -O0 -fast-isel=true -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-apple-macosx10.6.7"
;Radar 9321650
;CHECK: ##DEBUG_VALUE: my_a
; rdar://problem/9321650
;
; CHECK: DW_AT_name {{.*}}"j"
; CHECK: DW_TAG_variable
; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000)
; CHECK-NEXT: DW_AT_name {{.*}}"my_a"
; CHECK: .debug_loc contents:
; CHECK: 0x00000000: Beginning address offset:
; CHECK-NEXT: Ending address offset:
; CHECK-NEXT: Location description: 77 08
; rsp+8
%class.A = type { i32, i32, i32, i32 }

View File

@ -70,7 +70,7 @@ entry:
; <label>:28 ; preds = %22, %entry
store i32 %0, i32* %3, align 4
call void @llvm.dbg.declare(metadata %struct.A* %agg.result, metadata !24, metadata !DIExpression(DW_OP_deref)), !dbg !25
call void @llvm.dbg.declare(metadata %struct.A* %agg.result, metadata !24, metadata !DIExpression()), !dbg !25
call void @_ZN1AC1Ev(%struct.A* %agg.result), !dbg !25
store i64 1172321806, i64* %4, !dbg !26
%29 = inttoptr i64 %10 to i32*, !dbg !26

View File

@ -107,5 +107,5 @@ define internal void @"__24-[Main initWithContext:]_block_invoke_2"(i8* %.block_
!106 = !DILocation(line: 40, scope: !42)
!107 = !DIFile(filename: "llvm/tools/clang/test/CodeGenObjC/debug-info-block-captured-self.m", directory: "")
!108 = !{i32 1, !"Debug Info Version", i32 3}
!109 = !DIExpression(DW_OP_deref, DW_OP_plus, 32)
!110 = !DIExpression(DW_OP_deref, DW_OP_plus, 32)
!109 = !DIExpression(DW_OP_plus, 32, DW_OP_deref)
!110 = !DIExpression(DW_OP_plus, 32, DW_OP_deref)

View File

@ -10,7 +10,7 @@
; Capture(buf);
; }
; }
; The interesting part is !DIExpression(DW_OP_deref, DW_OP_minus, 400)
; The interesting part is !DIExpression(DW_OP_minus, 400)
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
@ -56,20 +56,17 @@ declare void @Capture(i32*)
!14 = !{i32 2, !"Debug Info Version", i32 3}
!15 = !{!"clang version 3.8.0 (trunk 248518) (llvm/trunk 248512)"}
!16 = !DILocation(line: 5, column: 3, scope: !4)
!17 = !DIExpression(DW_OP_deref, DW_OP_minus, 400)
!17 = !DIExpression(DW_OP_minus, 400)
!18 = !DILocation(line: 5, column: 7, scope: !4)
!19 = !DILocation(line: 6, column: 11, scope: !4)
!20 = !DILocation(line: 6, column: 3, scope: !4)
!21 = !DILocation(line: 7, column: 1, scope: !4)
; RCX - 400
; CHECK: .short 6 # Loc expr size
; CHECK: .short 3 # Loc expr size
; CHECK-NEXT: .byte 114 # DW_OP_breg2
; CHECK-NEXT: .byte 0 # 0
; CHECK-NEXT: .byte 16 # DW_OP_constu
; CHECK-NEXT: .byte 144 # 400
; CHECK-NEXT: .byte 3 # DW_OP_minus
; CHECK-NEXT: .byte 28
; CHECK-NEXT: .byte 240 # -400
; CHECK-NEXT: .byte 124
; RCX is clobbered in call @Capture, but there is a spilled copy.
; *(RSP + 8) - 400

View File

@ -8,8 +8,8 @@
; CHECK: Beginning address offset: 0x0000000000000000
; CHECK: Ending address offset: 0x0000000000000004
; CHECK: Location description: 50 10 ff ff ff ff 0f 1a 10 01 1c
; rax, constu 0xffffffff, and, constu 0x00000001, minus
; CHECK: Location description: 70 00 10 ff ff ff ff 0f 1a 10 01 1c 9f
; rax+0, constu 0xffffffff, and, constu 0x00000001, minus, stack-value
source_filename = "minus.c"
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.12.0"
@ -42,7 +42,7 @@ attributes #1 = { nounwind readnone }
!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!11 = !{!12}
!12 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !1, line: 1, type: !10)
!13 = !DIExpression(DW_OP_minus, 1)
!13 = !DIExpression(DW_OP_minus, 1, DW_OP_stack_value)
!14 = !DILocation(line: 1, column: 13, scope: !7)
!15 = !DILocation(line: 2, column: 11, scope: !7)
!16 = !DILocation(line: 2, column: 3, scope: !7)

View File

@ -1,10 +1,22 @@
; RUN: llc -split-dwarf=Enable -O0 %s -mtriple=x86_64-unknown-linux-gnu -filetype=obj -o %t
; RUN: llvm-dwarfdump -debug-dump=all %t | FileCheck %s
; RUN: llvm-dwarfdump -debug-dump=all %t | FileCheck %s --check-prefix=CHECK-DWO
; Based on the debuginfo-tests/sret.cpp code.
; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x51ac5644b1937aa1)
; CHECK: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x51ac5644b1937aa1)
; CHECK-DWO: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x51ac5644b1937aa1)
; CHECK-DWO: DW_AT_GNU_dwo_id [DW_FORM_data8] (0x51ac5644b1937aa1)
; RUN: llc -O0 -fast-isel=true -mtriple=x86_64-apple-darwin -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
; RUN: llc -O0 -fast-isel=false -mtriple=x86_64-apple-darwin -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
; CHECK: _ZN1B9AInstanceEv
; CHECK: DW_TAG_variable
; CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] (0x00000000)
; CHECK-NEXT: DW_AT_name {{.*}}"a"
; CHECK: .debug_loc contents:
; CHECK: 0x00000000: Beginning address offset:
; CHECK-NEXT: Ending address offset:
; CHECK-NEXT: Location description: 75 00
; rdi+0
%class.A = type { i32 (...)**, i32 }
%class.B = type { i8 }
@ -98,7 +110,7 @@ entry:
call void @llvm.dbg.declare(metadata %class.B** %this.addr, metadata !89, metadata !DIExpression()), !dbg !91
%this1 = load %class.B*, %class.B** %this.addr
store i1 false, i1* %nrvo, !dbg !92
call void @llvm.dbg.declare(metadata %class.A* %agg.result, metadata !93, metadata !DIExpression(DW_OP_deref)), !dbg !92
call void @llvm.dbg.declare(metadata %class.A* %agg.result, metadata !93, metadata !DIExpression()), !dbg !92
call void @_ZN1AC1Ei(%class.A* %agg.result, i32 12), !dbg !92
store i1 true, i1* %nrvo, !dbg !94
store i32 1, i32* %cleanup.dest.slot

View File

@ -24,9 +24,9 @@ entry:
; CHECK: entry:
; Verify that llvm.dbg.declare calls are in the entry basic block.
; CHECK-NOT: %entry
; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ARG_ID:[0-9]+]], metadata ![[OPDEREF:[0-9]+]])
; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[ARG_ID:[0-9]+]], metadata ![[EMPTY:[0-9]+]])
; CHECK-NOT: %entry
; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[VAR_ID:[0-9]+]], metadata ![[OPDEREF:[0-9]+]])
; CHECK: call void @llvm.dbg.declare(metadata {{.*}}, metadata ![[VAR_ID:[0-9]+]], metadata ![[EMPTY:[0-9]+]])
declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone
@ -47,7 +47,7 @@ declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone
; Verify that debug descriptors for argument and local variable will be replaced
; with descriptors that end with OpDeref (encoded as 2).
; CHECK: ![[ARG_ID]] = !DILocalVariable(name: "p", arg: 1,{{.*}} line: 1
; CHECK: ![[OPDEREF]] = !DIExpression(DW_OP_deref)
; CHECK: ![[EMPTY]] = !DIExpression()
; CHECK: ![[VAR_ID]] = !DILocalVariable(name: "r",{{.*}} line: 2
; Verify that there are no more variable descriptors.
; CHECK-NOT: !DILocalVariable(tag: DW_TAG_arg_variable

View File

@ -37,10 +37,10 @@ entry:
; CHECK-DAG: ![[VAR_ARG]] = !DILocalVariable(name: "zzz"
; 100 aligned up to 8
; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_deref, DW_OP_minus, 104
; CHECK-DAG: ![[EXPR_ARG]] = !DIExpression(DW_OP_minus, 104)
; CHECK-DAG: ![[VAR_LOCAL]] = !DILocalVariable(name: "xxx"
; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_deref, DW_OP_minus, 208
; CHECK-DAG: ![[EXPR_LOCAL]] = !DIExpression(DW_OP_minus, 208)
; Function Attrs: nounwind readnone
declare void @llvm.dbg.declare(metadata, metadata, metadata) #1