summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp193
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.h6
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.cpp51
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/DebugHandlerBase.h30
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 {
OpenPOWER on IntegriCloud