summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp101
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h16
2 files changed, 76 insertions, 41 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 5d1f08bf30b..1850a30a5d1 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -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;
}
@@ -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.
@@ -944,19 +954,20 @@ 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));
}
}
@@ -964,8 +975,13 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) {
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();
}
@@ -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));
@@ -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);
}
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
index 25b3f2c3a95..04551a4a120 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h
@@ -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.
@@ -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 {
OpenPOWER on IntegriCloud