Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfCompileUnit.cpp @@ -978,8 +978,6 @@ "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); } Index: llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ llvm/trunk/lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -427,138 +427,6 @@ 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 { - ... - struct __Block_byref_x_VarName *forwarding; - ... - SomeType VarName; - ... - }; - - 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 - DW_OP_deref - DW_OP_plus_uconst - - 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(Ty); - TmpTy = resolve(DTy->getBaseType()); - isPointer = true; - } - - // Find the __forwarding field and the variable field in the __Block_byref - // struct. - DINodeArray Fields = cast(TmpTy)->getElements(); - const DIDerivedType *varField = nullptr; - const DIDerivedType *forwardingField = nullptr; - - for (unsigned i = 0, N = Fields.size(); i < N; ++i) { - auto *DT = cast(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 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(Ty)) { Index: llvm/trunk/lib/IR/Verifier.cpp =================================================================== --- llvm/trunk/lib/IR/Verifier.cpp +++ llvm/trunk/lib/IR/Verifier.cpp @@ -4534,6 +4534,14 @@ &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(Var->getRawType())) + if (Type->isBlockByrefStruct()) + AssertDI(DII.getExpression() && DII.getExpression()->getNumElements(), + "BlockByRef variable without complex expression", Var, &DII); + verifyFnArgs(DII); } Index: llvm/trunk/test/Verifier/blockbyref.ll =================================================================== --- llvm/trunk/test/Verifier/blockbyref.ll +++ llvm/trunk/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)