Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit ba129eb

Browse files
committed
[codeview] Translate bitpiece metadata to DEFRANGE_SUBFIELD* records
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
1 parent 1911873 commit ba129eb

File tree

4 files changed

+520
-52
lines changed

4 files changed

+520
-52
lines changed

include/llvm/DebugInfo/CodeView/SymbolRecord.h

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -677,15 +677,12 @@ class DefRangeRegisterSym : public SymbolRecord {
677677
RecordOffset(RecordOffset), Header(*H), Gaps(Gaps) {}
678678

679679
DefRangeRegisterSym(uint16_t Register, uint16_t MayHaveNoName,
680-
uint32_t OffsetStart, uint16_t ISectStart, uint16_t Range,
681680
ArrayRef<LocalVariableAddrGap> Gaps)
682681
: SymbolRecord(SymbolRecordKind::DefRangeRegisterSym), RecordOffset(0),
683682
Gaps(Gaps) {
684683
Header.Register = Register;
685684
Header.MayHaveNoName = MayHaveNoName;
686-
Header.Range.OffsetStart = OffsetStart;
687-
Header.Range.ISectStart = ISectStart;
688-
Header.Range.Range = Range;
685+
Header.Range = {};
689686
}
690687

691688
static Expected<DefRangeRegisterSym> deserialize(SymbolRecordKind Kind,
@@ -731,6 +728,7 @@ class DefRangeSubfieldRegisterSym : public SymbolRecord {
731728
Header.Register = Register;
732729
Header.MayHaveNoName = MayHaveNoName;
733730
Header.OffsetInParent = OffsetInParent;
731+
Header.Range = {};
734732
}
735733

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

804802
DefRangeRegisterRelSym(uint16_t BaseRegister, uint16_t Flags,
805-
int32_t BasePointerOffset, uint32_t OffsetStart,
806-
uint16_t ISectStart, uint16_t Range,
803+
int32_t BasePointerOffset,
807804
ArrayRef<LocalVariableAddrGap> Gaps)
808805
: SymbolRecord(SymbolRecordKind::DefRangeRegisterRelSym), RecordOffset(0),
809806
Gaps(Gaps) {
810807
Header.BaseRegister = BaseRegister;
811808
Header.Flags = Flags;
812809
Header.BasePointerOffset = BasePointerOffset;
813-
Header.Range.OffsetStart = OffsetStart;
814-
Header.Range.ISectStart = ISectStart;
815-
Header.Range.Range = Range;
810+
Header.Range = {};
816811
}
817812

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

828-
bool hasSpilledUDTMember() const { return Header.Flags & 1; }
829-
uint16_t offsetInParent() const { return Header.Flags >> 4; }
823+
// The flags implement this notional bitfield:
824+
// uint16_t IsSubfield : 1;
825+
// uint16_t Padding : 3;
826+
// uint16_t OffsetInParent : 12;
827+
enum : uint16_t {
828+
IsSubfieldFlag = 1,
829+
OffsetInParentShift = 4,
830+
};
831+
832+
bool hasSpilledUDTMember() const { return Header.Flags & IsSubfieldFlag; }
833+
uint16_t offsetInParent() const { return Header.Flags >> OffsetInParentShift; }
830834

831835
uint32_t getRelocationOffset() const {
832836
return RecordOffset + offsetof(Hdr, Range);

lib/CodeGen/AsmPrinter/CodeViewDebug.cpp

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -838,17 +838,21 @@ CodeViewDebug::createDefRangeMem(uint16_t CVRegister, int Offset) {
838838
DR.InMemory = -1;
839839
DR.DataOffset = Offset;
840840
assert(DR.DataOffset == Offset && "truncation");
841+
DR.IsSubfield = 0;
841842
DR.StructOffset = 0;
842843
DR.CVRegister = CVRegister;
843844
return DR;
844845
}
845846

846847
CodeViewDebug::LocalVarDefRange
847-
CodeViewDebug::createDefRangeReg(uint16_t CVRegister) {
848+
CodeViewDebug::createDefRangeGeneral(uint16_t CVRegister, bool InMemory,
849+
int Offset, bool IsSubfield,
850+
uint16_t StructOffset) {
848851
LocalVarDefRange DR;
849-
DR.InMemory = 0;
850-
DR.DataOffset = 0;
851-
DR.StructOffset = 0;
852+
DR.InMemory = InMemory;
853+
DR.DataOffset = Offset;
854+
DR.IsSubfield = IsSubfield;
855+
DR.StructOffset = StructOffset;
852856
DR.CVRegister = CVRegister;
853857
return DR;
854858
}
@@ -929,10 +933,16 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
929933
const MachineInstr *DVInst = Range.first;
930934
assert(DVInst->isDebugValue() && "Invalid History entry");
931935
const DIExpression *DIExpr = DVInst->getDebugExpression();
932-
933-
// Bail if there is a complex DWARF expression for now.
934-
if (DIExpr && DIExpr->getNumElements() > 0)
935-
continue;
936+
bool IsSubfield = false;
937+
unsigned StructOffset = 0;
938+
939+
// Handle bitpieces.
940+
if (DIExpr && DIExpr->isBitPiece()) {
941+
IsSubfield = true;
942+
StructOffset = DIExpr->getBitPieceOffset() / 8;
943+
} else if (DIExpr && DIExpr->getNumElements() > 0) {
944+
continue; // Ignore unrecognized exprs.
945+
}
936946

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

946956
// Handle the two cases we can handle: indirect in memory and in register.
947-
bool IsIndirect = DVInst->getOperand(1).isImm();
948-
unsigned CVReg = TRI->getCodeViewRegNum(DVInst->getOperand(0).getReg());
957+
unsigned CVReg = TRI->getCodeViewRegNum(Reg);
958+
bool InMemory = DVInst->getOperand(1).isImm();
959+
int Offset = InMemory ? DVInst->getOperand(1).getImm() : 0;
949960
{
950-
LocalVarDefRange DefRange;
951-
if (IsIndirect) {
952-
int64_t Offset = DVInst->getOperand(1).getImm();
953-
DefRange = createDefRangeMem(CVReg, Offset);
954-
} else {
955-
DefRange = createDefRangeReg(CVReg);
956-
}
961+
LocalVarDefRange DR;
962+
DR.CVRegister = CVReg;
963+
DR.InMemory = InMemory;
964+
DR.DataOffset = Offset;
965+
DR.IsSubfield = IsSubfield;
966+
DR.StructOffset = StructOffset;
967+
957968
if (Var.DefRanges.empty() ||
958-
Var.DefRanges.back().isDifferentLocation(DefRange)) {
959-
Var.DefRanges.emplace_back(std::move(DefRange));
969+
Var.DefRanges.back().isDifferentLocation(DR)) {
970+
Var.DefRanges.emplace_back(std::move(DR));
960971
}
961972
}
962973

963974
// Compute the label range.
964975
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
965976
const MCSymbol *End = getLabelAfterInsn(Range.second);
966977
if (!End) {
967-
if (std::next(I) != E)
968-
End = getLabelBeforeInsn(std::next(I)->first);
978+
// This range is valid until the next overlapping bitpiece. In the
979+
// common case, ranges will not be bitpieces, so they will overlap.
980+
auto J = std::next(I);
981+
while (J != E && !piecesOverlap(DIExpr, J->first->getDebugExpression()))
982+
++J;
983+
if (J != E)
984+
End = getLabelBeforeInsn(J->first);
969985
else
970986
End = Asm->getFunctionEnd();
971987
}
@@ -2024,13 +2040,15 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
20242040
SmallString<20> BytePrefix;
20252041
for (const LocalVarDefRange &DefRange : Var.DefRanges) {
20262042
BytePrefix.clear();
2027-
// FIXME: Handle bitpieces.
2028-
if (DefRange.StructOffset != 0)
2029-
continue;
2030-
20312043
if (DefRange.InMemory) {
2032-
DefRangeRegisterRelSym Sym(DefRange.CVRegister, 0, DefRange.DataOffset, 0,
2033-
0, 0, ArrayRef<LocalVariableAddrGap>());
2044+
uint16_t RegRelFlags = 0;
2045+
if (DefRange.IsSubfield) {
2046+
RegRelFlags = DefRangeRegisterRelSym::IsSubfieldFlag |
2047+
(DefRange.StructOffset
2048+
<< DefRangeRegisterRelSym::OffsetInParentShift);
2049+
}
2050+
DefRangeRegisterRelSym Sym(DefRange.CVRegister, RegRelFlags,
2051+
DefRange.DataOffset, None);
20342052
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER_REL);
20352053
BytePrefix +=
20362054
StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
@@ -2039,15 +2057,26 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
20392057
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
20402058
} else {
20412059
assert(DefRange.DataOffset == 0 && "unexpected offset into register");
2042-
// Unclear what matters here.
2043-
DefRangeRegisterSym Sym(DefRange.CVRegister, 0, 0, 0, 0,
2044-
ArrayRef<LocalVariableAddrGap>());
2045-
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
2046-
BytePrefix +=
2047-
StringRef(reinterpret_cast<const char *>(&SymKind), sizeof(SymKind));
2048-
BytePrefix +=
2049-
StringRef(reinterpret_cast<const char *>(&Sym.Header),
2050-
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
2060+
if (DefRange.IsSubfield) {
2061+
// Unclear what matters here.
2062+
DefRangeSubfieldRegisterSym Sym(DefRange.CVRegister, 0,
2063+
DefRange.StructOffset, None);
2064+
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_SUBFIELD_REGISTER);
2065+
BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
2066+
sizeof(SymKind));
2067+
BytePrefix +=
2068+
StringRef(reinterpret_cast<const char *>(&Sym.Header),
2069+
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
2070+
} else {
2071+
// Unclear what matters here.
2072+
DefRangeRegisterSym Sym(DefRange.CVRegister, 0, None);
2073+
ulittle16_t SymKind = ulittle16_t(S_DEFRANGE_REGISTER);
2074+
BytePrefix += StringRef(reinterpret_cast<const char *>(&SymKind),
2075+
sizeof(SymKind));
2076+
BytePrefix +=
2077+
StringRef(reinterpret_cast<const char *>(&Sym.Header),
2078+
sizeof(Sym.Header) - sizeof(LocalVariableAddrRange));
2079+
}
20512080
}
20522081
OS.EmitCVDefRangeDirective(DefRange.Ranges, BytePrefix);
20532082
}

lib/CodeGen/AsmPrinter/CodeViewDebug.h

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,11 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
4848
/// Offset of variable data in memory.
4949
int DataOffset : 31;
5050

51-
/// Offset of the data into the user level struct. If zero, no splitting
52-
/// occurred.
53-
uint16_t StructOffset;
51+
/// Non-zero if this is a piece of an aggregate.
52+
uint16_t IsSubfield : 1;
53+
54+
/// Offset into aggregate.
55+
uint16_t StructOffset : 15;
5456

5557
/// Register containing the data or the register base of the memory
5658
/// location containing the data.
@@ -60,14 +62,18 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
6062
/// ranges.
6163
bool isDifferentLocation(LocalVarDefRange &O) {
6264
return InMemory != O.InMemory || DataOffset != O.DataOffset ||
63-
StructOffset != O.StructOffset || CVRegister != O.CVRegister;
65+
IsSubfield != O.IsSubfield || StructOffset != O.StructOffset ||
66+
CVRegister != O.CVRegister;
6467
}
6568

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

6972
static LocalVarDefRange createDefRangeMem(uint16_t CVRegister, int Offset);
70-
static LocalVarDefRange createDefRangeReg(uint16_t CVRegister);
73+
static LocalVarDefRange createDefRangeGeneral(uint16_t CVRegister,
74+
bool InMemory, int Offset,
75+
bool IsSubfield,
76+
uint16_t StructOffset);
7177

7278
/// Similar to DbgVariable in DwarfDebug, but not dwarf-specific.
7379
struct LocalVariable {

0 commit comments

Comments
 (0)