Debug info: Infrastructure to support debug locations for fragmented
variables (for example, by-value struct arguments passed in registers, or
large integer values split across several smaller registers).
On the IR level, this adds a new type of complex address operation OpPiece
to DIVariable that describes size and offset of a variable fragment.
On the DWARF emitter level, all pieces describing the same variable are
collected, sorted and emitted as DWARF expressions using the DW_OP_piece
and DW_OP_bit_piece operators.
http://reviews.llvm.org/D3373
rdar://problem/15928306
What this patch doesn't do / Future work:
- This patch only adds the backend machinery to make this work, patches
that change SROA and SelectionDAG's type legalizer to actually create
such debug info will follow. (http://reviews.llvm.org/D2680)
- Making the DIVariable complex expressions into an argument of dbg.value
will reduce the memory footprint of the debug metadata.
- The sorting/uniquing of pieces should be moved into DebugLocEntry,
to facilitate the merging of multi-piece entries.
llvm-svn: 214576
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index 7cbad1e..51c6c95 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -618,7 +618,11 @@
if (!Name.empty())
OS << Name << ":";
}
- OS << V.getName() << " <- ";
+ OS << V.getName();
+ if (V.isVariablePiece())
+ OS << " [piece offset=" << V.getPieceOffset()
+ << " size="<<V.getPieceSize()<<"]";
+ OS << " <- ";
// The second operand is only an offset if it's an immediate.
bool Deref = MI->getOperand(0).isReg() && MI->getOperand(1).isImm();
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
index 02cd12b..987c095 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -214,13 +214,10 @@
Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref");
}
-/// Emit a dwarf register operation for describing
-/// - a small value occupying only part of a register or
-/// - a small register representing only part of a value.
-static void emitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits,
- unsigned OffsetInBits) {
- assert(SizeInBits > 0 && "zero-sized piece");
- unsigned SizeOfByte = 8;
+void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits,
+ unsigned OffsetInBits) const {
+ assert(SizeInBits > 0 && "piece has size zero");
+ const unsigned SizeOfByte = 8;
if (OffsetInBits > 0 || SizeInBits % SizeOfByte) {
Streamer.EmitInt8(dwarf::DW_OP_bit_piece, "DW_OP_bit_piece");
Streamer.EmitULEB128(SizeInBits, Twine(SizeInBits));
@@ -255,7 +252,7 @@
// If this is a valid register number, emit it.
if (Reg >= 0) {
emitDwarfRegOp(Streamer, Reg);
- emitDwarfOpPiece(Streamer, PieceSizeInBits, PieceOffsetInBits);
+ EmitDwarfOpPiece(Streamer, PieceSizeInBits, PieceOffsetInBits);
return;
}
@@ -266,19 +263,19 @@
if (Reg >= 0) {
unsigned Idx = TRI->getSubRegIndex(*SR, MLoc.getReg());
unsigned Size = TRI->getSubRegIdxSize(Idx);
- unsigned Offset = TRI->getSubRegIdxOffset(Idx);
+ unsigned RegOffset = TRI->getSubRegIdxOffset(Idx);
OutStreamer.AddComment("super-register");
emitDwarfRegOp(Streamer, Reg);
- if (PieceOffsetInBits == Offset) {
- emitDwarfOpPiece(Streamer, Size, Offset);
+ if (PieceOffsetInBits == RegOffset) {
+ EmitDwarfOpPiece(Streamer, 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_piece describes the part of the
// variable, not the position of the subregister.
- emitDwarfOpPiece(Streamer, Size, PieceOffsetInBits);
- if (Offset)
- emitDwarfOpShr(Streamer, Offset);
+ if (RegOffset)
+ emitDwarfOpShr(Streamer, RegOffset);
+ EmitDwarfOpPiece(Streamer, Size, PieceOffsetInBits);
}
return;
}
@@ -312,7 +309,7 @@
if (Reg >= 0 && Intersection.any()) {
OutStreamer.AddComment("sub-register");
emitDwarfRegOp(Streamer, Reg);
- emitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset);
+ EmitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset);
CurPos = Offset + Size;
// Mark it as emitted.
diff --git a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp
index a66d08e..f557ccd 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp
@@ -11,6 +11,7 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include <algorithm>
@@ -36,7 +37,7 @@
const MachineInstr &MI) {
// Instruction range should start with a DBG_VALUE instruction for the
// variable.
- assert(MI.isDebugValue() && MI.getDebugVariable() == Var);
+ assert(MI.isDebugValue() && getEntireVariable(MI.getDebugVariable()) == Var);
auto &Ranges = VarInstrRanges[Var];
if (!Ranges.empty() && Ranges.back().second == nullptr &&
Ranges.back().first->isIdenticalTo(&MI)) {
@@ -182,7 +183,10 @@
}
assert(MI.getNumOperands() > 1 && "Invalid DBG_VALUE instruction!");
- const MDNode *Var = MI.getDebugVariable();
+ // Use the base variable (without any DW_OP_piece expressions)
+ // as index into History. The full variables including the
+ // piece expressions are attached to the MI.
+ DIVariable Var = getEntireVariable(MI.getDebugVariable());
if (unsigned PrevReg = Result.getRegisterForVar(Var))
dropRegDescribedVar(RegVars, PrevReg, Var);
diff --git a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h
index b9177f0..6f72b91 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h
@@ -28,9 +28,11 @@
// range. If end is not specified, location is valid until the start
// instruction of the next instruction range, or until the end of the
// function.
+public:
typedef std::pair<const MachineInstr *, const MachineInstr *> InstrRange;
typedef SmallVector<InstrRange, 4> InstrRanges;
typedef MapVector<const MDNode *, InstrRanges> InstrRangesMap;
+private:
InstrRangesMap VarInstrRanges;
public:
diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
index 3beb799..8cfe39d 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DebugLocEntry.h
@@ -10,6 +10,7 @@
#ifndef CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H__
#define CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H__
#include "llvm/IR/Constants.h"
+#include "llvm/IR/DebugInfo.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/MC/MCSymbol.h"
@@ -106,17 +107,36 @@
/// share the same Loc/Constant and if Next immediately follows this
/// Entry.
bool Merge(const DebugLocEntry &Next) {
+ // If this and Next are describing different pieces of the same
+ // variable, merge them by appending next's values to the current
+ // list of values.
+ if (Begin == Next.Begin && Values.size() > 0 && Next.Values.size() > 0) {
+ DIVariable Var(Values[0].Variable);
+ DIVariable NextVar(Next.Values[0].Variable);
+ if (Var.getName() == NextVar.getName() &&
+ Var.isVariablePiece() && NextVar.isVariablePiece()) {
+ Values.append(Next.Values.begin(), Next.Values.end());
+ End = Next.End;
+ return true;
+ }
+ }
+ // If this and Next are describing the same variable, merge them.
if ((End == Next.Begin && Values == Next.Values)) {
End = Next.End;
return true;
}
return false;
}
+
const MCSymbol *getBeginSym() const { return Begin; }
const MCSymbol *getEndSym() const { return End; }
const DwarfCompileUnit *getCU() const { return Unit; }
const ArrayRef<Value> getValues() const { return Values; }
- void addValue(Value Val) { Values.push_back(Val); }
+ void addValue(Value Val) {
+ assert(DIVariable(Val.Variable).isVariablePiece() &&
+ "multi-value DebugLocEntries must be pieces");
+ Values.push_back(Val);
+ }
};
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
index f5b8dd7..dc6081c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.cpp
@@ -1194,6 +1194,101 @@
llvm_unreachable("Unexpected 3 operand DBG_VALUE instruction!");
}
+/// Determine whether two variable pieces overlap.
+static bool piecesOverlap(DIVariable P1, DIVariable P2) {
+ if (!P1.isVariablePiece() || !P2.isVariablePiece())
+ return true;
+ unsigned l1 = P1.getPieceOffset();
+ unsigned l2 = P2.getPieceOffset();
+ unsigned r1 = l1 + P1.getPieceSize();
+ unsigned r2 = l2 + P2.getPieceSize();
+ // True where [l1,r1[ and [r1,r2[ overlap.
+ return (l1 < r2) && (l2 < r1);
+}
+
+/// Build the location list for all DBG_VALUEs in the function that
+/// describe the same variable. If the ranges of several independent
+/// pieces of the same variable overlap partially, split them up and
+/// combine the ranges. The resulting DebugLocEntries are will have
+/// strict monotonically increasing begin addresses and will never
+/// overlap.
+//
+// Input:
+//
+// Ranges History [var, loc, piece ofs size]
+// 0 | [x, (reg0, piece 0, 32)]
+// 1 | | [x, (reg1, piece 32, 32)] <- IsPieceOfPrevEntry
+// 2 | | ...
+// 3 | [clobber reg0]
+// 4 [x, (mem, piece 0, 64)] <- overlapping with both previous pieces of x.
+//
+// Output:
+//
+// [0-1] [x, (reg0, piece 0, 32)]
+// [1-3] [x, (reg0, piece 0, 32), (reg1, piece 32, 32)]
+// [3-4] [x, (reg1, piece 32, 32)]
+// [4- ] [x, (mem, piece 0, 64)]
+void DwarfDebug::
+buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
+ const DbgValueHistoryMap::InstrRanges &Ranges,
+ DwarfCompileUnit *TheCU) {
+ typedef std::pair<DIVariable, DebugLocEntry::Value> Range;
+ SmallVector<Range, 4> OpenRanges;
+
+ for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
+ const MachineInstr *Begin = I->first;
+ const MachineInstr *End = I->second;
+ assert(Begin->isDebugValue() && "Invalid History entry");
+
+ // Check if a variable is inaccessible in this range.
+ if (!Begin->isDebugValue() ||
+ (Begin->getNumOperands() > 1 && Begin->getOperand(0).isReg() &&
+ !Begin->getOperand(0).getReg())) {
+ OpenRanges.clear();
+ continue;
+ }
+
+ // If this piece overlaps with any open ranges, truncate them.
+ DIVariable DIVar = Begin->getDebugVariable();
+ auto Last = std::remove_if(OpenRanges.begin(), OpenRanges.end(), [&](Range R){
+ return piecesOverlap(DIVar, R.first);
+ });
+ OpenRanges.erase(Last, OpenRanges.end());
+
+ const MCSymbol *StartLabel = getLabelBeforeInsn(Begin);
+ assert(StartLabel && "Forgot label before DBG_VALUE starting a range!");
+
+ const MCSymbol *EndLabel;
+ if (End != nullptr)
+ EndLabel = getLabelAfterInsn(End);
+ else if (std::next(I) == Ranges.end())
+ EndLabel = FunctionEndSym;
+ else
+ EndLabel = getLabelBeforeInsn(std::next(I)->first);
+ assert(EndLabel && "Forgot label after instruction ending a range!");
+
+ DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n");
+
+ auto Value = getDebugLocValue(Begin);
+ DebugLocEntry Loc(StartLabel, EndLabel, Value, TheCU);
+ if (DebugLoc.empty() || !DebugLoc.back().Merge(Loc)) {
+ // Add all values from still valid non-overlapping pieces.
+ for (auto Range : OpenRanges)
+ Loc.addValue(Range.second);
+ DebugLoc.push_back(std::move(Loc));
+ }
+ // Add this value to the list of open ranges.
+ if (DIVar.isVariablePiece())
+ OpenRanges.push_back({DIVar, Value});
+
+ DEBUG(dbgs() << "Values:\n";
+ for (auto Value : DebugLoc.back().getValues())
+ Value.getVariable()->dump();
+ dbgs() << "-----\n");
+ }
+}
+
+
// Find variables for each lexical scope.
void
DwarfDebug::collectVariableInfo(SmallPtrSet<const MDNode *, 16> &Processed) {
@@ -1227,7 +1322,7 @@
if (!Scope)
continue;
- Processed.insert(DV);
+ Processed.insert(getEntireVariable(DV));
const MachineInstr *MInsn = Ranges.front().first;
assert(MInsn->isDebugValue() && "History must begin with debug value");
ensureAbstractVariableIsCreatedIfScoped(DV, Scope->getScopeNode());
@@ -1246,38 +1341,9 @@
DebugLocList &LocList = DotDebugLocEntries.back();
LocList.Label =
Asm->GetTempSymbol("debug_loc", DotDebugLocEntries.size() - 1);
- SmallVector<DebugLocEntry, 4> &DebugLoc = LocList.List;
- for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
- const MachineInstr *Begin = I->first;
- const MachineInstr *End = I->second;
- assert(Begin->isDebugValue() && "Invalid History entry");
- // Check if a variable is unaccessible in this range.
- if (Begin->getNumOperands() > 1 && Begin->getOperand(0).isReg() &&
- !Begin->getOperand(0).getReg())
- continue;
- DEBUG(dbgs() << "DotDebugLoc Pair:\n" << "\t" << *Begin);
- if (End != nullptr)
- DEBUG(dbgs() << "\t" << *End);
- else
- DEBUG(dbgs() << "\tNULL\n");
-
- const MCSymbol *StartLabel = getLabelBeforeInsn(Begin);
- assert(StartLabel && "Forgot label before DBG_VALUE starting a range!");
-
- const MCSymbol *EndLabel;
- if (End != nullptr)
- EndLabel = getLabelAfterInsn(End);
- else if (std::next(I) == Ranges.end())
- EndLabel = FunctionEndSym;
- else
- EndLabel = getLabelBeforeInsn(std::next(I)->first);
- assert(EndLabel && "Forgot label after instruction ending a range!");
-
- DebugLocEntry Loc(StartLabel, EndLabel, getDebugLocValue(Begin), TheCU);
- if (DebugLoc.empty() || !DebugLoc.back().Merge(Loc))
- DebugLoc.push_back(std::move(Loc));
- }
+ // Build the location list for this variable.
+ buildLocationList(LocList.List, Ranges, TheCU);
}
// Collect info for variables that were optimized out.
@@ -1476,10 +1542,25 @@
// The first mention of a function argument gets the FunctionBeginSym
// label, so arguments are visible when breaking at function entry.
- DIVariable DV(I.first);
+ DIVariable DV(Ranges.front().first->getDebugVariable());
if (DV.isVariable() && DV.getTag() == dwarf::DW_TAG_arg_variable &&
- getDISubprogram(DV.getContext()).describes(MF->getFunction()))
- LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym;
+ getDISubprogram(DV.getContext()).describes(MF->getFunction())) {
+ if (!DV.isVariablePiece())
+ LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym;
+ else {
+ // Mark all non-overlapping initial pieces.
+ for (auto I = Ranges.begin(); I != Ranges.end(); ++I) {
+ DIVariable Piece = I->first->getDebugVariable();
+ if (std::all_of(Ranges.begin(), I,
+ [&](DbgValueHistoryMap::InstrRange Pred){
+ return !piecesOverlap(Piece, Pred.first->getDebugVariable());
+ }))
+ LabelsBeforeInsn[I->first] = FunctionBeginSym;
+ else
+ break;
+ }
+ }
+ }
for (const auto &Range : Ranges) {
requestLabelBeforeInsn(Range.first);
@@ -1962,12 +2043,79 @@
Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection());
}
+/// Emits an optimal (=sorted) sequence of DW_OP_pieces.
+void DwarfDebug::emitLocPieces(ByteStreamer &Streamer,
+ const DITypeIdentifierMap &Map,
+ ArrayRef<DebugLocEntry::Value> Values) {
+ typedef DebugLocEntry::Value Piece;
+ SmallVector<Piece, 4> Pieces(Values.begin(), Values.end());
+ assert(std::all_of(Pieces.begin(), Pieces.end(), [](Piece &P) {
+ return DIVariable(P.getVariable()).isVariablePiece();
+ }) && "all values are expected to be pieces");
+
+ // Sort the pieces so they can be emitted using DW_OP_piece.
+ std::sort(Pieces.begin(), Pieces.end(), [](const Piece &A, const Piece &B) {
+ DIVariable VarA(A.getVariable());
+ DIVariable VarB(B.getVariable());
+ return VarA.getPieceOffset() < VarB.getPieceOffset();
+ });
+ // Remove any duplicate entries by dropping all but the first.
+ Pieces.erase(std::unique(Pieces.begin(), Pieces.end(),
+ [] (const Piece &A,const Piece &B){
+ return A.getVariable() == B.getVariable();
+ }), Pieces.end());
+
+ unsigned Offset = 0;
+ for (auto Piece : Pieces) {
+ DIVariable Var(Piece.getVariable());
+ unsigned PieceOffset = Var.getPieceOffset();
+ unsigned PieceSize = Var.getPieceSize();
+ assert(Offset <= PieceOffset && "overlapping pieces in DebugLocEntry");
+ if (Offset < PieceOffset) {
+ // The DWARF spec seriously mandates pieces with no locations for gaps.
+ Asm->EmitDwarfOpPiece(Streamer, (PieceOffset-Offset)*8);
+ Offset += PieceOffset-Offset;
+ }
+
+ Offset += PieceSize;
+
+ const unsigned SizeOfByte = 8;
+ assert(!Var.isIndirect() && "indirect address for piece");
+#ifndef NDEBUG
+ unsigned VarSize = Var.getSizeInBits(Map);
+ assert(PieceSize+PieceOffset <= VarSize/SizeOfByte
+ && "piece is larger than or outside of variable");
+ assert(PieceSize*SizeOfByte != VarSize
+ && "piece covers entire variable");
+#endif
+ if (Piece.isLocation() && Piece.getLoc().isReg())
+ Asm->EmitDwarfRegOpPiece(Streamer,
+ Piece.getLoc(),
+ PieceSize*SizeOfByte);
+ else {
+ emitDebugLocValue(Streamer, Piece);
+ Asm->EmitDwarfOpPiece(Streamer, PieceSize*SizeOfByte);
+ }
+ }
+}
+
+
void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer,
const DebugLocEntry &Entry) {
- assert(Entry.getValues().size() == 1 &&
- "multi-value entries are not supported yet.");
const DebugLocEntry::Value Value = Entry.getValues()[0];
DIVariable DV(Value.getVariable());
+ if (DV.isVariablePiece())
+ // Emit all pieces that belong to the same variable and range.
+ return emitLocPieces(Streamer, TypeIdentifierMap, Entry.getValues());
+
+ assert(Entry.getValues().size() == 1 && "only pieces may have >1 value");
+ emitDebugLocValue(Streamer, Value);
+}
+
+void DwarfDebug::emitDebugLocValue(ByteStreamer &Streamer,
+ const DebugLocEntry::Value &Value) {
+ DIVariable DV(Value.getVariable());
+ // Regular entry.
if (Value.isInt()) {
DIBasicType BTy(resolve(DV.getType()));
if (BTy.Verify() && (BTy.getEncoding() == dwarf::DW_ATE_signed ||
@@ -2014,6 +2162,9 @@
} else if (Element == DIBuilder::OpDeref) {
if (!Loc.isReg())
Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref");
+ } else if (Element == DIBuilder::OpPiece) {
+ i += 3;
+ // handled in emitDebugLocEntry.
} else
llvm_unreachable("unknown Opcode found in complex address");
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
index f45314a..fd6c155 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfDebug.h
@@ -535,6 +535,12 @@
/// \brief Populate LexicalScope entries with variables' info.
void collectVariableInfo(SmallPtrSet<const MDNode *, 16> &ProcessedVars);
+ /// \brief Build the location list for all DBG_VALUEs in the
+ /// function that describe the same variable.
+ void buildLocationList(SmallVectorImpl<DebugLocEntry> &DebugLoc,
+ const DbgValueHistoryMap::InstrRanges &Ranges,
+ DwarfCompileUnit *TheCU);
+
/// \brief Collect variable information from the side table maintained
/// by MMI.
void collectVariableInfoFromMMITable(SmallPtrSet<const MDNode *, 16> &P);
@@ -642,6 +648,13 @@
/// \brief Emit an entry for the debug loc section. This can be used to
/// handle an entry that's going to be emitted into the debug loc section.
void emitDebugLocEntry(ByteStreamer &Streamer, const DebugLocEntry &Entry);
+ /// \brief emit a single value for the debug loc section.
+ void emitDebugLocValue(ByteStreamer &Streamer,
+ const DebugLocEntry::Value &Value);
+ /// Emits an optimal (=sorted) sequence of DW_OP_pieces.
+ void emitLocPieces(ByteStreamer &Streamer,
+ const DITypeIdentifierMap &Map,
+ ArrayRef<DebugLocEntry::Value> Values);
/// Emit the location for a debug loc entry, including the size header.
void emitDebugLocEntryLocation(const DebugLocEntry &Entry);
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
index 2139ffc..6cc90e0c 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
@@ -491,7 +491,10 @@
}
/// addRegisterOp - Add register operand.
-void DwarfUnit::addRegisterOp(DIELoc &TheDie, unsigned Reg) {
+// FIXME: Ideally, this would share the implementation with
+// AsmPrinter::EmitDwarfRegOpPiece.
+void DwarfUnit::addRegisterOpPiece(DIELoc &TheDie, unsigned Reg,
+ unsigned SizeInBits, unsigned OffsetInBits) {
const TargetRegisterInfo *RI = Asm->TM.getRegisterInfo();
int DWReg = RI->getDwarfRegNum(Reg, false);
bool isSubRegister = DWReg < 0;
@@ -511,7 +514,7 @@
return;
}
- // Emit register
+ // Emit register.
if (DWReg < 32)
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_reg0 + DWReg);
else {
@@ -519,18 +522,34 @@
addUInt(TheDie, dwarf::DW_FORM_udata, DWReg);
}
- // Emit Mask
- if (isSubRegister) {
- unsigned Size = RI->getSubRegIdxSize(Idx);
- unsigned Offset = RI->getSubRegIdxOffset(Idx);
- if (Offset > 0) {
+ // Emit mask.
+ bool isPiece = SizeInBits > 0;
+ if (isSubRegister || isPiece) {
+ const unsigned SizeOfByte = 8;
+ unsigned RegSizeInBits = RI->getSubRegIdxSize(Idx);
+ unsigned RegOffsetInBits = RI->getSubRegIdxOffset(Idx);
+ unsigned PieceSizeInBits = std::max(SizeInBits, RegSizeInBits);
+ unsigned PieceOffsetInBits = OffsetInBits ? OffsetInBits : RegOffsetInBits;
+ assert(RegSizeInBits >= SizeInBits && "register smaller than value");
+
+ if (RegOffsetInBits != PieceOffsetInBits) {
+ // Manually shift the value into place, since the DW_OP_piece
+ // describes the part of the variable, not the position of the
+ // subregister.
+ addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_constu);
+ addUInt(TheDie, dwarf::DW_FORM_data1, RegOffsetInBits);
+ addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_shr);
+ }
+
+ if (PieceOffsetInBits > 0 || PieceSizeInBits % SizeOfByte) {
+ assert(PieceSizeInBits > 0 && "piece has zero size");
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece);
- addUInt(TheDie, dwarf::DW_FORM_data1, Size);
- addUInt(TheDie, dwarf::DW_FORM_data1, Offset);
- } else {
- unsigned ByteSize = Size / 8; // Assuming 8 bits per byte.
+ addUInt(TheDie, dwarf::DW_FORM_data1, PieceSizeInBits);
+ addUInt(TheDie, dwarf::DW_FORM_data1, PieceOffsetInBits);
+ } else {
+ assert(PieceSizeInBits > 0 && "piece has zero size");
addUInt(TheDie, dwarf::DW_FORM_data1, dwarf::DW_OP_piece);
- addUInt(TheDie, dwarf::DW_FORM_data1, ByteSize);
+ addUInt(TheDie, dwarf::DW_FORM_data1, PieceSizeInBits/SizeOfByte);
}
}
}
@@ -560,7 +579,7 @@
DIELoc *Loc = new (DIEValueAllocator) DIELoc();
if (Location.isReg() && !Indirect)
- addRegisterOp(*Loc, Location.getReg());
+ addRegisterOpPiece(*Loc, Location.getReg());
else {
addRegisterOffset(*Loc, Location.getReg(), Location.getOffset());
if (Indirect && !Location.isReg()) {
@@ -589,8 +608,13 @@
// DW_OP_breg + Offset instead of DW_OP_reg + Offset.
addRegisterOffset(*Loc, Location.getReg(), DV.getAddrElement(1));
i = 2;
+ } else if (N >= 2 && DV.getAddrElement(0) == DIBuilder::OpDeref) {
+ addRegisterOpPiece(*Loc, Location.getReg(),
+ DV.getVariable().getPieceSize(),
+ DV.getVariable().getPieceOffset());
+ i = 3;
} else
- addRegisterOp(*Loc, Location.getReg());
+ addRegisterOpPiece(*Loc, Location.getReg());
} else
addRegisterOffset(*Loc, Location.getReg(), Location.getOffset());
@@ -599,9 +623,21 @@
if (Element == DIBuilder::OpPlus) {
addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_plus_uconst);
addUInt(*Loc, dwarf::DW_FORM_udata, DV.getAddrElement(++i));
+
} else if (Element == DIBuilder::OpDeref) {
if (!Location.isReg())
addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref);
+
+ } else if (Element == DIBuilder::OpPiece) {
+ const unsigned SizeOfByte = 8;
+ unsigned PieceOffsetInBits = DV.getAddrElement(++i)*SizeOfByte;
+ unsigned PieceSizeInBits = DV.getAddrElement(++i)*SizeOfByte;
+ // Emit DW_OP_bit_piece Size Offset.
+ assert(PieceSizeInBits > 0 && "piece has zero size");
+ addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece);
+ addUInt(*Loc, dwarf::DW_FORM_udata, PieceSizeInBits);
+ addUInt(*Loc, dwarf::DW_FORM_udata, PieceOffsetInBits);
+
} else
llvm_unreachable("unknown DIBuilder Opcode");
}
@@ -712,7 +748,7 @@
DIELoc *Loc = new (DIEValueAllocator) DIELoc();
if (Location.isReg())
- addRegisterOp(*Loc, Location.getReg());
+ addRegisterOpPiece(*Loc, Location.getReg());
else
addRegisterOffset(*Loc, Location.getReg(), Location.getOffset());
diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
index 5580412..9e82a1b 100644
--- a/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
+++ b/llvm/lib/CodeGen/AsmPrinter/DwarfUnit.h
@@ -359,7 +359,8 @@
void addTemplateParams(DIE &Buffer, DIArray TParams);
/// addRegisterOp - Add register operand.
- void addRegisterOp(DIELoc &TheDie, unsigned Reg);
+ void addRegisterOpPiece(DIELoc &TheDie, unsigned Reg,
+ unsigned SizeInBits = 0, unsigned OffsetInBits = 0);
/// addRegisterOffset - Add register offset.
void addRegisterOffset(DIELoc &TheDie, unsigned Reg, int64_t Offset);