diff options
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 193 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h | 6 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp | 51 | ||||
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h | 30 |
4 files changed, 194 insertions, 86 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp index 8879f6b1f3e..23322704bc4 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp @@ -949,13 +949,105 @@ void CodeViewDebug::collectVariableInfoFromMFTable( } } +void CodeViewDebug::calculateRanges( + LocalVariable &Var, const DbgValueHistoryMap::InstrRanges &Ranges) { + const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo(); + + // calculate the definition ranges. + for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { + const InsnRange &Range = *I; + const MachineInstr *DVInst = Range.first; + assert(DVInst->isDebugValue() && "Invalid History entry"); + // FIXME: Find a way to represent constant variables, since they are + // relatively common. + DbgVariableLocation Location; + bool Supported = + DbgVariableLocation::extractFromMachineInstruction(Location, *DVInst); + // If not Supported, don't even look at Location because it's invalid. + if (!Supported) continue; + + // Because we cannot express DW_OP_deref in CodeView directly, + // we use a trick: we encode the type as a reference to the + // real type. + if (Var.Deref) { + // When we're encoding the type as a reference to the original type, + // we need to remove a level of indirection from incoming locations. + // E.g. [RSP+8] with DW_OP_deref becomes [RSP+8], + // and [RCX+0] without DW_OP_deref becomes RCX. + if (!Location.Deref) { + if (Location.InMemory) + Location.InMemory = false; + else + Supported = false; + } + } else if (Location.Deref) { + // We've encountered a Deref range when we had not applied the + // reference encoding. Start over using reference encoding. + Var.Deref = true; + Var.DefRanges.clear(); + calculateRanges(Var, Ranges); + return; + } + + // If we don't know how to handle this range, skip past it. + if (!Supported || Location.Register == 0 || (Location.Offset && !Location.InMemory)) + continue; + + // Handle the two cases we can handle: indirect in memory and in register. + { + LocalVarDefRange DR; + DR.CVRegister = TRI->getCodeViewRegNum(Location.Register); + DR.InMemory = Location.InMemory; + DR.DataOffset = Location.Offset; + if (Location.FragmentInfo) { + DR.IsSubfield = true; + DR.StructOffset = Location.FragmentInfo->OffsetInBits / 8; + } else { + DR.IsSubfield = false; + DR.StructOffset = 0; + } + + if (Var.DefRanges.empty() || + Var.DefRanges.back().isDifferentLocation(DR)) { + Var.DefRanges.emplace_back(std::move(DR)); + } + } + + // Compute the label range. + const MCSymbol *Begin = getLabelBeforeInsn(Range.first); + const MCSymbol *End = getLabelAfterInsn(Range.second); + if (!End) { + // 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); + const DIExpression *DIExpr = DVInst->getDebugExpression(); + while (J != E && + !fragmentsOverlap(DIExpr, J->first->getDebugExpression())) + ++J; + if (J != E) + End = getLabelBeforeInsn(J->first); + else + End = Asm->getFunctionEnd(); + } + + // If the last range end is our begin, just extend the last range. + // Otherwise make a new range. + SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &R = + Var.DefRanges.back().Ranges; + if (!R.empty() && R.back().second == Begin) + R.back().second = End; + else + R.emplace_back(Begin, End); + + // FIXME: Do more range combining. + } +} + void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { DenseSet<InlinedVariable> Processed; // Grab the variable info that was squirreled away in the MMI side-table. collectVariableInfoFromMFTable(Processed); - const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo(); - for (const auto &I : DbgValues) { InlinedVariable IV = I.first; if (Processed.count(IV)) @@ -978,89 +1070,7 @@ void CodeViewDebug::collectVariableInfo(const DISubprogram *SP) { LocalVariable Var; Var.DIVar = DIVar; - // Calculate the definition ranges. - for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { - const InsnRange &Range = *I; - const MachineInstr *DVInst = Range.first; - assert(DVInst->isDebugValue() && "Invalid History entry"); - const DIExpression *DIExpr = DVInst->getDebugExpression(); - bool InMemory = DVInst->getOperand(1).isImm(); - bool IsSubfield = false; - unsigned StructOffset = 0; - // Recognize a +Offset expression. - int Offset = 0; - DIExpressionCursor Ops(DIExpr); - auto Op = Ops.peek(); - if (Op && Op->getOp() == dwarf::DW_OP_plus_uconst) { - Offset = Op->getArg(0); - Ops.take(); - } - - // Handle fragments. - auto Fragment = Ops.getFragmentInfo(); - if (Fragment) { - IsSubfield = true; - StructOffset = Fragment->OffsetInBits / 8; - } - // Ignore unrecognized exprs. - if (Ops.peek() && Ops.peek()->getOp() != dwarf::DW_OP_LLVM_fragment) - continue; - if (!InMemory && Offset) - continue; - - // Bail if operand 0 is not a valid register. This means the variable is a - // simple constant, or is described by a complex expression. - // FIXME: Find a way to represent constant variables, since they are - // relatively common. - unsigned Reg = - DVInst->getOperand(0).isReg() ? DVInst->getOperand(0).getReg() : 0; - if (Reg == 0) - continue; - - // Handle the two cases we can handle: indirect in memory and in register. - unsigned CVReg = TRI->getCodeViewRegNum(Reg); - { - 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(DR)) { - Var.DefRanges.emplace_back(std::move(DR)); - } - } - - // Compute the label range. - const MCSymbol *Begin = getLabelBeforeInsn(Range.first); - const MCSymbol *End = getLabelAfterInsn(Range.second); - if (!End) { - // 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 && - !fragmentsOverlap(DIExpr, J->first->getDebugExpression())) - ++J; - if (J != E) - End = getLabelBeforeInsn(J->first); - else - End = Asm->getFunctionEnd(); - } - - // If the last range end is our begin, just extend the last range. - // Otherwise make a new range. - SmallVectorImpl<std::pair<const MCSymbol *, const MCSymbol *>> &Ranges = - Var.DefRanges.back().Ranges; - if (!Ranges.empty() && Ranges.back().second == Begin) - Ranges.back().second = End; - else - Ranges.emplace_back(Begin, End); - - // FIXME: Do more range combining. - } - + calculateRanges(Var, Ranges); recordLocalVariable(std::move(Var), InlinedAt); } } @@ -1987,6 +1997,16 @@ TypeIndex CodeViewDebug::getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef) { return recordTypeIndexForDINode(Ty, TI, ClassTy); } +TypeIndex CodeViewDebug::getTypeIndexForReferenceTo(DITypeRef TypeRef) { + DIType *Ty = TypeRef.resolve(); + PointerRecord PR(getTypeIndex(Ty), + getPointerSizeInBytes() == 8 ? PointerKind::Near64 + : PointerKind::Near32, + PointerMode::LValueReference, PointerOptions::None, + Ty->getSizeInBits() / 8); + return TypeTable.writeKnownType(PR); +} + TypeIndex CodeViewDebug::getCompleteTypeIndex(DITypeRef TypeRef) { const DIType *Ty = TypeRef.resolve(); @@ -2094,7 +2114,8 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) { Flags |= LocalSymFlags::IsOptimizedOut; OS.AddComment("TypeIndex"); - TypeIndex TI = getCompleteTypeIndex(Var.DIVar->getType()); + TypeIndex TI = Var.Deref ? getTypeIndexForReferenceTo(Var.DIVar->getType()) + : getCompleteTypeIndex(Var.DIVar->getType()); OS.EmitIntValue(TI.getIndex(), 4); OS.AddComment("Flags"); OS.EmitIntValue(static_cast<uint16_t>(Flags), 2); diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h index 91f691c635e..4345bb4d1c2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h +++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h @@ -94,6 +94,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { struct LocalVariable { const DILocalVariable *DIVar = nullptr; SmallVector<LocalVarDefRange, 1> DefRanges; + bool Deref = false; }; struct InlineSite { @@ -147,6 +148,9 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { codeview::TypeIndex getFuncIdForSubprogram(const DISubprogram *SP); + void calculateRanges(LocalVariable &Var, + const DbgValueHistoryMap::InstrRanges &Ranges); + static void collectInlineSiteChildren(SmallVectorImpl<unsigned> &Children, const FunctionInfo &FI, const InlineSite &Site); @@ -259,6 +263,8 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase { codeview::TypeIndex getTypeIndex(DITypeRef TypeRef, DITypeRef ClassTyRef = DITypeRef()); + codeview::TypeIndex getTypeIndexForReferenceTo(DITypeRef TypeRef); + codeview::TypeIndex getMemberFunctionType(const DISubprogram *SP, const DICompositeType *Class); diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp index 0971c594220..4f647de1ed2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp @@ -23,6 +23,57 @@ using namespace llvm; +bool DbgVariableLocation::extractFromMachineInstruction( + DbgVariableLocation &Location, const MachineInstr &Instruction) { + if (!Instruction.isDebugValue()) + return false; + if (!Instruction.getOperand(0).isReg()) + return false; + Location.Register = Instruction.getOperand(0).getReg(); + Location.InMemory = Instruction.getOperand(1).isImm(); + Location.Deref = false; + Location.FragmentInfo.reset(); + // We only handle expressions generated by DIExpression::appendOffset, + // which doesn't require a full stack machine. + int64_t Offset = 0; + const DIExpression *DIExpr = Instruction.getDebugExpression(); + auto Op = DIExpr->expr_op_begin(); + while (Op != DIExpr->expr_op_end()) { + switch (Op->getOp()) { + case dwarf::DW_OP_constu: { + int Value = Op->getArg(0); + ++Op; + if (Op != DIExpr->expr_op_end()) { + switch (Op->getOp()) { + case dwarf::DW_OP_minus: + Offset -= Value; + break; + case dwarf::DW_OP_plus: + Offset += Value; + default: + continue; + } + } + } break; + case dwarf::DW_OP_plus_uconst: + Offset += Op->getArg(0); + break; + case dwarf::DW_OP_LLVM_fragment: + Location.FragmentInfo = {Op->getArg(1), Op->getArg(0)}; + break; + case dwarf::DW_OP_deref: + Location.Deref = true; + break; + default: + return false; + } + ++Op; + } + + Location.Offset = Offset; + return true; +} + DebugHandlerBase::DebugHandlerBase(AsmPrinter *A) : Asm(A), MMI(Asm->MMI) {} // Each LexicalScope has first instruction and last instruction to mark diff --git a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h index 659a921e1fc..670300cd7a6 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h +++ b/llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h @@ -17,14 +17,44 @@ #include "AsmPrinterHandler.h" #include "DbgValueHistoryCalculator.h" +#include "llvm/ADT/Optional.h" #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/IR/DebugInfoMetadata.h" namespace llvm { class AsmPrinter; +class MachineInstr; class MachineModuleInfo; +/// Represents the location at which a variable is stored. +struct DbgVariableLocation { + /// Offset relative to base register. + int64_t Offset; + + /// Base register. + unsigned Register; + + /// If false, Register is the location. If true, + /// Register+Offset point at the location. + unsigned InMemory : 1; + + /// If false, the location holds the variable's value. + /// If true, the location holds the variable's address. + unsigned Deref : 1; + + /// Present if the location is part of a larger variable. + llvm::Optional<llvm::DIExpression::FragmentInfo> FragmentInfo; + + /// Extract a VariableLocation from a MachineInstr. The struct passed in as + /// Location is populated. The MachineInstr must be a debug value + /// instruction. + /// @return true if successful and false if not. + static bool extractFromMachineInstruction(DbgVariableLocation &Location, + const MachineInstr &Instruction); +}; + /// Base class for debug information backends. Common functionality related to /// tracking which variables and scopes are alive at a given PC live here. class DebugHandlerBase : public AsmPrinterHandler { |