Index: docs/SourceLevelDebugging.rst =================================================================== --- docs/SourceLevelDebugging.rst +++ docs/SourceLevelDebugging.rst @@ -589,6 +589,12 @@ Name the source variable name. Context and line indicate where the variable was defined. Type descriptor defines the declared type of the variable. +The ``OpPiece`` operator is used for (typically larger aggregate) +variables that are fragmented across several locations. It takes two +i32 arguments, an offset and a size in bytes to describe which piece +of the variable is at this location. + + .. _format_common_intrinsics: Debugger intrinsic functions Index: include/llvm/CodeGen/AsmPrinter.h =================================================================== --- include/llvm/CodeGen/AsmPrinter.h +++ include/llvm/CodeGen/AsmPrinter.h @@ -405,6 +405,13 @@ /// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified. virtual unsigned getISAEncoding() { return 0; } + /// Emit a dwarf register operation for describing + /// - a small value occupying only part of a register or + /// - a register representing only part of a value. + void EmitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits, + unsigned OffsetInBits = 0) const; + + /// \brief Emit a partial DWARF register operation. /// \param MLoc the register /// \param PieceSize size and @@ -421,7 +428,7 @@ unsigned PieceSize = 0, unsigned PieceOffset = 0) const; - /// Emit dwarf register operation. + /// EmitDwarfRegOp - Emit a dwarf register operation. /// \param Indirect whether this is a register-indirect address virtual void EmitDwarfRegOp(ByteStreamer &BS, const MachineLocation &MLoc, bool Indirect) const; Index: include/llvm/IR/DIBuilder.h =================================================================== --- include/llvm/IR/DIBuilder.h +++ include/llvm/IR/DIBuilder.h @@ -85,7 +85,7 @@ public: explicit DIBuilder(Module &M); - enum ComplexAddrKind { OpPlus=1, OpDeref }; + enum ComplexAddrKind { OpPlus=1, OpDeref, OpPiece }; enum DebugEmissionKind { FullDebug=1, LineTablesOnly }; /// finalize - Construct any deferred debug info descriptors. @@ -561,6 +561,16 @@ DITypeRef Ty, ArrayRef Addr, unsigned ArgNo = 0); + /// createVariablePiece - Create a descriptor to describe one part + /// of aggregate variable that is fragmented across multiple Values. + /// + /// @param Variable Variable that is partially represented by this. + /// @param OffsetInBytes Offset of the piece in bytes. + /// @param SizeInBytes Size of the piece in bytes. + DIVariable createVariablePiece(DIVariable Variable, + unsigned OffsetInBytes, + unsigned SizeInBytes); + /// createFunction - Create a new descriptor for the specified subprogram. /// See comments in DISubprogram for descriptions of these fields. /// @param Scope Function scope. Index: include/llvm/IR/DebugInfo.h =================================================================== --- include/llvm/IR/DebugInfo.h +++ include/llvm/IR/DebugInfo.h @@ -754,6 +754,17 @@ /// information for an inlined function arguments. bool isInlinedFnArgument(const Function *CurFn); + /// isVariablePiece - Return whether this is a piece of an aggregate + /// variable. + bool isVariablePiece() const; + /// getPieceOffset - Return the offset of this piece in bytes. + uint64_t getPieceOffset() const; + /// getPieceSize - Return the size of this piece in bytes. + uint64_t getPieceSize() const; + + /// Return the size reported by the variable's type. + unsigned getSizeInBits(const DITypeIdentifierMap &Map); + void printExtendedName(raw_ostream &OS) const; }; @@ -871,6 +882,9 @@ /// cleanseInlinedVariable - Remove inlined scope from the variable. DIVariable cleanseInlinedVariable(MDNode *DV, LLVMContext &VMContext); +/// getEntireVariable - Remove OpPiece exprs from the variable. +DIVariable getEntireVariable(DIVariable DV); + /// Construct DITypeIdentifierMap by going through retained types of each CU. DITypeIdentifierMap generateDITypeIdentifierMap(const NamedMDNode *CU_Nodes); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -641,7 +641,11 @@ if (!Name.empty()) OS << Name << ":"; } - OS << V.getName() << " <- "; + OS << V.getName(); + if (V.isVariablePiece()) + OS << " [piece offset=" << V.getPieceOffset() + << " size="<getOperand(0).isReg() && MI->getOperand(1).isImm(); Index: lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -214,11 +214,8 @@ Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref"); } -/// Emit a dwarf register operation for describing -/// - a small value occupying only part of a register or -/// - a small register representing only part of a value. -static void emitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits, - unsigned OffsetInBits) { +void AsmPrinter::EmitDwarfOpPiece(ByteStreamer &Streamer, unsigned SizeInBits, + unsigned OffsetInBits) const { assert(SizeInBits > 0 && "zero-sized piece"); unsigned SizeOfByte = 8; if (OffsetInBits > 0 || SizeInBits % SizeOfByte) { @@ -255,7 +252,7 @@ // If this is a valid register number, emit it. if (Reg >= 0) { emitDwarfRegOp(Streamer, Reg); - emitDwarfOpPiece(Streamer, PieceSizeInBits, PieceOffsetInBits); + EmitDwarfOpPiece(Streamer, PieceSizeInBits, PieceOffsetInBits); return; } @@ -270,13 +267,13 @@ OutStreamer.AddComment("super-register"); emitDwarfRegOp(Streamer, Reg); if (PieceOffsetInBits == Offset) { - emitDwarfOpPiece(Streamer, Size, Offset); + EmitDwarfOpPiece(Streamer, Size, Offset); } else { // If this is part of a variable in a sub-register at a // non-zero offset, we need to manually shift the value into // place, since the DW_OP_piece describes the part of the // variable, not the position of the subregister. - emitDwarfOpPiece(Streamer, Size, PieceOffsetInBits); + EmitDwarfOpPiece(Streamer, Size, PieceOffsetInBits); if (Offset) emitDwarfOpShr(Streamer, Offset); } @@ -312,7 +309,7 @@ if (Reg >= 0 && Intersection.any()) { OutStreamer.AddComment("sub-register"); emitDwarfRegOp(Streamer, Reg); - emitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset); + EmitDwarfOpPiece(Streamer, Size, Offset == CurPos ? 0 : Offset); CurPos = Offset + Size; // Mark it as emitted. Index: lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h =================================================================== --- lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h +++ lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.h @@ -28,9 +28,11 @@ // range. If end is not specified, location is valid until the start // instruction of the next instruction range, or until the end of the // function. +public: typedef std::pair InstrRange; typedef SmallVector InstrRanges; typedef MapVector InstrRangesMap; +private: InstrRangesMap VarInstrRanges; public: Index: lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp +++ lib/CodeGen/AsmPrinter/DbgValueHistoryCalculator.cpp @@ -11,6 +11,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/Support/Debug.h" #include "llvm/Target/TargetRegisterInfo.h" #include @@ -36,7 +37,7 @@ const MachineInstr &MI) { // Instruction range should start with a DBG_VALUE instruction for the // variable. - assert(MI.isDebugValue() && MI.getDebugVariable() == Var); + assert(MI.isDebugValue() && getEntireVariable(MI.getDebugVariable()) == Var); auto &Ranges = VarInstrRanges[Var]; if (!Ranges.empty() && Ranges.back().second == nullptr && Ranges.back().first->isIdenticalTo(&MI)) { @@ -182,7 +183,10 @@ } assert(MI.getNumOperands() > 1 && "Invalid DBG_VALUE instruction!"); - const MDNode *Var = MI.getDebugVariable(); + // Use the base variable (without any DW_OP_piece expressions) + // as index into History. The full variables including the + // piece expressions are attached to the MI. + DIVariable Var = getEntireVariable(MI.getDebugVariable()); if (unsigned PrevReg = Result.getRegisterForVar(Var)) dropRegDescribedVar(RegVars, PrevReg, Var); Index: lib/CodeGen/AsmPrinter/DebugLocEntry.h =================================================================== --- lib/CodeGen/AsmPrinter/DebugLocEntry.h +++ lib/CodeGen/AsmPrinter/DebugLocEntry.h @@ -10,6 +10,7 @@ #ifndef CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H__ #define CODEGEN_ASMPRINTER_DEBUGLOCENTRY_H__ #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/MC/MachineLocation.h" #include "llvm/MC/MCSymbol.h" @@ -106,17 +107,34 @@ /// share the same Loc/Constant and if Next immediately follows this /// Entry. bool Merge(const DebugLocEntry &Next) { + // If this and Next are describing pieces of the same variable + // merge them by appending next's values to the current list of values. + if (Begin == Next.Begin && Values.size() > 0 && Next.Values.size() > 0) { + DIVariable Var(Values[0].Variable); + DIVariable NextVar(Next.Values[0].Variable); + if (Var.getName() == NextVar.getName() && + Var.isVariablePiece() && NextVar.isVariablePiece()) { + Values.append(Next.Values.begin(), Next.Values.end()); + End = Next.End; + return true; + } + } if ((End == Next.Begin && Values == Next.Values)) { End = Next.End; return true; } return false; } + const MCSymbol *getBeginSym() const { return Begin; } const MCSymbol *getEndSym() const { return End; } const DwarfCompileUnit *getCU() const { return Unit; } const ArrayRef getValues() const { return Values; } - void addValue(Value Val) { Values.push_back(Val); } + void addValue(Value Val) { + assert(DIVariable(Val.Variable).isVariablePiece() && + "multi-value DebugLocEntries must be pieces"); + Values.push_back(Val); + } }; } Index: lib/CodeGen/AsmPrinter/DwarfDebug.h =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.h +++ lib/CodeGen/AsmPrinter/DwarfDebug.h @@ -535,6 +535,12 @@ /// \brief Populate LexicalScope entries with variables' info. void collectVariableInfo(SmallPtrSet &ProcessedVars); + /// \brief Build the location list for all DBG_VALUEs in the + /// function that describe the same variable. + void buildLocationList(SmallVectorImpl &DebugLoc, + const DbgValueHistoryMap::InstrRanges &Ranges, + DwarfCompileUnit *TheCU); + /// \brief Collect variable information from the side table maintained /// by MMI. void collectVariableInfoFromMMITable(SmallPtrSet &P); @@ -642,6 +648,13 @@ /// \brief Emit an entry for the debug loc section. This can be used to /// handle an entry that's going to be emitted into the debug loc section. void emitDebugLocEntry(ByteStreamer &Streamer, const DebugLocEntry &Entry); + /// \brief emit a single value for the debug loc section. + void emitDebugLocValue(ByteStreamer &Streamer, + const DebugLocEntry::Value &Value); + /// Emits an optimal (=sorted) sequence of DW_OP_pieces. + void emitLocPieces(ByteStreamer &Streamer, + const DITypeIdentifierMap &Map, + ArrayRef Values); /// Emit the location for a debug loc entry, including the size header. void emitDebugLocEntryLocation(const DebugLocEntry &Entry); Index: lib/CodeGen/AsmPrinter/DwarfDebug.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfDebug.cpp +++ lib/CodeGen/AsmPrinter/DwarfDebug.cpp @@ -1192,6 +1192,103 @@ llvm_unreachable("Unexpected 3 operand DBG_VALUE instruction!"); } +/// Determine whether two variable pieces overlap. +static bool piecesOverlap(DIVariable P1, DIVariable P2) { + if (!P1.isVariablePiece() || !P2.isVariablePiece()) + return true; + unsigned l1 = P1.getPieceOffset(); + unsigned l2 = P2.getPieceOffset(); + unsigned r1 = l1 + P1.getPieceSize(); + unsigned r2 = l2 + P2.getPieceSize(); + // True where [l1,r1[ and [r1,r2[ overlap. + return (l1 < r2) && (l2 < r1); +} + +/// Build the location list for all DBG_VALUEs in the function that +/// describe the same variable. If the ranges of several independent +/// pieces of the same variable overlap partially, split them up and +/// combine the ranges. The resulting DebugLocEntries are will have +/// strict monotonically increasing begin addresses and will never +/// overlap. +// +// Input: +// +// Ranges History [var, loc, piece ofs size] +// 0 | [x, (reg0, piece 0, 32)] +// 1 | | [x, (reg1, piece 32, 32)] <- IsPieceOfPrevEntry +// 2 | | ... +// 3 | [clobber reg0] +// 4 [x, (mem, piece 0, 64)] <- overlapping with both previous pieces of x. +// +// Output: +// +// [0-1] [x, (reg0, piece 0, 32)] +// [1-3] [x, (reg0, piece 0, 32), (reg1, piece 32, 32)] +// [3-4] [x, (reg1, piece 32, 32)] +// [4- ] [x, (mem, piece 0, 64)] +void DwarfDebug:: +buildLocationList(SmallVectorImpl &DebugLoc, + const DbgValueHistoryMap::InstrRanges &Ranges, + DwarfCompileUnit *TheCU) { + typedef std::pair Range; + SmallVector OpenRanges; + + for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { + const MachineInstr *Begin = I->first; + const MachineInstr *End = I->second; + assert(Begin->isDebugValue() && "Invalid History entry"); + + + // Check if a variable is unaccessible in this range. + if (!Begin->isDebugValue() || + (Begin->getNumOperands() > 1 && Begin->getOperand(0).isReg() && + !Begin->getOperand(0).getReg())) { + OpenRanges.clear(); + continue; + } + + // If this piece overlaps with any open ranges, truncate them. + DIVariable DIVar = Begin->getDebugVariable(); + auto Last = std::remove_if(OpenRanges.begin(), OpenRanges.end(), [&](Range R){ + return piecesOverlap(DIVar, R.first); + }); + OpenRanges.erase(Last, OpenRanges.end()); + + + const MCSymbol *StartLabel = getLabelBeforeInsn(Begin); + assert(StartLabel && "Forgot label before DBG_VALUE starting a range!"); + + const MCSymbol *EndLabel; + if (End != nullptr) + EndLabel = getLabelAfterInsn(End); + else if (std::next(I) == Ranges.end()) + EndLabel = FunctionEndSym; + else + EndLabel = getLabelBeforeInsn(std::next(I)->first); + assert(EndLabel && "Forgot label after instruction ending a range!"); + + DEBUG(dbgs() << "DotDebugLoc: " << *Begin << "\n"); + + auto Value = getDebugLocValue(Begin); + DebugLocEntry Loc(StartLabel, EndLabel, Value, TheCU); + if (DebugLoc.empty() || !DebugLoc.back().Merge(Loc)) { + // Add all values from still valid non-overlapping pieces. + for (auto Range : OpenRanges) + Loc.addValue(Range.second); + DebugLoc.push_back(std::move(Loc)); + } + // Add this value to the list of open ranges. + if (DIVar.isVariablePiece()) + OpenRanges.push_back({DIVar, Value}); + + DEBUG(dbgs() << "Values:\n"; + for (auto Value : DebugLoc.back().getValues()) + Value.getVariable()->dump(); + dbgs() << "-----\n"); + } +} + + // Find variables for each lexical scope. void DwarfDebug::collectVariableInfo(SmallPtrSet &Processed) { @@ -1225,7 +1322,7 @@ if (!Scope) continue; - Processed.insert(DV); + Processed.insert(getEntireVariable(DV)); const MachineInstr *MInsn = Ranges.front().first; assert(MInsn->isDebugValue() && "History must begin with debug value"); ensureAbstractVariableIsCreatedIfScoped(DV, Scope->getScopeNode()); @@ -1244,38 +1341,9 @@ DebugLocList &LocList = DotDebugLocEntries.back(); LocList.Label = Asm->GetTempSymbol("debug_loc", DotDebugLocEntries.size() - 1); - SmallVector &DebugLoc = LocList.List; - for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - const MachineInstr *Begin = I->first; - const MachineInstr *End = I->second; - assert(Begin->isDebugValue() && "Invalid History entry"); - - // Check if a variable is unaccessible in this range. - if (Begin->getNumOperands() > 1 && Begin->getOperand(0).isReg() && - !Begin->getOperand(0).getReg()) - continue; - DEBUG(dbgs() << "DotDebugLoc Pair:\n" << "\t" << *Begin); - if (End != nullptr) - DEBUG(dbgs() << "\t" << *End); - else - DEBUG(dbgs() << "\tNULL\n"); - - const MCSymbol *StartLabel = getLabelBeforeInsn(Begin); - assert(StartLabel && "Forgot label before DBG_VALUE starting a range!"); - - const MCSymbol *EndLabel; - if (End != nullptr) - EndLabel = getLabelAfterInsn(End); - else if (std::next(I) == Ranges.end()) - EndLabel = FunctionEndSym; - else - EndLabel = getLabelBeforeInsn(std::next(I)->first); - assert(EndLabel && "Forgot label after instruction ending a range!"); - - DebugLocEntry Loc(StartLabel, EndLabel, getDebugLocValue(Begin), TheCU); - if (DebugLoc.empty() || !DebugLoc.back().Merge(Loc)) - DebugLoc.push_back(std::move(Loc)); - } + + // Build the location list for this variable. + buildLocationList(LocList.List, Ranges, TheCU); } // Collect info for variables that were optimized out. @@ -1474,10 +1542,25 @@ // The first mention of a function argument gets the FunctionBeginSym // label, so arguments are visible when breaking at function entry. - DIVariable DV(I.first); + DIVariable DV(Ranges.front().first->getDebugVariable()); if (DV.isVariable() && DV.getTag() == dwarf::DW_TAG_arg_variable && - getDISubprogram(DV.getContext()).describes(MF->getFunction())) - LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym; + getDISubprogram(DV.getContext()).describes(MF->getFunction())) { + if (!DV.isVariablePiece()) + LabelsBeforeInsn[Ranges.front().first] = FunctionBeginSym; + else { + // Mark all non-overlapping initial pieces. + for (auto I = Ranges.begin(); I != Ranges.end(); ++I) { + DIVariable Piece = I->first->getDebugVariable(); + if (std::all_of(Ranges.begin(), I, + [&](DbgValueHistoryMap::InstrRange Pred){ + return !piecesOverlap(Piece, Pred.first->getDebugVariable()); + })) + LabelsBeforeInsn[I->first] = FunctionBeginSym; + else + break; + } + } + } for (const auto &Range : Ranges) { requestLabelBeforeInsn(Range.first); @@ -1960,12 +2043,79 @@ Holder.emitStrings(Asm->getObjFileLowering().getDwarfStrSection()); } +/// Emits an optimal (=sorted) sequence of DW_OP_pieces. +void DwarfDebug::emitLocPieces(ByteStreamer &Streamer, + const DITypeIdentifierMap &Map, + ArrayRef Values) { + typedef DebugLocEntry::Value Piece; + SmallVector Pieces(Values.begin(), Values.end()); + assert(std::all_of(Pieces.begin(), Pieces.end(), [](Piece &P) { + return DIVariable(P.getVariable()).isVariablePiece(); + }) && "all values are expected to be pieces"); + + // Sort the pieces so they can be emitted using DW_OP_piece. + std::sort(Pieces.begin(), Pieces.end(), [](const Piece &A, const Piece &B) { + DIVariable VarA(A.getVariable()); + DIVariable VarB(B.getVariable()); + return VarA.getPieceOffset() < VarB.getPieceOffset(); + }); + // Remove any duplicate entries by dropping all but the first. + Pieces.erase(std::unique(Pieces.begin(), Pieces.end(), + [] (const Piece &A,const Piece &B){ + return A.getVariable() == B.getVariable(); + }), Pieces.end()); + + unsigned Offset = 0; + for (auto Piece : Pieces) { + DIVariable Var(Piece.getVariable()); + unsigned PieceOffset = Var.getPieceOffset(); + unsigned PieceSize = Var.getPieceSize(); + assert(Offset <= PieceOffset && "overlapping pieces in DebugLocEntry"); + if (Offset < PieceOffset) { + // The DWARF spec seriously mandates pieces with no locations for gaps. + Asm->EmitDwarfOpPiece(Streamer, (PieceOffset-Offset)*8); + Offset += PieceOffset-Offset; + } + + Offset += PieceSize; + + // Assuming 8 bits per byte. + assert(!Var.isIndirect() && "indirect address for piece"); +#ifndef NDEBUG + unsigned VarSize = Var.getSizeInBits(Map); + assert(PieceSize+PieceOffset <= VarSize/8 + && "piece is larger than or outside of variable"); + assert(PieceSize*8 != VarSize + && "piece covers entire variable"); +#endif + if (Piece.isLocation() && Piece.getLoc().isReg()) + Asm->EmitDwarfRegOpPiece(Streamer, + Piece.getLoc(), + PieceSize*8); + else { + emitDebugLocValue(Streamer, Piece); + Asm->EmitDwarfOpPiece(Streamer, PieceSize*8); + } + } +} + + void DwarfDebug::emitDebugLocEntry(ByteStreamer &Streamer, const DebugLocEntry &Entry) { - assert(Entry.getValues().size() == 1 && - "multi-value entries are not supported yet."); const DebugLocEntry::Value Value = Entry.getValues()[0]; DIVariable DV(Value.getVariable()); + if (DV.isVariablePiece()) + // Emit all pieces that belong to the same variable and range. + return emitLocPieces(Streamer, TypeIdentifierMap, Entry.getValues()); + + assert(Entry.getValues().size() == 1 && "only pieces may have >1 value"); + emitDebugLocValue(Streamer, Value); +} + +void DwarfDebug::emitDebugLocValue(ByteStreamer &Streamer, + const DebugLocEntry::Value &Value) { + DIVariable DV(Value.getVariable()); + // Regular entry. if (Value.isInt()) { DIBasicType BTy(resolve(DV.getType())); if (BTy.Verify() && (BTy.getEncoding() == dwarf::DW_ATE_signed || @@ -2012,6 +2162,9 @@ } else if (Element == DIBuilder::OpDeref) { if (!Loc.isReg()) Streamer.EmitInt8(dwarf::DW_OP_deref, "DW_OP_deref"); + } else if (Element == DIBuilder::OpPiece) { + i += 3; + // handled in emitDebugLocEntry. } else llvm_unreachable("unknown Opcode found in complex address"); } Index: lib/CodeGen/AsmPrinter/DwarfUnit.cpp =================================================================== --- lib/CodeGen/AsmPrinter/DwarfUnit.cpp +++ lib/CodeGen/AsmPrinter/DwarfUnit.cpp @@ -602,6 +602,11 @@ } else if (Element == DIBuilder::OpDeref) { if (!Location.isReg()) addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_deref); + } else if (Element == DIBuilder::OpPiece) { + unsigned SizeOfByte = 8; + addUInt(*Loc, dwarf::DW_FORM_data1, dwarf::DW_OP_bit_piece); + addUInt(*Loc, dwarf::DW_FORM_udata, DV.getAddrElement(++i)*SizeOfByte); + addUInt(*Loc, dwarf::DW_FORM_udata, DV.getAddrElement(++i)*SizeOfByte); } else llvm_unreachable("unknown DIBuilder Opcode"); } Index: lib/IR/DebugInfo.cpp =================================================================== --- lib/IR/DebugInfo.cpp +++ lib/IR/DebugInfo.cpp @@ -12,13 +12,14 @@ // //===----------------------------------------------------------------------===// -#include "llvm/IR/DebugInfo.h" #include "LLVMContextImpl.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" @@ -151,6 +152,36 @@ /// getInlinedAt - If this variable is inlined then return inline location. MDNode *DIVariable::getInlinedAt() const { return getNodeField(DbgNode, 7); } +bool DIVariable::isVariablePiece() const { + return hasComplexAddress() && getAddrElement(0) == DIBuilder::OpPiece; +} + +uint64_t DIVariable::getPieceOffset() const { + assert(isVariablePiece()); + return getAddrElement(1); +} + +uint64_t DIVariable::getPieceSize() const { + assert(isVariablePiece()); + return getAddrElement(2); +} + +/// Return the size reported by the variable's type. +unsigned DIVariable::getSizeInBits(const DITypeIdentifierMap &Map) { + DIType Ty = getType().resolve(Map); + // Follow derived types until we reach a type that + // reports back a size. + while (Ty.isDerivedType() && !Ty.isCompositeType()) { + DIDerivedType DT(&*Ty); + Ty = DT.getTypeDerivedFrom().resolve(Map); + } + assert(Ty.getSizeInBits() && "type with size 0"); + return Ty.getSizeInBits(); +} + + + + //===----------------------------------------------------------------------===// // Predicates //===----------------------------------------------------------------------===// @@ -922,6 +953,20 @@ return DIVariable(MDNode::get(VMContext, Elts)); } + +/// getEntireVariable - Remove OpPiece exprs from the variable. +DIVariable llvm::getEntireVariable(DIVariable DV) { + if (!DV.isVariablePiece()) + return DV; + + SmallVector Elts; + for (unsigned i = 0; i < 8; ++i) + Elts.push_back(DV->getOperand(i)); + + return DIVariable(MDNode::get(DV->getContext(), Elts)); +} + + /// getDISubprogram - Find subprogram that is enclosing this scope. DISubprogram llvm::getDISubprogram(const MDNode *Scope) { DIDescriptor D(Scope); @@ -1411,6 +1456,10 @@ OS << " [" << Res << ']'; OS << " [line " << getLineNumber() << ']'; + + if (isVariablePiece()) + OS << " [piece, size " << getPieceSize() + << ", offset " << getPieceOffset() << ']'; } void DIObjCProperty::printInternal(raw_ostream &OS) const {