[codeview] Check for a DIExpression offset for local variables

Fixes inalloca parameters, which previously all pointed to the same
offset. Extend the test to use llvm-readobj so that we can test the
offset in a readable way.

llvm-svn: 302578
This commit is contained in:
Reid Kleckner 2017-05-09 19:59:29 +00:00
parent dfa7f613ed
commit b5fced7324
4 changed files with 72 additions and 1 deletions

View File

@ -2276,6 +2276,10 @@ public:
/// Append \p Ops with operations to apply the \p Offset.
static void appendOffset(SmallVectorImpl<uint64_t> &Ops, int64_t Offset);
/// If this is a constant offset, extract it. If there is no expression,
/// return true with an offset of zero.
bool extractIfOffset(int64_t &Offset) const;
/// Constants for DIExpression::prepend.
enum { NoDeref = false, WithDeref = true, WithStackValue = true };

View File

@ -888,13 +888,21 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
if (!Scope)
continue;
// If the variable has an attached offset expression, extract it.
// FIXME: Try to handle DW_OP_deref as well.
int64_t ExprOffset = 0;
if (VI.Expr)
if (!VI.Expr->extractIfOffset(ExprOffset))
continue;
// Get the frame register used and the offset.
unsigned FrameReg = 0;
int FrameOffset = TFI->getFrameIndexReference(*Asm->MF, VI.Slot, FrameReg);
uint16_t CVReg = TRI->getCodeViewRegNum(FrameReg);
// Calculate the label ranges.
LocalVarDefRange DefRange = createDefRangeMem(CVReg, FrameOffset);
LocalVarDefRange DefRange =
createDefRangeMem(CVReg, FrameOffset + ExprOffset);
for (const InsnRange &Range : Scope->getRanges()) {
const MCSymbol *Begin = getLabelBeforeInsn(Range.first);
const MCSymbol *End = getLabelAfterInsn(Range.second);

View File

@ -672,6 +672,24 @@ void DIExpression::appendOffset(SmallVectorImpl<uint64_t> &Ops,
}
}
bool DIExpression::extractIfOffset(int64_t &Offset) const {
if (getNumElements() == 0) {
Offset = 0;
return true;
}
if (getNumElements() != 2)
return false;
if (Elements[0] == dwarf::DW_OP_plus) {
Offset = Elements[1];
return true;
}
if (Elements[0] == dwarf::DW_OP_minus) {
Offset = -Elements[1];
return true;
}
return false;
}
DIExpression *DIExpression::prepend(const DIExpression *Expr, bool Deref,
int64_t Offset, bool StackValue) {
SmallVector<uint64_t, 8> Ops;

View File

@ -1,5 +1,6 @@
; RUN: llc -O0 < %s | FileCheck %s --check-prefix=CHECK --check-prefix=DEBUG
; RUN: llc < %s | FileCheck %s
; RUN: llc -filetype=obj -O0 < %s | llvm-readobj -codeview - | FileCheck %s --check-prefix=OBJ
; IR generated by the following source:
; struct NonTrivial {
@ -54,6 +55,46 @@
; CHECK: .asciz "c"
; CHECK: .cv_def_range [[start]] [[end]]
; OBJ-LABEL: ProcStart {
; OBJ: Kind: S_GPROC32_ID (0x1147)
; OBJ: DisplayName: f
; OBJ: }
; OBJ: Local {
; OBJ: Type: NonTrivial (0x1007)
; OBJ: Flags [ (0x1)
; OBJ: IsParameter (0x1)
; OBJ: ]
; OBJ: VarName: a
; OBJ: }
; OBJ: DefRangeRegisterRel {
; OBJ: BaseRegister: 21
; OBJ: BasePointerOffset: 12
; OBJ: }
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x1)
; OBJ: IsParameter (0x1)
; OBJ: ]
; OBJ: VarName: b
; OBJ: }
; OBJ: DefRangeRegisterRel {
; OBJ: BaseRegister: 21
; OBJ: BasePointerOffset: 16
; OBJ: }
; FIXME: Retain unused.
; OBJ: Local {
; OBJ: Type: int (0x74)
; OBJ: Flags [ (0x1)
; OBJ: IsParameter (0x1)
; OBJ: ]
; OBJ: VarName: c
; OBJ: }
; OBJ: DefRangeRegisterRel {
; OBJ: BaseRegister: 21
; OBJ: BasePointerOffset: 24
; OBJ: }
; OBJ-LABEL: ProcEnd {
; OBJ: }
; ModuleID = 't.cpp'