mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-24 20:30:06 +00:00
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:
parent
cc56be2830
commit
b560ea777b
@ -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)
|
||||
|
@ -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``
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -79,6 +79,9 @@ public:
|
||||
|
||||
unsigned size() const;
|
||||
void shrinkTo(unsigned N);
|
||||
|
||||
/// Perform bitcode upgrades on llvm.dbg.* calls.
|
||||
void upgradeDebugIntrinsics(Function &F);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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));
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
36
test/Bitcode/DIExpression-aggresult.ll
Normal file
36
test/Bitcode/DIExpression-aggresult.ll
Normal 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)
|
BIN
test/Bitcode/DIExpression-aggresult.ll.bc
Normal file
BIN
test/Bitcode/DIExpression-aggresult.ll.bc
Normal file
Binary file not shown.
27
test/Bitcode/DIExpression-deref.ll
Normal file
27
test/Bitcode/DIExpression-deref.ll
Normal 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}
|
BIN
test/Bitcode/DIExpression-deref.ll.bc
Normal file
BIN
test/Bitcode/DIExpression-deref.ll.bc
Normal file
Binary file not shown.
@ -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
|
||||
}
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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 }
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user