mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-05 02:07:56 +00:00
[codeview] Generalize DIExpression parsing to handle load chains
Summary: Hopefully this also clarifies exactly when and why we're rewriting certiain S_LOCALs using reference types: We're using the reference type to stand in for a zero-offset load. Reviewers: inglorion Subscribers: llvm-commits, hiraditya Differential Revision: https://reviews.llvm.org/D37309 llvm-svn: 312247
This commit is contained in:
parent
f0e1949722
commit
1e6362c860
@ -949,11 +949,19 @@ void CodeViewDebug::collectVariableInfoFromMFTable(
|
||||
}
|
||||
}
|
||||
|
||||
static bool canUseReferenceType(const DbgVariableLocation &Loc) {
|
||||
return !Loc.LoadChain.empty() && Loc.LoadChain.back() == 0;
|
||||
}
|
||||
|
||||
static bool needsReferenceType(const DbgVariableLocation &Loc) {
|
||||
return Loc.LoadChain.size() == 2 && Loc.LoadChain.back() == 0;
|
||||
}
|
||||
|
||||
void CodeViewDebug::calculateRanges(
|
||||
LocalVariable &Var, const DbgValueHistoryMap::InstrRanges &Ranges) {
|
||||
const TargetRegisterInfo *TRI = Asm->MF->getSubtarget().getRegisterInfo();
|
||||
|
||||
// calculate the definition ranges.
|
||||
// Calculate the definition ranges.
|
||||
for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
|
||||
const InsnRange &Range = *I;
|
||||
const MachineInstr *DVInst = Range.first;
|
||||
@ -965,39 +973,37 @@ void CodeViewDebug::calculateRanges(
|
||||
if (!Location)
|
||||
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
|
||||
continue;
|
||||
}
|
||||
} 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;
|
||||
// CodeView can only express variables in register and variables in memory
|
||||
// at a constant offset from a register. However, for variables passed
|
||||
// indirectly by pointer, it is common for that pointer to be spilled to a
|
||||
// stack location. For the special case of one offseted load followed by a
|
||||
// zero offset load (a pointer spilled to the stack), we change the type of
|
||||
// the local variable from a value type to a reference type. This tricks the
|
||||
// debugger into doing the load for us.
|
||||
if (Var.UseReferenceType) {
|
||||
// We're using a reference type. Drop the last zero offset load.
|
||||
if (canUseReferenceType(*Location))
|
||||
Location->LoadChain.pop_back();
|
||||
else
|
||||
continue;
|
||||
} else if (needsReferenceType(*Location)) {
|
||||
// This location can't be expressed without switching to a reference type.
|
||||
// Start over using that.
|
||||
Var.UseReferenceType = true;
|
||||
Var.DefRanges.clear();
|
||||
calculateRanges(Var, Ranges);
|
||||
return;
|
||||
}
|
||||
|
||||
// If we don't know how to handle this range, skip past it.
|
||||
if (Location->Register == 0 || (Location->Offset && !Location->InMemory))
|
||||
// We can only handle a register or an offseted load of a register.
|
||||
if (Location->Register == 0 || Location->LoadChain.size() > 1)
|
||||
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;
|
||||
DR.InMemory = !Location->LoadChain.empty();
|
||||
DR.DataOffset =
|
||||
!Location->LoadChain.empty() ? Location->LoadChain.back() : 0;
|
||||
if (Location->FragmentInfo) {
|
||||
DR.IsSubfield = true;
|
||||
DR.StructOffset = Location->FragmentInfo->OffsetInBits / 8;
|
||||
@ -2113,8 +2119,9 @@ void CodeViewDebug::emitLocalVariable(const LocalVariable &Var) {
|
||||
Flags |= LocalSymFlags::IsOptimizedOut;
|
||||
|
||||
OS.AddComment("TypeIndex");
|
||||
TypeIndex TI = Var.Deref ? getTypeIndexForReferenceTo(Var.DIVar->getType())
|
||||
: getCompleteTypeIndex(Var.DIVar->getType());
|
||||
TypeIndex TI = Var.UseReferenceType
|
||||
? getTypeIndexForReferenceTo(Var.DIVar->getType())
|
||||
: getCompleteTypeIndex(Var.DIVar->getType());
|
||||
OS.EmitIntValue(TI.getIndex(), 4);
|
||||
OS.AddComment("Flags");
|
||||
OS.EmitIntValue(static_cast<uint16_t>(Flags), 2);
|
||||
|
@ -94,7 +94,7 @@ class LLVM_LIBRARY_VISIBILITY CodeViewDebug : public DebugHandlerBase {
|
||||
struct LocalVariable {
|
||||
const DILocalVariable *DIVar = nullptr;
|
||||
SmallVector<LocalVarDefRange, 1> DefRanges;
|
||||
bool Deref = false;
|
||||
bool UseReferenceType = false;
|
||||
};
|
||||
|
||||
struct InlineSite {
|
||||
|
@ -34,8 +34,6 @@ DbgVariableLocation::extractFromMachineInstruction(
|
||||
if (!Instruction.getOperand(0).isReg())
|
||||
return None;
|
||||
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.
|
||||
@ -67,7 +65,8 @@ DbgVariableLocation::extractFromMachineInstruction(
|
||||
Location.FragmentInfo = {Op->getArg(1), Op->getArg(0)};
|
||||
break;
|
||||
case dwarf::DW_OP_deref:
|
||||
Location.Deref = true;
|
||||
Location.LoadChain.push_back(Offset);
|
||||
Offset = 0;
|
||||
break;
|
||||
default:
|
||||
return None;
|
||||
@ -75,7 +74,12 @@ DbgVariableLocation::extractFromMachineInstruction(
|
||||
++Op;
|
||||
}
|
||||
|
||||
Location.Offset = Offset;
|
||||
// Do one final implicit DW_OP_deref if this was an indirect DBG_VALUE
|
||||
// instruction.
|
||||
// FIXME: Replace these with DIExpression.
|
||||
if (Instruction.isIndirectDebugValue())
|
||||
Location.LoadChain.push_back(Offset);
|
||||
|
||||
return Location;
|
||||
}
|
||||
|
||||
|
@ -30,19 +30,12 @@ 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;
|
||||
/// Chain of offsetted loads necessary to load the value if it lives in
|
||||
/// memory. Every load except for the last is pointer-sized.
|
||||
SmallVector<int64_t, 1> LoadChain;
|
||||
|
||||
/// Present if the location is part of a larger variable.
|
||||
llvm::Optional<llvm::DIExpression::FragmentInfo> FragmentInfo;
|
||||
|
@ -195,7 +195,7 @@ body: |
|
||||
CFI_INSTRUCTION offset %esi, -8
|
||||
%esi = MOV32rm %esp, 1, _, 8, _ :: (load 4 from %fixed-stack.2)
|
||||
DBG_VALUE %esp, 0, !26, !10, debug-location !25
|
||||
DBG_VALUE %esp, 0, !23, !11, debug-location !25
|
||||
DBG_VALUE %esp, 0, !23, !DIExpression(DW_OP_plus_uconst, 8, DW_OP_deref), debug-location !25
|
||||
CALLpcrel32 @getString, csr_32, implicit %esp, implicit-def %esp, implicit-def %eax, debug-location !29
|
||||
%ecx = MOV32rm %eax, 1, _, 0, _, debug-location !29 :: (dereferenceable load 4 from %ir.1)
|
||||
%edx = MOV32rm %eax, 1, _, 4, _, debug-location !29 :: (dereferenceable load 4 from %ir.1 + 4)
|
||||
@ -246,7 +246,7 @@ body: |
|
||||
bb.0.entry:
|
||||
%eax = MOV32rm %esp, 1, _, 4, _ :: (load 4 from %fixed-stack.1)
|
||||
%eax = MOV32rm killed %eax, 1, _, 0, _, debug-location !34 :: (load 4 from %ir.0)
|
||||
DBG_VALUE debug-use %eax, 0, !35, !28, debug-location !34
|
||||
DBG_VALUE debug-use %eax, 0, !35, !DIExpression(DW_OP_constu, 4, DW_OP_minus), debug-location !34
|
||||
%eax = ADD32rm killed %eax, %esp, 1, _, 8, _, implicit-def dead %eflags, debug-location !36 :: (load 4 from %fixed-stack.0)
|
||||
RET 0, %eax, debug-location !36
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user