Skip to content

Commit

Permalink
Remove addBlockByrefAddress(), it is dead code as far as clang is con…
Browse files Browse the repository at this point in the history
…cerned.

This patch removes addBlockByrefAddress(), it is dead code as far as
clang is concerned: Every byref block capture is emitted with a
complex expression that is equivalent to what this function does.

rdar://problem/31629055

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

llvm-svn: 341737
  • Loading branch information
adrian-prantl committed Sep 8, 2018
1 parent 4357ca6 commit 609bf36
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 134 deletions.
2 changes: 0 additions & 2 deletions llvm/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp
Expand Up @@ -978,8 +978,6 @@ void DwarfCompileUnit::addVariableAddress(const DbgVariable &DV, DIE &Die,
"block byref variable without a complex expression");
if (DV.hasComplexAddress())
addComplexAddress(DV, Die, dwarf::DW_AT_location, Location);
else if (DV.isBlockByrefVariable())
addBlockByrefAddress(DV, Die, dwarf::DW_AT_location, Location);
else
addAddress(Die, dwarf::DW_AT_location, Location);
}
Expand Down
132 changes: 0 additions & 132 deletions llvm/lib/CodeGen/AsmPrinter/DwarfUnit.cpp
Expand Up @@ -427,138 +427,6 @@ void DwarfUnit::addSourceLine(DIE &Die, const DIObjCProperty *Ty) {
addSourceLine(Die, Ty->getLine(), Ty->getFile());
}

/* Byref variables, in Blocks, are declared by the programmer as "SomeType
VarName;", but the compiler creates a __Block_byref_x_VarName struct, and
gives the variable VarName either the struct, or a pointer to the struct, as
its type. This is necessary for various behind-the-scenes things the
compiler needs to do with by-reference variables in Blocks.
However, as far as the original *programmer* is concerned, the variable
should still have type 'SomeType', as originally declared.
The function getBlockByrefType dives into the __Block_byref_x_VarName
struct to find the original type of the variable, which is then assigned to
the variable's Debug Information Entry as its real type. So far, so good.
However now the debugger will expect the variable VarName to have the type
SomeType. So we need the location attribute for the variable to be an
expression that explains to the debugger how to navigate through the
pointers and struct to find the actual variable of type SomeType.
The following function does just that. We start by getting
the "normal" location for the variable. This will be the location
of either the struct __Block_byref_x_VarName or the pointer to the
struct __Block_byref_x_VarName.
The struct will look something like:
struct __Block_byref_x_VarName {
... <various fields>
struct __Block_byref_x_VarName *forwarding;
... <various other fields>
SomeType VarName;
... <maybe more fields>
};
If we are given the struct directly (as our starting point) we
need to tell the debugger to:
1). Add the offset of the forwarding field.
2). Follow that pointer to get the real __Block_byref_x_VarName
struct to use (the real one may have been copied onto the heap).
3). Add the offset for the field VarName, to find the actual variable.
If we started with a pointer to the struct, then we need to
dereference that pointer first, before the other steps.
Translating this into DWARF ops, we will need to append the following
to the current location description for the variable:
DW_OP_deref -- optional, if we start with a pointer
DW_OP_plus_uconst <forward_fld_offset>
DW_OP_deref
DW_OP_plus_uconst <varName_fld_offset>
That is what this function does. */

void DwarfUnit::addBlockByrefAddress(const DbgVariable &DV, DIE &Die,
dwarf::Attribute Attribute,
const MachineLocation &Location) {
const DIType *Ty = DV.getType();
const DIType *TmpTy = Ty;
uint16_t Tag = Ty->getTag();
bool isPointer = false;

StringRef varName = DV.getName();

if (Tag == dwarf::DW_TAG_pointer_type) {
auto *DTy = cast<DIDerivedType>(Ty);
TmpTy = resolve(DTy->getBaseType());
isPointer = true;
}

// Find the __forwarding field and the variable field in the __Block_byref
// struct.
DINodeArray Fields = cast<DICompositeType>(TmpTy)->getElements();
const DIDerivedType *varField = nullptr;
const DIDerivedType *forwardingField = nullptr;

for (unsigned i = 0, N = Fields.size(); i < N; ++i) {
auto *DT = cast<DIDerivedType>(Fields[i]);
StringRef fieldName = DT->getName();
if (fieldName == "__forwarding")
forwardingField = DT;
else if (fieldName == varName)
varField = DT;
}

// Get the offsets for the forwarding field and the variable field.
unsigned forwardingFieldOffset = forwardingField->getOffsetInBits() >> 3;
unsigned varFieldOffset = varField->getOffsetInBits() >> 2;

// Decode the original location, and use that as the start of the byref
// variable's location.
DIELoc *Loc = new (DIEValueAllocator) DIELoc;
DIEDwarfExpression DwarfExpr(*Asm, *this, *Loc);
if (Location.isIndirect())
DwarfExpr.setMemoryLocationKind();

SmallVector<uint64_t, 6> Ops;
// If we started with a pointer to the __Block_byref... struct, then
// the first thing we need to do is dereference the pointer (DW_OP_deref).
if (isPointer)
Ops.push_back(dwarf::DW_OP_deref);

// Next add the offset for the '__forwarding' field:
// DW_OP_plus_uconst ForwardingFieldOffset. Note there's no point in
// adding the offset if it's 0.
if (forwardingFieldOffset > 0) {
Ops.push_back(dwarf::DW_OP_plus_uconst);
Ops.push_back(forwardingFieldOffset);
}

// Now dereference the __forwarding field to get to the real __Block_byref
// struct: DW_OP_deref.
Ops.push_back(dwarf::DW_OP_deref);

// Now that we've got the real __Block_byref... struct, add the offset
// for the variable's field to get to the location of the actual variable:
// DW_OP_plus_uconst varFieldOffset. Again, don't add if it's 0.
if (varFieldOffset > 0) {
Ops.push_back(dwarf::DW_OP_plus_uconst);
Ops.push_back(varFieldOffset);
}

DIExpressionCursor Cursor(Ops);
const TargetRegisterInfo &TRI = *Asm->MF->getSubtarget().getRegisterInfo();
if (!DwarfExpr.addMachineRegExpression(TRI, Cursor, Location.getReg()))
return;
DwarfExpr.addExpression(std::move(Cursor));

// Now attach the location information to the DIE.
addBlock(Die, Attribute, DwarfExpr.finalize());
}

/// Return true if type encoding is unsigned.
static bool isUnsignedDIType(DwarfDebug *DD, const DIType *Ty) {
if (auto *CTy = dyn_cast<DICompositeType>(Ty)) {
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/IR/Verifier.cpp
Expand Up @@ -4534,6 +4534,14 @@ void Verifier::visitDbgIntrinsic(StringRef Kind, DbgVariableIntrinsic &DII) {
&DII, BB, F, Var, Var->getScope()->getSubprogram(), Loc,
Loc->getScope()->getSubprogram());

// This check is redundant with one in visitLocalVariable().
AssertDI(isType(Var->getRawType()), "invalid type ref", Var,
Var->getRawType());
if (auto *Type = dyn_cast_or_null<DIType>(Var->getRawType()))
if (Type->isBlockByrefStruct())
AssertDI(DII.getExpression() && DII.getExpression()->getNumElements(),
"BlockByRef variable without complex expression", Var, &DII);

verifyFnArgs(DII);
}

Expand Down
19 changes: 19 additions & 0 deletions llvm/test/Verifier/blockbyref.ll
@@ -0,0 +1,19 @@
; RUN: llvm-as -disable-output <%s 2>&1| FileCheck %s

; CHECK: BlockByRef variable without complex expression
; CHECK: warning: ignoring invalid debug info

define void @foo() {
entry:
%s = alloca i32
call void @llvm.dbg.declare(metadata i32* %s, metadata !2, metadata !DIExpression()), !dbg !DILocation(scope: !1)
ret void
}

declare void @llvm.dbg.declare(metadata, metadata, metadata)

!llvm.module.flags = !{!0}
!0 = !{i32 2, !"Debug Info Version", i32 3}
!1 = distinct !DISubprogram()
!2 = !DILocalVariable(scope: !1, type: !3)
!3 = !DICompositeType(tag: DW_TAG_structure_type, flags: DIFlagBlockByrefStruct)

0 comments on commit 609bf36

Please sign in to comment.