Please use GitHub pull requests for new patches. Avoid migrating existing patches. Phabricator shutdown timeline
Changeset View
Changeset View
Standalone View
Standalone View
llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp
Show First 20 Lines • Show All 436 Lines • ▼ Show 20 Lines | public: | ||||
bool recoverAsEntryValue(const DebugVariable &Var, | bool recoverAsEntryValue(const DebugVariable &Var, | ||||
const DbgValueProperties &Prop, | const DbgValueProperties &Prop, | ||||
const ValueIDNum &Num) { | const ValueIDNum &Num) { | ||||
// Is this variable location a candidate to be an entry value. First, | // Is this variable location a candidate to be an entry value. First, | ||||
// should we be trying this at all? | // should we be trying this at all? | ||||
if (!ShouldEmitDebugEntryValues) | if (!ShouldEmitDebugEntryValues) | ||||
return false; | return false; | ||||
// We don't currently emit entry values for DBG_VALUE_LISTs. | |||||
if (Prop.IsVariadic) | |||||
return false; | |||||
// Is the variable appropriate for entry values (i.e., is a parameter). | // Is the variable appropriate for entry values (i.e., is a parameter). | ||||
if (!isEntryValueVariable(Var, Prop.DIExpr)) | if (!isEntryValueVariable(Var, Prop.DIExpr)) | ||||
return false; | return false; | ||||
// Is the value assigned to this variable still the entry value? | // Is the value assigned to this variable still the entry value? | ||||
if (!isEntryValueValue(Num)) | if (!isEntryValueValue(Num)) | ||||
return false; | return false; | ||||
// Emit a variable location using an entry value expression. | // Emit a variable location using an entry value expression. | ||||
DIExpression *NewExpr = | DIExpression *NewExpr = | ||||
DIExpression::prepend(Prop.DIExpr, DIExpression::EntryValue); | DIExpression::prepend(Prop.DIExpr, DIExpression::EntryValue); | ||||
Register Reg = MTracker->LocIdxToLocID[Num.getLoc()]; | Register Reg = MTracker->LocIdxToLocID[Num.getLoc()]; | ||||
MachineOperand MO = MachineOperand::CreateReg(Reg, false); | MachineOperand MO = MachineOperand::CreateReg(Reg, false); | ||||
PendingDbgValues.push_back(emitMOLoc(MO, Var, {NewExpr, Prop.Indirect})); | PendingDbgValues.push_back( | ||||
emitMOLoc(MO, Var, {NewExpr, Prop.Indirect, Prop.IsVariadic})); | |||||
return true; | return true; | ||||
} | } | ||||
/// Change a variable value after encountering a DBG_VALUE inside a block. | /// Change a variable value after encountering a DBG_VALUE inside a block. | ||||
void redefVar(const MachineInstr &MI) { | void redefVar(const MachineInstr &MI) { | ||||
DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(), | DebugVariable Var(MI.getDebugVariable(), MI.getDebugExpression(), | ||||
MI.getDebugLoc()->getInlinedAt()); | MI.getDebugLoc()->getInlinedAt()); | ||||
DbgValueProperties Properties(MI); | DbgValueProperties Properties(MI); | ||||
const MachineOperand &MO = MI.getOperand(0); | const MachineOperand &MO = MI.getDebugOperand(0); | ||||
// Ignore non-register locations, we don't transfer those. | // Ignore non-register locations, we don't transfer those. | ||||
if (!MO.isReg() || MO.getReg() == 0) { | if (!MO.isReg() || MO.getReg() == 0) { | ||||
auto It = ActiveVLocs.find(Var); | auto It = ActiveVLocs.find(Var); | ||||
if (It != ActiveVLocs.end()) { | if (It != ActiveVLocs.end()) { | ||||
ActiveMLocs[It->second.Loc].erase(Var); | ActiveMLocs[It->second.Loc].erase(Var); | ||||
ActiveVLocs.erase(It); | ActiveVLocs.erase(It); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 378 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
MachineInstrBuilder MLocTracker::emitLoc(Optional<LocIdx> MLoc, | MachineInstrBuilder MLocTracker::emitLoc(Optional<LocIdx> MLoc, | ||||
const DebugVariable &Var, | const DebugVariable &Var, | ||||
const DbgValueProperties &Properties) { | const DbgValueProperties &Properties) { | ||||
DebugLoc DL = DILocation::get(Var.getVariable()->getContext(), 0, 0, | DebugLoc DL = DILocation::get(Var.getVariable()->getContext(), 0, 0, | ||||
Var.getVariable()->getScope(), | Var.getVariable()->getScope(), | ||||
const_cast<DILocation *>(Var.getInlinedAt())); | const_cast<DILocation *>(Var.getInlinedAt())); | ||||
auto MIB = BuildMI(MF, DL, TII.get(TargetOpcode::DBG_VALUE)); | |||||
const MCInstrDesc &Desc = Properties.IsVariadic | |||||
? TII.get(TargetOpcode::DBG_VALUE_LIST) | |||||
: TII.get(TargetOpcode::DBG_VALUE); | |||||
auto GetRegOp = [](unsigned Reg) -> MachineOperand { | |||||
return MachineOperand::CreateReg( | |||||
/* Reg */ Reg, /* isDef */ false, /* isImp */ false, | |||||
/* isKill */ false, /* isDead */ false, | |||||
/* isUndef */ false, /* isEarlyClobber */ false, | |||||
/* SubReg */ 0, /* isDebug */ true); | |||||
}; | |||||
SmallVector<MachineOperand> MOs; | |||||
auto EmitUndef = [&]() { | |||||
MOs.clear(); | |||||
MOs.assign(Properties.getLocationOpCount(), GetRegOp(0)); | |||||
return BuildMI(MF, DL, Desc, false, MOs, Var.getVariable(), | |||||
Properties.DIExpr); | |||||
}; | |||||
// Only 1 location is currently supported. | |||||
if (Properties.IsVariadic && Properties.getLocationOpCount() != 1) | |||||
return EmitUndef(); | |||||
bool Indirect = Properties.Indirect; | |||||
const DIExpression *Expr = Properties.DIExpr; | const DIExpression *Expr = Properties.DIExpr; | ||||
if (!MLoc) { | if (!MLoc) { | ||||
// No location -> DBG_VALUE $noreg | // No location -> DBG_VALUE $noreg | ||||
MIB.addReg(0); | return EmitUndef(); | ||||
MIB.addReg(0); | |||||
} else if (LocIdxToLocID[*MLoc] >= NumRegs) { | } else if (LocIdxToLocID[*MLoc] >= NumRegs) { | ||||
unsigned LocID = LocIdxToLocID[*MLoc]; | unsigned LocID = LocIdxToLocID[*MLoc]; | ||||
SpillLocationNo SpillID = locIDToSpill(LocID); | SpillLocationNo SpillID = locIDToSpill(LocID); | ||||
StackSlotPos StackIdx = locIDToSpillIdx(LocID); | StackSlotPos StackIdx = locIDToSpillIdx(LocID); | ||||
unsigned short Offset = StackIdx.second; | unsigned short Offset = StackIdx.second; | ||||
// TODO: support variables that are located in spill slots, with non-zero | // TODO: support variables that are located in spill slots, with non-zero | ||||
// offsets from the start of the spill slot. It would require some more | // offsets from the start of the spill slot. It would require some more | ||||
// complex DIExpression calculations. This doesn't seem to be produced by | // complex DIExpression calculations. This doesn't seem to be produced by | ||||
// LLVM right now, so don't try and support it. | // LLVM right now, so don't try and support it. | ||||
// Accept no-subregister slots and subregisters where the offset is zero. | // Accept no-subregister slots and subregisters where the offset is zero. | ||||
// The consumer should already have type information to work out how large | // The consumer should already have type information to work out how large | ||||
// the variable is. | // the variable is. | ||||
if (Offset == 0) { | if (Offset == 0) { | ||||
const SpillLoc &Spill = SpillLocs[SpillID.id()]; | const SpillLoc &Spill = SpillLocs[SpillID.id()]; | ||||
unsigned Base = Spill.SpillBase; | unsigned Base = Spill.SpillBase; | ||||
MIB.addReg(Base); | MOs.push_back(GetRegOp(Base)); | ||||
// There are several ways we can dereference things, and several inputs | // There are several ways we can dereference things, and several inputs | ||||
// to consider: | // to consider: | ||||
// * NRVO variables will appear with IsIndirect set, but should have | // * NRVO variables will appear with IsIndirect set, but should have | ||||
// nothing else in their DIExpressions, | // nothing else in their DIExpressions, | ||||
// * Variables with DW_OP_stack_value in their expr already need an | // * Variables with DW_OP_stack_value in their expr already need an | ||||
// explicit dereference of the stack location, | // explicit dereference of the stack location, | ||||
// * Values that don't match the variable size need DW_OP_deref_size, | // * Values that don't match the variable size need DW_OP_deref_size, | ||||
Show All 22 Lines | if (Offset == 0) { | ||||
// spilt to the stack, or a dbg.addr pointing at a coroutine frame | // spilt to the stack, or a dbg.addr pointing at a coroutine frame | ||||
// field. It should end up being a memory location, with the pointer | // field. It should end up being a memory location, with the pointer | ||||
// to the variable loaded off the stack with a deref. It can't be a | // to the variable loaded off the stack with a deref. It can't be a | ||||
// DW_OP_stack_value expression. | // DW_OP_stack_value expression. | ||||
assert(!Expr->isImplicit()); | assert(!Expr->isImplicit()); | ||||
Expr = TRI.prependOffsetExpression( | Expr = TRI.prependOffsetExpression( | ||||
Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, | Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, | ||||
Spill.SpillOffset); | Spill.SpillOffset); | ||||
MIB.addImm(0); | |||||
} else if (UseDerefSize) { | } else if (UseDerefSize) { | ||||
// We're loading a value off the stack that's not the same size as the | // We're loading a value off the stack that's not the same size as the | ||||
// variable. Add / subtract stack offset, explicitly deref with a size, | // variable. Add / subtract stack offset, explicitly deref with a size, | ||||
// and add DW_OP_stack_value if not already present. | // and add DW_OP_stack_value if not already present. | ||||
SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, | SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, | ||||
DerefSizeInBytes}; | DerefSizeInBytes}; | ||||
Expr = DIExpression::prependOpcodes(Expr, Ops, true); | Expr = DIExpression::prependOpcodes(Expr, Ops, true); | ||||
unsigned Flags = DIExpression::StackValue | DIExpression::ApplyOffset; | unsigned Flags = DIExpression::StackValue | DIExpression::ApplyOffset; | ||||
Expr = TRI.prependOffsetExpression(Expr, Flags, Spill.SpillOffset); | Expr = TRI.prependOffsetExpression(Expr, Flags, Spill.SpillOffset); | ||||
MIB.addReg(0); | |||||
} else if (Expr->isComplex()) { | } else if (Expr->isComplex()) { | ||||
// A variable with no size ambiguity, but with extra elements in it's | // A variable with no size ambiguity, but with extra elements in it's | ||||
// expression. Manually dereference the stack location. | // expression. Manually dereference the stack location. | ||||
assert(Expr->isComplex()); | assert(Expr->isComplex()); | ||||
Expr = TRI.prependOffsetExpression( | Expr = TRI.prependOffsetExpression( | ||||
Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, | Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, | ||||
Spill.SpillOffset); | Spill.SpillOffset); | ||||
MIB.addReg(0); | |||||
} else { | } else { | ||||
// A plain value that has been spilt to the stack, with no further | // A plain value that has been spilt to the stack, with no further | ||||
// context. Request a location expression, marking the DBG_VALUE as | // context. Request a location expression, marking the DBG_VALUE as | ||||
// IsIndirect. | // IsIndirect. | ||||
Expr = TRI.prependOffsetExpression(Expr, DIExpression::ApplyOffset, | Expr = TRI.prependOffsetExpression(Expr, DIExpression::ApplyOffset, | ||||
Spill.SpillOffset); | Spill.SpillOffset); | ||||
MIB.addImm(0); | Indirect = true; | ||||
} | } | ||||
} else { | } else { | ||||
// This is a stack location with a weird subregister offset: emit an undef | // This is a stack location with a weird subregister offset: emit an undef | ||||
// DBG_VALUE instead. | // DBG_VALUE instead. | ||||
MIB.addReg(0); | return EmitUndef(); | ||||
MIB.addReg(0); | |||||
} | } | ||||
} else { | } else { | ||||
// Non-empty, non-stack slot, must be a plain register. | // Non-empty, non-stack slot, must be a plain register. | ||||
unsigned LocID = LocIdxToLocID[*MLoc]; | unsigned LocID = LocIdxToLocID[*MLoc]; | ||||
MIB.addReg(LocID); | MOs.push_back(GetRegOp(LocID)); | ||||
if (Properties.Indirect) | |||||
MIB.addImm(0); | |||||
else | |||||
MIB.addReg(0); | |||||
} | } | ||||
MIB.addMetadata(Var.getVariable()); | return BuildMI(MF, DL, Desc, Indirect, MOs, Var.getVariable(), Expr); | ||||
MIB.addMetadata(Expr); | |||||
return MIB; | |||||
} | } | ||||
/// Default construct and initialize the pass. | /// Default construct and initialize the pass. | ||||
InstrRefBasedLDV::InstrRefBasedLDV() = default; | InstrRefBasedLDV::InstrRefBasedLDV() = default; | ||||
bool InstrRefBasedLDV::isCalleeSaved(LocIdx L) const { | bool InstrRefBasedLDV::isCalleeSaved(LocIdx L) const { | ||||
unsigned Reg = MTracker->LocIdxToLocID[L]; | unsigned Reg = MTracker->LocIdxToLocID[L]; | ||||
for (MCRegAliasIterator RAI(Reg, TRI, true); RAI.isValid(); ++RAI) | for (MCRegAliasIterator RAI(Reg, TRI, true); RAI.isValid(); ++RAI) | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) { | ||||
if (MI.isDebugValueList()) { | if (MI.isDebugValueList()) { | ||||
if (VTracker) | if (VTracker) | ||||
VTracker->defVar(MI, Properties, None); | VTracker->defVar(MI, Properties, None); | ||||
if (TTracker) | if (TTracker) | ||||
TTracker->redefVar(MI, Properties, None); | TTracker->redefVar(MI, Properties, None); | ||||
return true; | return true; | ||||
} | } | ||||
const MachineOperand &MO = MI.getOperand(0); | const MachineOperand &MO = MI.getDebugOperand(0); | ||||
// MLocTracker needs to know that this register is read, even if it's only | // MLocTracker needs to know that this register is read, even if it's only | ||||
// read by a debug inst. | // read by a debug inst. | ||||
if (MO.isReg() && MO.getReg() != 0) | if (MO.isReg() && MO.getReg() != 0) | ||||
(void)MTracker->readReg(MO.getReg()); | (void)MTracker->readReg(MO.getReg()); | ||||
// If we're preparing for the second analysis (variables), the machine value | // If we're preparing for the second analysis (variables), the machine value | ||||
// locations are already solved, and we report this DBG_VALUE and the value | // locations are already solved, and we report this DBG_VALUE and the value | ||||
// it refers to to VLocTracker. | // it refers to to VLocTracker. | ||||
if (VTracker) { | if (VTracker) { | ||||
if (MO.isReg()) { | if (MO.isReg()) { | ||||
// Feed defVar the new variable location, or if this is a | // Feed defVar the new variable location, or if this is a | ||||
// DBG_VALUE $noreg, feed defVar None. | // DBG_VALUE $noreg, feed defVar None. | ||||
if (MO.getReg()) | if (MO.getReg()) | ||||
VTracker->defVar(MI, Properties, MTracker->readReg(MO.getReg())); | VTracker->defVar(MI, Properties, MTracker->readReg(MO.getReg())); | ||||
else | else | ||||
VTracker->defVar(MI, Properties, None); | VTracker->defVar(MI, Properties, None); | ||||
} else if (MI.getOperand(0).isImm() || MI.getOperand(0).isFPImm() || | } else if (MO.isImm() || MO.isFPImm() || MO.isCImm()) { | ||||
MI.getOperand(0).isCImm()) { | VTracker->defVar(MI, MO); | ||||
VTracker->defVar(MI, MI.getOperand(0)); | |||||
} | } | ||||
} | } | ||||
// If performing final tracking of transfers, report this variable definition | // If performing final tracking of transfers, report this variable definition | ||||
// to the TransferTracker too. | // to the TransferTracker too. | ||||
if (TTracker) | if (TTracker) | ||||
TTracker->redefVar(MI); | TTracker->redefVar(MI); | ||||
return true; | return true; | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | if (NewID && !MTracker->isSpill(L)) { | ||||
NewID = None; | NewID = None; | ||||
} | } | ||||
} | } | ||||
// We, we have a value number or None. Tell the variable value tracker about | // We, we have a value number or None. Tell the variable value tracker about | ||||
// it. The rest of this LiveDebugValues implementation acts exactly the same | // it. The rest of this LiveDebugValues implementation acts exactly the same | ||||
// for DBG_INSTR_REFs as DBG_VALUEs (just, the former can refer to values that | // for DBG_INSTR_REFs as DBG_VALUEs (just, the former can refer to values that | ||||
// aren't immediately available). | // aren't immediately available). | ||||
DbgValueProperties Properties(Expr, false); | DbgValueProperties Properties(Expr, false, false); | ||||
if (VTracker) | if (VTracker) | ||||
VTracker->defVar(MI, Properties, NewID); | VTracker->defVar(MI, Properties, NewID); | ||||
// If we're on the final pass through the function, decompose this INSTR_REF | // If we're on the final pass through the function, decompose this INSTR_REF | ||||
// into a plain DBG_VALUE. | // into a plain DBG_VALUE. | ||||
if (!TTracker) | if (!TTracker) | ||||
return true; | return true; | ||||
Show All 23 Lines | bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, | ||||
// Tell transfer tracker that the variable value has changed. | // Tell transfer tracker that the variable value has changed. | ||||
TTracker->redefVar(MI, Properties, FoundLoc); | TTracker->redefVar(MI, Properties, FoundLoc); | ||||
// If there was a value with no location; but the value is defined in a | // If there was a value with no location; but the value is defined in a | ||||
// later instruction in this block, this is a block-local use-before-def. | // later instruction in this block, this is a block-local use-before-def. | ||||
if (!FoundLoc && NewID && NewID->getBlock() == CurBB && | if (!FoundLoc && NewID && NewID->getBlock() == CurBB && | ||||
NewID->getInst() > CurInst) | NewID->getInst() > CurInst) | ||||
TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false}, *NewID); | TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false, false}, | ||||
*NewID); | |||||
// Produce a DBG_VALUE representing what this DBG_INSTR_REF meant. | // Produce a DBG_VALUE representing what this DBG_INSTR_REF meant. | ||||
// This DBG_VALUE is potentially a $noreg / undefined location, if | // This DBG_VALUE is potentially a $noreg / undefined location, if | ||||
// FoundLoc is None. | // FoundLoc is None. | ||||
// (XXX -- could morph the DBG_INSTR_REF in the future). | // (XXX -- could morph the DBG_INSTR_REF in the future). | ||||
MachineInstr *DbgMI = MTracker->emitLoc(FoundLoc, V, Properties); | MachineInstr *DbgMI = MTracker->emitLoc(FoundLoc, V, Properties); | ||||
TTracker->PendingDbgValues.push_back(DbgMI); | TTracker->PendingDbgValues.push_back(DbgMI); | ||||
TTracker->flushDbgValues(MI.getIterator(), nullptr); | TTracker->flushDbgValues(MI.getIterator(), nullptr); | ||||
▲ Show 20 Lines • Show All 1,359 Lines • ▼ Show 20 Lines | void InstrRefBasedLDV::buildVLocValueMap( | ||||
// Allocate some vectors for storing the live ins and live outs. Large. | // Allocate some vectors for storing the live ins and live outs. Large. | ||||
SmallVector<DbgValue, 32> LiveIns, LiveOuts; | SmallVector<DbgValue, 32> LiveIns, LiveOuts; | ||||
LiveIns.reserve(NumBlocks); | LiveIns.reserve(NumBlocks); | ||||
LiveOuts.reserve(NumBlocks); | LiveOuts.reserve(NumBlocks); | ||||
// Initialize all values to start as NoVals. This signifies "it's live | // Initialize all values to start as NoVals. This signifies "it's live | ||||
// through, but we don't know what it is". | // through, but we don't know what it is". | ||||
DbgValueProperties EmptyProperties(EmptyExpr, false); | DbgValueProperties EmptyProperties(EmptyExpr, false, false); | ||||
for (unsigned int I = 0; I < NumBlocks; ++I) { | for (unsigned int I = 0; I < NumBlocks; ++I) { | ||||
DbgValue EmptyDbgValue(I, EmptyProperties, DbgValue::NoVal); | DbgValue EmptyDbgValue(I, EmptyProperties, DbgValue::NoVal); | ||||
LiveIns.push_back(EmptyDbgValue); | LiveIns.push_back(EmptyDbgValue); | ||||
LiveOuts.push_back(EmptyDbgValue); | LiveOuts.push_back(EmptyDbgValue); | ||||
} | } | ||||
// Produce by-MBB indexes of live-in/live-outs, to ease lookup within | // Produce by-MBB indexes of live-in/live-outs, to ease lookup within | ||||
// vlocJoin. | // vlocJoin. | ||||
▲ Show 20 Lines • Show All 1,071 Lines • Show Last 20 Lines |