Skip to content

Commit

Permalink
[codeview] Translate bitpiece metadata to DEFRANGE_SUBFIELD* records
Browse files Browse the repository at this point in the history
This allows LLVM to describe locations of aggregate variables that have
been split by SROA.

Fixes PR29141

Reviewers: amccarth, majnemer

Differential Revision: https://reviews.llvm.org/D25253

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@283388 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
rnk committed Oct 5, 2016
1 parent 1911873 commit ba129eb
Show file tree
Hide file tree
Showing 4 changed files with 520 additions and 52 deletions.
26 changes: 15 additions & 11 deletions include/llvm/DebugInfo/CodeView/SymbolRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -677,15 +677,12 @@ class DefRangeRegisterSym : public SymbolRecord {
RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}

DefRangeRegisterSym(uint16_t Register, uint16_t MayHaveNoName,
uint32_t OffsetStart, uint16_t ISectStart, uint16_t Range,
ArrayRef<LocalVariableAddrGap> Gaps)
: SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), RecordOffset(0),
Gaps(Gaps) {
Header.Register = Register;
Header.MayHaveNoName = MayHaveNoName;
Header.Range.OffsetStart = OffsetStart;
Header.Range.ISectStart = ISectStart;
Header.Range.Range = Range;
Header.Range = {};
}

static Expected<DefRangeRegisterSym> deserialize(SymbolRecordKind Kind,
Expand Down Expand Up @@ -731,6 +728,7 @@ class DefRangeSubfieldRegisterSym : public SymbolRecord {
Header.Register = Register;
Header.MayHaveNoName = MayHaveNoName;
Header.OffsetInParent = OffsetInParent;
Header.Range = {};
}

static Expected<DefRangeSubfieldRegisterSym>
Expand Down Expand Up @@ -802,17 +800,14 @@ class DefRangeRegisterRelSym : public SymbolRecord {
RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}

DefRangeRegisterRelSym(uint16_t BaseRegister, uint16_t Flags,
int32_t BasePointerOffset, uint32_t OffsetStart,
uint16_t ISectStart, uint16_t Range,
int32_t BasePointerOffset,
ArrayRef<LocalVariableAddrGap> Gaps)
: SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), RecordOffset(0),
Gaps(Gaps) {
Header.BaseRegister = BaseRegister;
Header.Flags = Flags;
Header.BasePointerOffset = BasePointerOffset;
Header.Range.OffsetStart = OffsetStart;
Header.Range.ISectStart = ISectStart;
Header.Range.Range = Range;
Header.Range = {};
}

static Expected<DefRangeRegisterRelSym> deserialize(SymbolRecordKind Kind,
Expand All @@ -825,8 +820,17 @@ class DefRangeRegisterRelSym : public SymbolRecord {
return DefRangeRegisterRelSym(RecordOffset, H, Gaps);
}

bool hasSpilledUDTMember() const { return Header.Flags & 1; }
uint16_t offsetInParent() const { return Header.Flags >> 4; }
// The flags implement this notional bitfield:
// uint16_t IsSubfield : 1;
// uint16_t Padding : 3;
// uint16_t OffsetInParent : 12;
enum : uint16_t {
IsSubfieldFlag = 1,
OffsetInParentShift = 4,
};

bool hasSpilledUDTMember() const { return Header.Flags & IsSubfieldFlag; }
uint16_t offsetInParent() const { return Header.Flags >> OffsetInParentShift; }

uint32_t getRelocationOffset() const {
return RecordOffset + offsetof(Hdr, Range);
Expand Down
101 changes: 65 additions & 36 deletions lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -838,17 +838,21 @@ CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) {
DR.InMemory = -1;
DR.DataOffset = Offset;
assert(DR.DataOffset == Offset && "truncation");
DR.IsSubfield = 0;
DR.StructOffset = 0;
DR.CVRegister = CVRegister;
return DR;
}

CodeViewDebug::LocalVarDefRange
CodeViewDebug::createDefRangeReg(uint16_t CVRegister) {
CodeViewDebug::createDefRangeGeneral(uint16_t CVRegister, bool InMemory,
int Offset, bool IsSubfield,
uint16_t StructOffset) {
LocalVarDefRange DR;
DR.InMemory = 0;
DR.DataOffset = 0;
DR.StructOffset = 0;
DR.InMemory = InMemory;
DR.DataOffset = Offset;
DR.IsSubfield = IsSubfield;
DR.StructOffset = StructOffset;
DR.CVRegister = CVRegister;
return DR;
}
Expand Down Expand Up @@ -929,10 +933,16 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
const MachineInstr *DVInst = Range.first;
assert(DVInst->isDebugValue() && "Invalid History entry");
const DIExpression *DIExpr = DVInst->getDebugExpression();

// Bail if there is a complex DWARF expression for now.
if (DIExpr && DIExpr->getNumElements() > 0)
continue;
bool IsSubfield = false;
unsigned StructOffset = 0;

// Handle bitpieces.
if (DIExpr && DIExpr->isBitPiece()) {
IsSubfield = true;
StructOffset = DIExpr->getBitPieceOffset() / 8;
} else if (DIExpr && DIExpr->getNumElements() > 0) {
continue; // Ignore unrecognized exprs.
}

// Bail if operand 0 is not a valid register. This means the variable is a
// simple constant, or is described by a complex expression.
Expand All @@ -944,28 +954,34 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
continue;

// Handle the two cases we can handle: indirect in memory and in register.
bool IsIndirect = DVInst->getOperand(1).isImm();
unsigned CVReg = TRI->getCodeViewRegNum(DVInst->getOperand(0).getReg());
unsigned CVReg = TRI->getCodeViewRegNum(Reg);
bool InMemory = DVInst->getOperand(1).isImm();
int Offset = InMemory ? DVInst->getOperand(1).getImm() : 0;
{
LocalVarDefRange DefRange;
if (IsIndirect) {
int64_t Offset = DVInst->getOperand(1).getImm();
DefRange = createDefRangeMem(CVReg, Offset);
} else {
DefRange = createDefRangeReg(CVReg);
}
LocalVarDefRange DR;
DR.CVRegister = CVReg;
DR.InMemory = InMemory;
DR.DataOffset = Offset;
DR.IsSubfield = IsSubfield;
DR.StructOffset = StructOffset;

if (Var.DefRanges.empty() ||
Var.DefRanges.back().isDifferentLocation(DefRange)) {
Var.DefRanges.emplace_back(std::move(DefRange));
Var.DefRanges.back().isDifferentLocation(DR)) {
Var.DefRanges.emplace_back(std::move(DR));
}
}

// Compute the label range.
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
const MCSymbol *End = getLabelAfterInsn(Range.second);
if (!End) {
if (std::next(I) != E)
End = getLabelBeforeInsn(std::next(I)->first);
// This range is valid until the next overlapping bitpiece. In the
// common case, ranges will not be bitpieces, so they will overlap.
auto J = std::next(I);
while (J != E && !piecesOverlap(DIExpr, J->first->getDebugExpression()))
++J;
if (J != E)
End = getLabelBeforeInsn(J->first);
else
End = Asm->getFunctionEnd();
}
Expand Down Expand Up @@ -2024,13 +2040,15 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
SmallString<20> BytePrefix;
for (const LocalVarDefRange &DefRange : Var.DefRanges) {
BytePrefix.clear();
// FIXME: Handle bitpieces.
if (DefRange.StructOffset != 0)
continue;

if (DefRange.InMemory) {
DefRangeRegisterRelSym Sym(DefRange.CVRegister, 0, DefRange.DataOffset, 0,
0, 0, ArrayRef<LocalVariableAddrGap>());
uint16_t RegRelFlags = 0;
if (DefRange.IsSubfield) {
RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag |
(DefRange.StructOffset
<< DefRangeRegisterRelSym::OffsetInParentShift);
}
DefRangeRegisterRelSym Sym(DefRange.CVRegister, RegRelFlags,
DefRange.DataOffset, None);
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
Expand All @@ -2039,15 +2057,26 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
} else {
assert(DefRange.DataOffset == 0 && "unexpected offset into register");
// Unclear what matters here.
DefRangeRegisterSym Sym(DefRange.CVRegister, 0, 0, 0, 0,
ArrayRef<LocalVariableAddrGap>());
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&Sym.Header),
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
if (DefRange.IsSubfield) {
// Unclear what matters here.
DefRangeSubfieldRegisterSym Sym(DefRange.CVRegister, 0,
DefRange.StructOffset, None);
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_SUBFIELD_REGISTER);
BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
sizeof(SymKind));
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&Sym.Header),
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
} else {
// Unclear what matters here.
DefRangeRegisterSym Sym(DefRange.CVRegister, 0, None);
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
sizeof(SymKind));
BytePrefix +=
StringRef(reinterpret_cast<const char *>(&Sym.Header),
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
}
}
OS.EmitCVDefRangeDirective(DefRange.Ranges, BytePrefix);
}
Expand Down
16 changes: 11 additions & 5 deletions lib/CodeGen/AsmPrinter/CodeViewDebug.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,11 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
/// Offset of variable data in memory.
int DataOffset : 31;

/// Offset of the data into the user level struct. If zero, no splitting
/// occurred.
uint16_t StructOffset;
/// Non-zero if this is a piece of an aggregate.
uint16_t IsSubfield : 1;

/// Offset into aggregate.
uint16_t StructOffset : 15;

/// Register containing the data or the register base of the memory
/// location containing the data.
Expand All @@ -60,14 +62,18 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
/// ranges.
bool isDifferentLocation(LocalVarDefRange &O) {
return InMemory != O.InMemory || DataOffset != O.DataOffset ||
StructOffset != O.StructOffset || CVRegister != O.CVRegister;
IsSubfield != O.IsSubfield || StructOffset != O.StructOffset ||
CVRegister != O.CVRegister;
}

SmallVector<std::pair<const MCSymbol *, const MCSymbol *>, 1> Ranges;
};

static LocalVarDefRange createDefRangeMem(uint16_t CVRegister, int Offset);
static LocalVarDefRange createDefRangeReg(uint16_t CVRegister);
static LocalVarDefRange createDefRangeGeneral(uint16_t CVRegister,
bool InMemory, int Offset,
bool IsSubfield,
uint16_t StructOffset);

/// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.
struct LocalVariable {
Expand Down
Loading

0 comments on commit ba129eb

Please sign in to comment.