1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 19:23:23 +01:00

Fix LLVM's use of DW_OP_bit_piece in DWARF expressions.

LLVM's use of DW_OP_bit_piece is incorrect and a based on a
misunderstanding of the wording in the DWARF specification. The offset
argument of DW_OP_bit_piece refers to the offset into the location
that is on the top of the DWARF expression stack, and not an offset
into the source variable. This has since also been clarified in the
DWARF specification.

This patch fixes all uses of DW_OP_bit_piece to emit the correct
offset and simplifies the DwarfExpression class to semi-automaticaly
emit empty DW_OP_pieces to adjust the offset of the source variable,
thus simplifying the code using DwarfExpression.

While this is an incompatible bugfix, in practice I don't expect this
to be much of a problem since LLVM's old interpretation and the
correct interpretation of DW_OP_bit_piece differ only when there are
gaps in the fragmented locations of the described variables or if
individual fragments are smaller than a byte. LLDB at least won't
interpret locations with gaps in them because is has no way to present
undefined bits in a variable, and there is a high probability that an
old-form expression will be malformed when interpreted correctly,
because the DW_OP_bit_piece offset will be outside of the location at
the top of the stack.

As a nice side-effect, this patch enables us to use a more efficient
encoding for subregisters: In order to express a sub-register at a
non-zero offset we now use a DW_OP_bit_piece instead of shifting the
value into place manually.

This patch also adds missing test coverage for code paths that weren't
exercised before.

<rdar://problem/29335809>
Differential Revision: https://reviews.llvm.org/D27550

llvm-svn: 289266
This commit is contained in:
Adrian Prantl 2016-12-09 20:43:40 +00:00
parent ce70dd4dfd
commit 63b8f792d5
15 changed files with 536 additions and 164 deletions

View File

@ -468,10 +468,6 @@ public:
/// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified.
virtual unsigned getISAEncoding() { return 0; }
/// EmitDwarfRegOp - Emit a dwarf register operation.
virtual void EmitDwarfRegOp(ByteStreamer &BS,
const MachineLocation &MLoc) const;
//===------------------------------------------------------------------===//
// Dwarf Lowering Routines
//===------------------------------------------------------------------===//

View File

@ -174,36 +174,6 @@ void AsmPrinter::emitDwarfStringOffset(DwarfStringPoolEntryRef S) const {
EmitInt32(S.getOffset());
}
/// EmitDwarfRegOp - Emit dwarf register operation.
void AsmPrinter::EmitDwarfRegOp(ByteStreamer &Streamer,
const MachineLocation &MLoc) const {
DebugLocDwarfExpression Expr(getDwarfVersion(), Streamer);
const MCRegisterInfo *MRI = MMI->getContext().getRegisterInfo();
int Reg = MRI->getDwarfRegNum(MLoc.getReg(), false);
if (Reg < 0) {
// We assume that pointers are always in an addressable register.
if (MLoc.isIndirect())
// FIXME: We have no reasonable way of handling errors in here. The
// caller might be in the middle of a dwarf expression. We should
// probably assert that Reg >= 0 once debug info generation is more
// mature.
return Expr.EmitOp(dwarf::DW_OP_nop,
"nop (could not find a dwarf register number)");
// Attempt to find a valid super- or sub-register.
if (!Expr.AddMachineRegFragment(*MF->getSubtarget().getRegisterInfo(),
MLoc.getReg()))
Expr.EmitOp(dwarf::DW_OP_nop,
"nop (could not find a dwarf register number)");
return;
}
if (MLoc.isIndirect())
Expr.AddRegIndirect(Reg, MLoc.getOffset());
else
Expr.AddReg(Reg);
}
//===----------------------------------------------------------------------===//
// Dwarf Lowering Routines
//===----------------------------------------------------------------------===//

View File

@ -180,7 +180,9 @@ DIE *DwarfCompileUnit::getOrCreateGlobalVariableDIE(
if (Expr) {
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
DwarfExpr.addFragmentOffset(Expr);
DwarfExpr.AddExpression(Expr);
DwarfExpr.finalize();
}
}
@ -498,8 +500,10 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
// If there is an expression, emit raw unsigned bytes.
DwarfExpr.addFragmentOffset(Expr);
DwarfExpr.AddUnsignedConstant(DVInsn->getOperand(0).getImm());
DwarfExpr.AddExpression(Expr);
DwarfExpr.finalize();
addBlock(*VariableDie, dwarf::DW_AT_location, Loc);
} else
addConstantValue(*VariableDie, DVInsn->getOperand(0), DV.getType());
@ -524,11 +528,13 @@ DIE *DwarfCompileUnit::constructVariableDIEImpl(const DbgVariable &DV,
const TargetFrameLowering *TFI = Asm->MF->getSubtarget().getFrameLowering();
int Offset = TFI->getFrameIndexReference(*Asm->MF, FI, FrameReg);
assert(Expr != DV.getExpression().end() && "Wrong number of expressions");
DwarfExpr.addFragmentOffset(*Expr);
DwarfExpr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
FrameReg, Offset);
DwarfExpr.AddExpression(*Expr);
++Expr;
}
DwarfExpr.finalize();
addBlock(*VariableDie, dwarf::DW_AT_location, Loc);
return VariableDie;
@ -727,16 +733,22 @@ void DwarfCompileUnit::addVariableAddress(const DbgVariable &DV, DIE &Die,
void DwarfCompileUnit::addAddress(DIE &Die, dwarf::Attribute Attribute,
const MachineLocation &Location) {
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression Expr(*Asm, *this, *Loc);
bool validReg;
if (Location.isReg())
validReg = addRegisterFragment(*Loc, Location.getReg());
validReg = Expr.AddMachineReg(*Asm->MF->getSubtarget().getRegisterInfo(),
Location.getReg());
else
validReg = addRegisterOffset(*Loc, Location.getReg(), Location.getOffset());
validReg =
Expr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
Location.getReg(), Location.getOffset());
if (!validReg)
return;
Expr.finalize();
// Now attach the location information to the DIE.
addBlock(Die, Attribute, Loc);
}
@ -750,9 +762,11 @@ void DwarfCompileUnit::addComplexAddress(const DbgVariable &DV, DIE &Die,
const MachineLocation &Location) {
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
DIExpressionCursor ExprCursor(DV.getSingleExpression());
const DIExpression *Expr = DV.getSingleExpression();
DIExpressionCursor ExprCursor(Expr);
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
auto Reg = Location.getReg();
DwarfExpr.addFragmentOffset(Expr);
bool ValidReg =
Location.getOffset()
? DwarfExpr.AddMachineRegIndirect(TRI, Reg, Location.getOffset())

View File

@ -1413,9 +1413,9 @@ void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer,
static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
ByteStreamer &Streamer,
const DebugLocEntry::Value &Value,
unsigned FragmentOffsetInBits) {
DwarfExpression &DwarfExpr) {
DIExpressionCursor ExprCursor(Value.getExpression());
DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer);
DwarfExpr.addFragmentOffset(Value.getExpression());
// Regular entry.
if (Value.isInt()) {
if (BT && (BT->getEncoding() == dwarf::DW_ATE_signed ||
@ -1425,23 +1425,16 @@ static void emitDebugLocValue(const AsmPrinter &AP, const DIBasicType *BT,
DwarfExpr.AddUnsignedConstant(Value.getInt());
} else if (Value.isLocation()) {
MachineLocation Loc = Value.getLoc();
if (!ExprCursor)
// Regular entry.
AP.EmitDwarfRegOp(Streamer, Loc);
else {
// Complex address entry.
const TargetRegisterInfo &TRI = *AP.MF->getSubtarget().getRegisterInfo();
if (Loc.getOffset())
DwarfExpr.AddMachineRegIndirect(TRI, Loc.getReg(), Loc.getOffset());
else
DwarfExpr.AddMachineRegExpression(TRI, ExprCursor, Loc.getReg(),
FragmentOffsetInBits);
}
DwarfExpr.AddMachineRegExpression(TRI, ExprCursor, Loc.getReg());
} else if (Value.isConstantFP()) {
APInt RawBytes = Value.getConstantFP()->getValueAPF().bitcastToAPInt();
DwarfExpr.AddUnsignedConstant(RawBytes);
}
DwarfExpr.AddExpression(std::move(ExprCursor), FragmentOffsetInBits);
DwarfExpr.AddExpression(std::move(ExprCursor));
}
void DebugLocEntry::finalize(const AsmPrinter &AP,
@ -1449,6 +1442,7 @@ void DebugLocEntry::finalize(const AsmPrinter &AP,
const DIBasicType *BT) {
DebugLocStream::EntryBuilder Entry(List, Begin, End);
BufferByteStreamer Streamer = Entry.getStreamer();
DebugLocDwarfExpression DwarfExpr(AP.getDwarfVersion(), Streamer);
const DebugLocEntry::Value &Value = Values[0];
if (Value.isFragment()) {
// Emit all fragments that belong to the same variable and range.
@ -1458,26 +1452,14 @@ void DebugLocEntry::finalize(const AsmPrinter &AP,
assert(std::is_sorted(Values.begin(), Values.end()) &&
"fragments are expected to be sorted");
unsigned Offset = 0;
for (auto Fragment : Values) {
const DIExpression *Expr = Fragment.getExpression();
unsigned FragmentOffset = Expr->getFragmentOffsetInBits();
unsigned FragmentSize = Expr->getFragmentSizeInBits();
assert(Offset <= FragmentOffset && "overlapping or duplicate fragments");
if (Offset < FragmentOffset) {
// DWARF represents gaps as pieces with no locations.
DebugLocDwarfExpression Expr(AP.getDwarfVersion(), Streamer);
Expr.AddOpPiece(FragmentOffset-Offset, 0);
Offset += FragmentOffset-Offset;
}
Offset += FragmentSize;
for (auto Fragment : Values)
emitDebugLocValue(AP, BT, Streamer, Fragment, DwarfExpr);
emitDebugLocValue(AP, BT, Streamer, Fragment, FragmentOffset);
}
} else {
assert(Values.size() == 1 && "only fragments may have >1 value");
emitDebugLocValue(AP, BT, Streamer, Value, 0);
emitDebugLocValue(AP, BT, Streamer, Value, DwarfExpr);
}
DwarfExpr.finalize();
}
void DwarfDebug::emitDebugLocEntryLocation(const DebugLocStream::Entry &Entry) {

View File

@ -46,7 +46,9 @@ void DwarfExpression::AddRegIndirect(int DwarfReg, int Offset, bool Deref) {
}
void DwarfExpression::AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits) {
assert(SizeInBits > 0 && "piece has size zero");
if (!SizeInBits)
return;
const unsigned SizeOfByte = 8;
if (OffsetInBits > 0 || SizeInBits % SizeOfByte) {
EmitOp(dwarf::DW_OP_bit_piece);
@ -57,6 +59,7 @@ void DwarfExpression::AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits) {
unsigned ByteSize = SizeInBits / SizeOfByte;
EmitUnsigned(ByteSize);
}
this->OffsetInBits += SizeInBits;
}
void DwarfExpression::AddShr(unsigned ShiftBy) {
@ -82,10 +85,8 @@ bool DwarfExpression::AddMachineRegIndirect(const TargetRegisterInfo &TRI,
return true;
}
bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
unsigned MachineReg,
unsigned FragmentSizeInBits,
unsigned FragmentOffsetInBits) {
bool DwarfExpression::AddMachineReg(const TargetRegisterInfo &TRI,
unsigned MachineReg) {
if (!TRI.isPhysicalRegister(MachineReg))
return false;
@ -94,8 +95,6 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
// If this is a valid register number, emit it.
if (Reg >= 0) {
AddReg(Reg);
if (FragmentSizeInBits)
AddOpPiece(FragmentSizeInBits, FragmentOffsetInBits);
return true;
}
@ -108,24 +107,15 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
unsigned Size = TRI.getSubRegIdxSize(Idx);
unsigned RegOffset = TRI.getSubRegIdxOffset(Idx);
AddReg(Reg, "super-register");
if (FragmentOffsetInBits == RegOffset) {
AddOpPiece(Size, RegOffset);
} else {
// If this is part of a variable in a sub-register at a non-zero offset,
// we need to manually shift the value into place, since the
// DW_OP_LLVM_fragment describes the part of the variable, not the
// position of the subregister.
if (RegOffset)
AddShr(RegOffset);
AddOpPiece(Size, FragmentOffsetInBits);
}
// Use a DW_OP_bit_piece to describe the sub-register.
setSubRegisterPiece(Size, RegOffset);
return true;
}
}
// Otherwise, attempt to find a covering set of sub-register numbers.
// For example, Q0 on ARM is a composition of D0+D1.
unsigned CurPos = FragmentOffsetInBits;
unsigned CurPos = 0;
// The size of the register in bits, assuming 8 bits per byte.
unsigned RegSize = TRI.getMinimalPhysRegClass(MachineReg)->getSize() * 8;
// Keep track of the bits in the register we already emitted, so we
@ -147,7 +137,10 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
// its range, emit a DWARF piece for it.
if (Reg >= 0 && Intersection.any()) {
AddReg(Reg, "sub-register");
AddOpPiece(Size, Offset == CurPos ? 0 : Offset);
// Emit a piece for the any gap in the coverage.
if (Offset > CurPos)
AddOpPiece(Offset - CurPos);
AddOpPiece(Size);
CurPos = Offset + Size;
// Mark it as emitted.
@ -155,7 +148,7 @@ bool DwarfExpression::AddMachineRegFragment(const TargetRegisterInfo &TRI,
}
}
return CurPos > FragmentOffsetInBits;
return CurPos;
}
void DwarfExpression::AddStackValue() {
@ -191,35 +184,21 @@ void DwarfExpression::AddUnsignedConstant(const APInt &Value) {
}
}
static unsigned getOffsetOrZero(unsigned OffsetInBits,
unsigned FragmentOffsetInBits) {
if (OffsetInBits == FragmentOffsetInBits)
return 0;
assert(OffsetInBits >= FragmentOffsetInBits && "overlapping fragments");
return OffsetInBits;
}
bool DwarfExpression::AddMachineRegExpression(const TargetRegisterInfo &TRI,
DIExpressionCursor &ExprCursor,
unsigned MachineReg,
unsigned FragmentOffsetInBits) {
if (!ExprCursor)
return AddMachineRegFragment(TRI, MachineReg);
return AddMachineReg(TRI, MachineReg);
// Pattern-match combinations for which more efficient representations exist
// first.
bool ValidReg = false;
auto Op = ExprCursor.peek();
switch (Op->getOp()) {
case dwarf::DW_OP_LLVM_fragment: {
unsigned OffsetInBits = Op->getArg(0);
unsigned SizeInBits = Op->getArg(1);
// Piece always comes at the end of the expression.
AddMachineRegFragment(TRI, MachineReg, SizeInBits,
getOffsetOrZero(OffsetInBits, FragmentOffsetInBits));
ExprCursor.take();
default:
ValidReg = AddMachineReg(TRI, MachineReg);
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].
@ -231,7 +210,7 @@ bool DwarfExpression::AddMachineRegExpression(const TargetRegisterInfo &TRI,
TRI, MachineReg, Op->getOp() == dwarf::DW_OP_plus ? Offset : -Offset);
ExprCursor.consume(2);
} else
ValidReg = AddMachineRegFragment(TRI, MachineReg);
ValidReg = AddMachineReg(TRI, MachineReg);
break;
}
case dwarf::DW_OP_deref:
@ -250,10 +229,25 @@ void DwarfExpression::AddExpression(DIExpressionCursor &&ExprCursor,
auto Op = ExprCursor.take();
switch (Op->getOp()) {
case dwarf::DW_OP_LLVM_fragment: {
unsigned OffsetInBits = Op->getArg(0);
unsigned SizeInBits = Op->getArg(1);
AddOpPiece(SizeInBits,
getOffsetOrZero(OffsetInBits, FragmentOffsetInBits));
unsigned FragmentOffset = Op->getArg(0);
// The fragment offset must have already been adjusted by emitting an
// empty DW_OP_piece / DW_OP_bit_piece before we emitted the base
// location.
assert(OffsetInBits >= FragmentOffset && "fragment offset not added?");
// If \a 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
// sub-register that is smaller than the current fragment's size, use it.
if (SubRegisterSizeInBits)
SizeInBits = std::min<unsigned>(SizeInBits, SubRegisterSizeInBits);
AddOpPiece(SizeInBits, SubRegisterOffsetInBits);
setSubRegisterPiece(0, 0);
break;
}
case dwarf::DW_OP_plus:
@ -281,3 +275,20 @@ void DwarfExpression::AddExpression(DIExpressionCursor &&ExprCursor,
}
}
}
void DwarfExpression::finalize() {
if (SubRegisterSizeInBits)
AddOpPiece(SubRegisterSizeInBits, SubRegisterOffsetInBits);
}
void DwarfExpression::addFragmentOffset(const DIExpression *Expr) {
if (!Expr || !Expr->isFragment())
return;
uint64_t FragmentOffset = Expr->getFragmentOffsetInBits();
assert(FragmentOffset >= OffsetInBits &&
"overlapping or duplicate fragments");
if (FragmentOffset > OffsetInBits)
AddOpPiece(FragmentOffset - OffsetInBits);
OffsetInBits = FragmentOffset;
}

View File

@ -39,6 +39,9 @@ public:
End = Expr->expr_op_end();
}
DIExpressionCursor(ArrayRef<uint64_t> Expr)
: Start(Expr.begin()), End(Expr.end()) {}
/// Consume one operation.
Optional<DIExpression::ExprOperand> take() {
if (Start == End)
@ -77,10 +80,26 @@ public:
class DwarfExpression {
protected:
unsigned DwarfVersion;
/// Current Fragment Offset in Bits.
uint64_t OffsetInBits = 0;
/// Sometimes we need to add a DW_OP_bit_piece to describe a subregister.
unsigned SubRegisterSizeInBits = 0;
unsigned SubRegisterOffsetInBits = 0;
/// 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) {
SubRegisterSizeInBits = SizeInBits;
SubRegisterOffsetInBits = OffsetInBits;
}
public:
DwarfExpression(unsigned DwarfVersion) : DwarfVersion(DwarfVersion) {}
virtual ~DwarfExpression() {}
virtual ~DwarfExpression() {};
/// This needs to be called last to commit any pending changes.
void finalize();
/// Output a dwarf operand and an optional assembler comment.
virtual void EmitOp(uint8_t Op, const char *Comment = nullptr) = 0;
@ -97,9 +116,9 @@ public:
/// Emit an (double-)indirect dwarf register operation.
void AddRegIndirect(int DwarfReg, int Offset, bool Deref = false);
/// Emit a DW_OP_piece operation for a variable fragment.
/// \param OffsetInBits This is the offset where the fragment appears
/// inside the *source variable*.
/// Emit a DW_OP_piece or DW_OP_bit_piece operation for a variable fragment.
/// \param OffsetInBits This is an optional offset into the location that
/// is at the top of the DWARF stack.
void AddOpPiece(unsigned SizeInBits, unsigned OffsetInBits = 0);
/// Emit a shift-right dwarf expression.
@ -125,10 +144,7 @@ public:
/// Emit a partial DWARF register operation.
///
/// \param MachineReg the register,
/// \param FragmentSizeInBits size and
/// \param FragmentOffsetInBits offset of the fragment in bits, if this is
/// a fragment of an aggregate value.
/// \param MachineReg The register number.
///
/// If size and offset is zero an operation for the entire register is
/// emitted: Some targets do not provide a DWARF register number for every
@ -137,9 +153,7 @@ public:
/// multiple subregisters that alias the register.
///
/// \return false if no DWARF register exists for MachineReg.
bool AddMachineRegFragment(const TargetRegisterInfo &TRI, unsigned MachineReg,
unsigned FragmentSizeInBits = 0,
unsigned FragmentOffsetInBits = 0);
bool AddMachineReg(const TargetRegisterInfo &TRI, unsigned MachineReg);
/// Emit a signed constant.
void AddSignedConstant(int64_t Value);
@ -167,6 +181,10 @@ public:
/// fragment inside the entire variable.
void AddExpression(DIExpressionCursor &&Expr,
unsigned FragmentOffsetInBits = 0);
/// If applicable, emit an empty DW_OP_piece / DW_OP_bit_piece to advance to
/// the fragment described by \c Expr.
void addFragmentOffset(const DIExpression *Expr);
};
/// DwarfExpression implementation for .debug_loc entries.

View File

@ -371,22 +371,6 @@ void DwarfUnit::addSourceLine(DIE &Die, const DINamespace *NS) {
addSourceLine(Die, NS->getLine(), NS->getFilename(), NS->getDirectory());
}
bool DwarfUnit::addRegisterFragment(DIELoc &TheDie, unsigned Reg,
unsigned SizeInBits,
unsigned OffsetInBits) {
DIEDwarfExpression Expr(*Asm, *this, TheDie);
Expr.AddMachineRegFragment(*Asm->MF->getSubtarget().getRegisterInfo(), Reg,
SizeInBits, OffsetInBits);
return true;
}
bool DwarfUnit::addRegisterOffset(DIELoc &TheDie, unsigned Reg,
int64_t Offset) {
DIEDwarfExpression Expr(*Asm, *this, TheDie);
return Expr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
Reg, Offset);
}
/* Byref variables, in Blocks, are declared by the programmer as "SomeType
VarName;", but the compiler creates a __Block_byref_x_VarName struct, and
gives the variable VarName either the struct, or a pointer to the struct, as
@ -479,12 +463,17 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
// Decode the original location, and use that as the start of the byref
// variable's location.
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
SmallVector<uint64_t, 6> DIExpr;
DIEDwarfExpression Expr(*Asm, *this, *Loc);
bool validReg;
if (Location.isReg())
validReg = addRegisterFragment(*Loc, Location.getReg());
validReg = Expr.AddMachineReg(*Asm->MF->getSubtarget().getRegisterInfo(),
Location.getReg());
else
validReg = addRegisterOffset(*Loc, Location.getReg(), Location.getOffset());
validReg =
Expr.AddMachineRegIndirect(*Asm->MF->getSubtarget().getRegisterInfo(),
Location.getReg(), Location.getOffset());
if (!validReg)
return;
@ -492,27 +481,29 @@ void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
// 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).
if (isPointer)
addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
DIExpr.push_back(dwarf::DW_OP_deref);
// Next add the offset for the '__forwarding' field:
// DW_OP_plus_uconst ForwardingFieldOffset. Note there's no point in
// adding the offset if it's 0.
if (forwardingFieldOffset > 0) {
addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(*Loc, dwarf::DW_FORM_udata, forwardingFieldOffset);
DIExpr.push_back(dwarf::DW_OP_plus);
DIExpr.push_back(forwardingFieldOffset);
}
// Now dereference the __forwarding field to get to the real __Block_byref
// struct: DW_OP_deref.
addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
DIExpr.push_back(dwarf::DW_OP_deref);
// Now that we've got the real __Block_byref... struct, add the offset
// for the variable's field to get to the location of the actual variable:
// DW_OP_plus_uconst varFieldOffset. Again, don't add if it's 0.
if (varFieldOffset > 0) {
addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(*Loc, dwarf::DW_FORM_udata, varFieldOffset);
DIExpr.push_back(dwarf::DW_OP_plus);
DIExpr.push_back(varFieldOffset);
}
Expr.AddExpression(makeArrayRef(DIExpr));
Expr.finalize();
// Now attach the location information to the DIE.
addBlock(Die, Attribute, Loc);

View File

@ -235,19 +235,6 @@ public:
/// Add template parameters in buffer.
void addTemplateParams(DIE &Buffer, DINodeArray TParams);
/// Add register operand for a source variable fragment of the specified size
/// and offset.
///
/// \returns false if the register does not exist, e.g., because it was never
/// materialized.
bool addRegisterFragment(DIELoc &TheDie, unsigned Reg,
unsigned SizeInBits = 0, unsigned OffsetInBits = 0);
/// Add register offset.
/// \returns false if the register does not exist, e.g., because it was never
/// materialized.
bool addRegisterOffset(DIELoc &TheDie, unsigned Reg, int64_t Offset);
// FIXME: Should be reformulated in terms of addComplexAddress.
/// Start with the address based on the location provided, and generate the
/// DWARF information necessary to find the actual Block variable (navigating

View File

@ -5,8 +5,8 @@
; CHECK: DW_TAG_inlined_subroutine
; CHECK: "_Z3f111A"
; CHECK: DW_TAG_formal_parameter
; CHECK: DW_AT_location [DW_FORM_block1] (<0x0b> 91 51 9d 78 08 91 4a 9d 38 88 01 )
; -- fbreg -47, bit-piece 120 8 , fbreg -54, bit-piece 56 136 ------^
; CHECK: DW_AT_location [DW_FORM_block1] (<0x0c> 93 01 91 51 93 0f 93 01 91 4a 93 07 )
; -- piece 0x00000001, fbreg -47, piece 0x0000000f, piece 0x00000001, fbreg -54, piece 0x00000007 ------^
; CHECK: DW_AT_abstract_origin {{.*}} "p1"
;
; long a;

View File

@ -0,0 +1,3 @@
if not 'ARM' in config.root.targets:
config.unsupported = True

View File

@ -0,0 +1,125 @@
# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
# CHECK: .debug_info contents:
# CHECK: DW_TAG_variable
# CHECK-NEXT: DW_AT_location [DW_FORM_data4] ([[OFS:.*]])
# CHECK-NEXT: DW_AT_name {{.*}}"vec"
# CHECK: .debug_loc contents:
# CHECK: [[OFS]]: Beginning address offset: 0x0000000000000016
# CHECK: Ending address offset: 0x000000000000001e
# CHECK: Location description: 93 10 90 80 02 93 08 90 81 02 93 08
# piece 0x00000010, d0, piece 0x00000008, d1, piece 0x00000008
--- |
; Generate from (and then manually modified to incorporate a DW_OP_LLVM_fragment):
; typedef float vec2 __attribute__((vector_size(16)));
; vec2 v();
; float f() {
; vec2 vec = v();
; return vec[0] + vec[1];
; }
target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
target triple = "thumbv7s-apple-ios5.0.0"
define float @f() local_unnamed_addr #0 !dbg !9 {
entry:
%call = tail call <4 x float> bitcast (<4 x float> (...)* @v to <4 x float> ()*)() #0, !dbg !19
tail call void @llvm.dbg.value(metadata <4 x float> %call, i64 0, metadata !14, metadata !20), !dbg !21
%vecext = extractelement <4 x float> %call, i32 0, !dbg !22
%vecext1 = extractelement <4 x float> %call, i32 1, !dbg !23
%add = fadd float %vecext, %vecext1, !dbg !24
ret float %add, !dbg !25
}
declare arm_aapcs_vfpcc <4 x float> @v(...) local_unnamed_addr #0
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
attributes #0 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5, !6, !7}
!llvm.ident = !{!8}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "v.c", directory: "/")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 2}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 1, !"min_enum_size", i32 4}
!7 = !{i32 1, !"PIC Level", i32 2}
!8 = !{!"clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)"}
!9 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !10, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !13)
!10 = !DISubroutineType(types: !11)
!11 = !{!12}
!12 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
!13 = !{!14}
!14 = !DILocalVariable(name: "vec", scope: !9, file: !1, line: 4, type: !15)
!15 = !DIDerivedType(tag: DW_TAG_typedef, name: "vec2", file: !1, line: 1, baseType: !16)
!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 256, flags: DIFlagVector, elements: !17)
!17 = !{!18}
!18 = !DISubrange(count: 8)
!19 = !DILocation(line: 4, column: 13, scope: !9)
!20 = !DIExpression(DW_OP_LLVM_fragment, 128, 128)
!21 = !DILocation(line: 4, column: 7, scope: !9)
!22 = !DILocation(line: 5, column: 9, scope: !9)
!23 = !DILocation(line: 5, column: 18, scope: !9)
!24 = !DILocation(line: 5, column: 16, scope: !9)
!25 = !DILocation(line: 5, column: 2, scope: !9)
...
---
name: f
alignment: 1
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
calleeSavedRegisters: [ '%lr', '%d8', '%d9', '%d10', '%d11', '%d12', '%d13',
'%d14', '%d15', '%q4', '%q5', '%q6', '%q7', '%r4',
'%r5', '%r6', '%r7', '%r8', '%r10', '%r11', '%s16',
'%s17', '%s18', '%s19', '%s20', '%s21', '%s22',
'%s23', '%s24', '%s25', '%s26', '%s27', '%s28',
'%s29', '%s30', '%s31', '%d8_d10', '%d9_d11', '%d10_d12',
'%d11_d13', '%d12_d14', '%d13_d15', '%q4_q5', '%q5_q6',
'%q6_q7', '%q4_q5_q6_q7', '%r4_r5', '%r6_r7', '%r10_r11',
'%d8_d9_d10', '%d9_d10_d11', '%d10_d11_d12', '%d11_d12_d13',
'%d12_d13_d14', '%d13_d14_d15', '%d8_d10_d12',
'%d9_d11_d13', '%d10_d12_d14', '%d11_d13_d15',
'%d8_d10_d12_d14', '%d9_d11_d13_d15', '%d9_d10',
'%d11_d12', '%d13_d14', '%d9_d10_d11_d12', '%d11_d12_d13_d14' ]
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 4
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
maxCallFrameSize: 0
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
stack:
- { id: 0, type: spill-slot, offset: -4, size: 4, alignment: 4, callee-saved-register: '%lr' }
body: |
bb.0.entry:
liveins: %lr
early-clobber %sp = frame-setup t2STR_PRE killed undef %lr, %sp, -4, 14, _
frame-setup CFI_INSTRUCTION def_cfa_offset 4
frame-setup CFI_INSTRUCTION offset %lr, -4
tBL 14, _, @v, csr_ios, implicit-def dead %lr, implicit %sp, implicit-def %sp, implicit-def %r0, implicit-def %r1, implicit-def %r2, implicit-def %r3, debug-location !19
%d1 = VMOVDRR killed %r2, killed %r3, 14, _, implicit-def %q0, debug-location !19
%d0 = VMOVDRR killed %r0, killed %r1, 14, _, implicit killed %q0, implicit-def %q0, debug-location !19
DBG_VALUE debug-use %q0, debug-use _, !14, !20, debug-location !21
%s4 = VMOVS %s1, 14, _, implicit-def %d2, debug-location !24
%d0 = VADDfd %d0, killed %d2, 14, _, implicit killed %q0, debug-location !24
%r0 = VMOVRS %s0, 14, _, implicit killed %d0, debug-location !25
%lr, %sp = t2LDR_POST %sp, 4, 14, _, debug-location !25
tBX_RET 14, _, implicit %r0, debug-location !25
...

View File

@ -0,0 +1,125 @@
# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
# CHECK: .debug_info contents:
# CHECK: DW_TAG_variable
# CHECK-NEXT: DW_AT_location [DW_FORM_data4] ([[OFS:.*]])
# CHECK-NEXT: DW_AT_name {{.*}}"vec"
# CHECK: .debug_loc contents:
# CHECK: [[OFS]]: Beginning address offset: 0x0000000000000016
# CHECK: Ending address offset: 0x000000000000001e
# CHECK: Location description: 90 80 02 93 08 90 81 02 93 08
# d0, piece 0x00000008, d1, piece 0x00000008
--- |
; Generated from:
; typedef float vec2 __attribute__((vector_size(16)));
; vec2 v();
; float f() {
; vec2 vec = v();
; return vec[0] + vec[1];
; }
target datalayout = "e-m:o-p:32:32-f64:32:64-v64:32:64-v128:32:128-a:0:32-n32-S32"
target triple = "thumbv7s-apple-ios5.0.0"
define float @f() local_unnamed_addr #0 !dbg !9 {
entry:
%call = tail call <4 x float> bitcast (<4 x float> (...)* @v to <4 x float> ()*)() #0, !dbg !19
tail call void @llvm.dbg.value(metadata <4 x float> %call, i64 0, metadata !14, metadata !20), !dbg !21
%vecext = extractelement <4 x float> %call, i32 0, !dbg !22
%vecext1 = extractelement <4 x float> %call, i32 1, !dbg !23
%add = fadd float %vecext, %vecext1, !dbg !24
ret float %add, !dbg !25
}
declare arm_aapcs_vfpcc <4 x float> @v(...) local_unnamed_addr #0
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
attributes #0 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5, !6, !7}
!llvm.ident = !{!8}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "v.c", directory: "/")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 2}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"wchar_size", i32 4}
!6 = !{i32 1, !"min_enum_size", i32 4}
!7 = !{i32 1, !"PIC Level", i32 2}
!8 = !{!"clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)"}
!9 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !10, isLocal: false, isDefinition: true, scopeLine: 3, isOptimized: true, unit: !0, variables: !13)
!10 = !DISubroutineType(types: !11)
!11 = !{!12}
!12 = !DIBasicType(name: "float", size: 32, encoding: DW_ATE_float)
!13 = !{!14}
!14 = !DILocalVariable(name: "vec", scope: !9, file: !1, line: 4, type: !15)
!15 = !DIDerivedType(tag: DW_TAG_typedef, name: "vec2", file: !1, line: 1, baseType: !16)
!16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !12, size: 128, flags: DIFlagVector, elements: !17)
!17 = !{!18}
!18 = !DISubrange(count: 4)
!19 = !DILocation(line: 4, column: 13, scope: !9)
!20 = !DIExpression()
!21 = !DILocation(line: 4, column: 7, scope: !9)
!22 = !DILocation(line: 5, column: 9, scope: !9)
!23 = !DILocation(line: 5, column: 18, scope: !9)
!24 = !DILocation(line: 5, column: 16, scope: !9)
!25 = !DILocation(line: 5, column: 2, scope: !9)
...
---
name: f
alignment: 1
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
calleeSavedRegisters: [ '%lr', '%d8', '%d9', '%d10', '%d11', '%d12', '%d13',
'%d14', '%d15', '%q4', '%q5', '%q6', '%q7', '%r4',
'%r5', '%r6', '%r7', '%r8', '%r10', '%r11', '%s16',
'%s17', '%s18', '%s19', '%s20', '%s21', '%s22',
'%s23', '%s24', '%s25', '%s26', '%s27', '%s28',
'%s29', '%s30', '%s31', '%d8_d10', '%d9_d11', '%d10_d12',
'%d11_d13', '%d12_d14', '%d13_d15', '%q4_q5', '%q5_q6',
'%q6_q7', '%q4_q5_q6_q7', '%r4_r5', '%r6_r7', '%r10_r11',
'%d8_d9_d10', '%d9_d10_d11', '%d10_d11_d12', '%d11_d12_d13',
'%d12_d13_d14', '%d13_d14_d15', '%d8_d10_d12',
'%d9_d11_d13', '%d10_d12_d14', '%d11_d13_d15',
'%d8_d10_d12_d14', '%d9_d11_d13_d15', '%d9_d10',
'%d11_d12', '%d13_d14', '%d9_d10_d11_d12', '%d11_d12_d13_d14' ]
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 4
offsetAdjustment: 0
maxAlignment: 4
adjustsStack: true
hasCalls: true
maxCallFrameSize: 0
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
stack:
- { id: 0, type: spill-slot, offset: -4, size: 4, alignment: 4, callee-saved-register: '%lr' }
body: |
bb.0.entry:
liveins: %lr
early-clobber %sp = frame-setup t2STR_PRE killed undef %lr, %sp, -4, 14, _
frame-setup CFI_INSTRUCTION def_cfa_offset 4
frame-setup CFI_INSTRUCTION offset %lr, -4
tBL 14, _, @v, csr_ios, implicit-def dead %lr, implicit %sp, implicit-def %sp, implicit-def %r0, implicit-def %r1, implicit-def %r2, implicit-def %r3, debug-location !19
%d1 = VMOVDRR killed %r2, killed %r3, 14, _, implicit-def %q0, debug-location !19
%d0 = VMOVDRR killed %r0, killed %r1, 14, _, implicit killed %q0, implicit-def %q0, debug-location !19
DBG_VALUE debug-use %q0, debug-use _, !14, !20, debug-location !21
%s4 = VMOVS %s1, 14, _, implicit-def %d2, debug-location !24
%d0 = VADDfd %d0, killed %d2, 14, _, implicit killed %q0, debug-location !24
%r0 = VMOVRS %s0, 14, _, implicit killed %d0, debug-location !25
%lr, %sp = t2LDR_POST %sp, 4, 14, _, debug-location !25
tBX_RET 14, _, implicit %r0, debug-location !25
...

View File

@ -0,0 +1,102 @@
# RUN: llc -filetype=obj -o - %s | llvm-dwarfdump - | FileCheck %s
# CHECK: .debug_info contents:
# CHECK: DW_TAG_variable
# CHECK-NEXT: DW_AT_location [DW_FORM_sec_offset] ([[OFS:.*]])
# CHECK-NEXT: DW_AT_name {{.*}}"dh"
# CHECK: .debug_loc contents:
# CHECK: [[OFS]]: Beginning address offset: 0x0000000000000002
# CHECK: Ending address offset: 0x000000000000000c
# CHECK: Location description: 51 9d 08 08
# rdx, bit-piece 8 8
--- |
; Manually created after:
; char f(int i) {
; char dh = i>>8;
; return dh;
; }
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.12.0"
define signext i8 @f(i32 %i) local_unnamed_addr #0 !dbg !7 {
entry:
tail call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !13, metadata !15), !dbg !16
%shr1 = lshr i32 %i, 8, !dbg !17
%conv = trunc i32 %shr1 to i8, !dbg !18
tail call void @llvm.dbg.value(metadata i8 %conv, i64 0, metadata !14, metadata !15), !dbg !19
ret i8 %conv, !dbg !20
}
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #0
attributes #0 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 288677) (llvm/trunk 288679)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "t.c", directory: "/")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"PIC Level", i32 2}
!6 = !{!"clang version 4.0.0 (trunk 288677) (llvm/trunk 288679)"}
!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !12)
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !11}
!10 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
!12 = !{!13, !14}
!13 = !DILocalVariable(name: "i", arg: 1, scope: !7, file: !1, line: 1, type: !11)
!14 = !DILocalVariable(name: "dh", scope: !7, file: !1, line: 2, type: !10)
!15 = !DIExpression()
!16 = !DILocation(line: 1, column: 12, scope: !7)
!17 = !DILocation(line: 2, column: 14, scope: !7)
!18 = !DILocation(line: 2, column: 13, scope: !7)
!19 = !DILocation(line: 2, column: 8, scope: !7)
!20 = !DILocation(line: 3, column: 3, scope: !7)
...
---
name: f
alignment: 4
exposesReturnsTwice: false
legalized: false
regBankSelected: false
selected: false
tracksRegLiveness: true
liveins:
- { reg: '%edi' }
frameInfo:
isFrameAddressTaken: false
isReturnAddressTaken: false
hasStackMap: false
hasPatchPoint: false
stackSize: 8
offsetAdjustment: 0
maxAlignment: 0
adjustsStack: false
hasCalls: false
maxCallFrameSize: 0
hasOpaqueSPAdjustment: false
hasVAStart: false
hasMustTailInVarArgFunc: false
fixedStack:
- { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16 }
body: |
bb.0.entry:
liveins: %edi, %rbp
frame-setup PUSH64r killed %rbp, implicit-def %rsp, implicit %rsp
CFI_INSTRUCTION def_cfa_offset 16
CFI_INSTRUCTION offset %rbp, -16
%rbp = frame-setup MOV64rr %rsp
CFI_INSTRUCTION def_cfa_register %rbp
DBG_VALUE debug-use %dh, debug-use _, !14, !15, debug-location !16
%edi = SHR32ri killed %edi, 8, implicit-def dead %eflags, debug-location !17
%eax = MOVSX32rr8 %dil, implicit killed %edi, debug-location !20
%rbp = POP64r implicit-def %rsp, implicit %rsp, debug-location !20
RETQ %eax, debug-location !20
...

View File

@ -21,8 +21,8 @@
;
; CHECK: 0x00000025: Beginning address offset: 0x0000000000000004
; CHECK: Ending address offset: 0x0000000000000004
; CHECK: Location description: 10 03 93 04 55 93 04
; constu 0x00000003, piece 0x00000004, rdi, piece 0x00000004
; CHECK: Location description: 10 03 93 04 55 93 02
; constu 0x00000003, piece 0x00000004, rdi, piece 0x00000002
; CHECK: Beginning address offset: 0x0000000000000004
; CHECK: Ending address offset: 0x0000000000000014
; CHECK: Location description: 10 03 93 04 10 00

View File

@ -0,0 +1,48 @@
; Test dwarf codegen of DW_OP_minus.
; RUN: llc -filetype=obj < %s | llvm-dwarfdump - | FileCheck %s
; This was derived manually from:
; int inc(int i) {
; return i+1;
; }
; CHECK: Beginning address offset: 0x0000000000000000
; CHECK: Ending address offset: 0x0000000000000004
; CHECK: Location description: 50 10 01 1c 93 04
; rax, constu 0x00000001, minus, piece 0x00000004
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"
define i32 @inc(i32 %i) local_unnamed_addr #1 !dbg !7 {
entry:
%add = add nsw i32 %i, 1, !dbg !15
tail call void @llvm.dbg.value(metadata i32 %add, i64 0, metadata !12, metadata !13), !dbg !14
ret i32 %add, !dbg !16
}
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #1
attributes #1 = { nounwind readnone }
!llvm.dbg.cu = !{!0}
!llvm.module.flags = !{!3, !4, !5}
!llvm.ident = !{!6}
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
!1 = !DIFile(filename: "minus.c", directory: "/tmp")
!2 = !{}
!3 = !{i32 2, !"Dwarf Version", i32 4}
!4 = !{i32 2, !"Debug Info Version", i32 3}
!5 = !{i32 1, !"PIC Level", i32 2}
!6 = !{!"clang version 4.0.0 (trunk 286322) (llvm/trunk 286305)"}
!7 = distinct !DISubprogram(name: "inc", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11)
!8 = !DISubroutineType(types: !9)
!9 = !{!10, !10}
!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)
!14 = !DILocation(line: 1, column: 13, scope: !7)
!15 = !DILocation(line: 2, column: 11, scope: !7)
!16 = !DILocation(line: 2, column: 3, scope: !7)