diff options
Diffstat (limited to 'llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp')
| -rw-r--r-- | llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp | 621 |
1 files changed, 431 insertions, 190 deletions
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp index 0eb6100230bd..30ca8bd871e8 100644 --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -84,21 +84,18 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/IteratedDominanceFrontier.h" +#include "llvm/BinaryFormat/Dwarf.h" #include "llvm/CodeGen/LexicalScopes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" -#include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineInstrBundle.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/MachineOperand.h" #include "llvm/CodeGen/PseudoSourceValue.h" -#include "llvm/CodeGen/RegisterScavenging.h" #include "llvm/CodeGen/TargetFrameLowering.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" @@ -106,27 +103,23 @@ #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/Config/llvm-config.h" -#include "llvm/IR/DIBuilder.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" -#include "llvm/IR/Module.h" -#include "llvm/InitializePasses.h" #include "llvm/MC/MCRegisterInfo.h" -#include "llvm/Pass.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/GenericIteratedDominanceFrontier.h" #include "llvm/Support/TypeSize.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/Utils/SSAUpdaterImpl.h" #include <algorithm> #include <cassert> +#include <climits> #include <cstdint> #include <functional> -#include <limits.h> -#include <limits> #include <queue> #include <tuple> #include <utility> @@ -148,6 +141,20 @@ static cl::opt<bool> EmulateOldLDV("emulate-old-livedebugvalues", cl::Hidden, cl::desc("Act like old LiveDebugValues did"), cl::init(false)); +// Limit for the maximum number of stack slots we should track, past which we +// will ignore any spills. InstrRefBasedLDV gathers detailed information on all +// stack slots which leads to high memory consumption, and in some scenarios +// (such as asan with very many locals) the working set of the function can be +// very large, causing many spills. In these scenarios, it is very unlikely that +// the developer has hundreds of variables live at the same time that they're +// carefully thinking about -- instead, they probably autogenerated the code. +// When this happens, gracefully stop tracking excess spill slots, rather than +// consuming all the developer's memory. +static cl::opt<unsigned> + StackWorkingSetLimit("livedebugvalues-max-stack-slots", cl::Hidden, + cl::desc("livedebugvalues-stack-ws-limit"), + cl::init(250)); + /// Tracker for converting machine value locations and variable values into /// variable locations (the output of LiveDebugValues), recorded as DBG_VALUEs /// specifying block live-in locations and transfers within blocks. @@ -252,7 +259,7 @@ public: /// object fields to track variable locations as we step through the block. /// FIXME: could just examine mloctracker instead of passing in \p mlocs? void - loadInlocs(MachineBasicBlock &MBB, ValueIDNum *MLocs, + loadInlocs(MachineBasicBlock &MBB, ValueTable &MLocs, const SmallVectorImpl<std::pair<DebugVariable, DbgValue>> &VLocs, unsigned NumLocs) { ActiveMLocs.clear(); @@ -715,6 +722,20 @@ MLocTracker::MLocTracker(MachineFunction &MF, const TargetInstrInfo &TII, StackSlotIdxes.insert({{Size, Offs}, Idx}); } + // There may also be strange register class sizes (think x86 fp80s). + for (const TargetRegisterClass *RC : TRI.regclasses()) { + unsigned Size = TRI.getRegSizeInBits(*RC); + + // We might see special reserved values as sizes, and classes for other + // stuff the machine tries to model. If it's more than 512 bits, then it + // is very unlikely to be a register than can be spilt. + if (Size > 512) + continue; + + unsigned Idx = StackSlotIdxes.size(); + StackSlotIdxes.insert({{Size, 0}, Idx}); + } + for (auto &Idx : StackSlotIdxes) StackIdxesToPos[Idx.second] = Idx.first; @@ -757,9 +778,15 @@ void MLocTracker::writeRegMask(const MachineOperand *MO, unsigned CurBB, Masks.push_back(std::make_pair(MO, InstID)); } -SpillLocationNo MLocTracker::getOrTrackSpillLoc(SpillLoc L) { +Optional<SpillLocationNo> MLocTracker::getOrTrackSpillLoc(SpillLoc L) { SpillLocationNo SpillID(SpillLocs.idFor(L)); + if (SpillID.id() == 0) { + // If there is no location, and we have reached the limit of how many stack + // slots to track, then don't track this one. + if (SpillLocs.size() >= StackWorkingSetLimit) + return None; + // Spill location is untracked: create record for this one, and all // subregister slots too. SpillID = SpillLocationNo(SpillLocs.insert(L)); @@ -843,19 +870,72 @@ MachineInstrBuilder MLocTracker::emitLoc(Optional<LocIdx> MLoc, // the variable is. if (Offset == 0) { const SpillLoc &Spill = SpillLocs[SpillID.id()]; - Expr = TRI.prependOffsetExpression(Expr, DIExpression::ApplyOffset, - Spill.SpillOffset); unsigned Base = Spill.SpillBase; MIB.addReg(Base); - MIB.addImm(0); - // Being on the stack makes this location indirect; if it was _already_ - // indirect though, we need to add extra indirection. See this test for - // a scenario where this happens: - // llvm/test/DebugInfo/X86/spill-nontrivial-param.ll + // There are several ways we can dereference things, and several inputs + // to consider: + // * NRVO variables will appear with IsIndirect set, but should have + // nothing else in their DIExpressions, + // * Variables with DW_OP_stack_value in their expr already need an + // explicit dereference of the stack location, + // * Values that don't match the variable size need DW_OP_deref_size, + // * Everything else can just become a simple location expression. + + // We need to use deref_size whenever there's a mismatch between the + // size of value and the size of variable portion being read. + // Additionally, we should use it whenever dealing with stack_value + // fragments, to avoid the consumer having to determine the deref size + // from DW_OP_piece. + bool UseDerefSize = false; + unsigned ValueSizeInBits = getLocSizeInBits(*MLoc); + unsigned DerefSizeInBytes = ValueSizeInBits / 8; + if (auto Fragment = Var.getFragment()) { + unsigned VariableSizeInBits = Fragment->SizeInBits; + if (VariableSizeInBits != ValueSizeInBits || Expr->isComplex()) + UseDerefSize = true; + } else if (auto Size = Var.getVariable()->getSizeInBits()) { + if (*Size != ValueSizeInBits) { + UseDerefSize = true; + } + } + if (Properties.Indirect) { - std::vector<uint64_t> Elts = {dwarf::DW_OP_deref}; - Expr = DIExpression::append(Expr, Elts); + // This is something like an NRVO variable, where the pointer has been + // 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 + // to the variable loaded off the stack with a deref. It can't be a + // DW_OP_stack_value expression. + assert(!Expr->isImplicit()); + Expr = TRI.prependOffsetExpression( + Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, + Spill.SpillOffset); + MIB.addImm(0); + } else if (UseDerefSize) { + // 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, + // and add DW_OP_stack_value if not already present. + SmallVector<uint64_t, 2> Ops = {dwarf::DW_OP_deref_size, + DerefSizeInBytes}; + Expr = DIExpression::prependOpcodes(Expr, Ops, true); + unsigned Flags = DIExpression::StackValue | DIExpression::ApplyOffset; + Expr = TRI.prependOffsetExpression(Expr, Flags, Spill.SpillOffset); + MIB.addReg(0); + } else if (Expr->isComplex()) { + // A variable with no size ambiguity, but with extra elements in it's + // expression. Manually dereference the stack location. + assert(Expr->isComplex()); + Expr = TRI.prependOffsetExpression( + Expr, DIExpression::ApplyOffset | DIExpression::DerefAfter, + Spill.SpillOffset); + MIB.addReg(0); + } else { + // A plain value that has been spilt to the stack, with no further + // context. Request a location expression, marking the DBG_VALUE as + // IsIndirect. + Expr = TRI.prependOffsetExpression(Expr, DIExpression::ApplyOffset, + Spill.SpillOffset); + MIB.addImm(0); } } else { // This is a stack location with a weird subregister offset: emit an undef @@ -879,7 +959,7 @@ MachineInstrBuilder MLocTracker::emitLoc(Optional<LocIdx> MLoc, } /// Default construct and initialize the pass. -InstrRefBasedLDV::InstrRefBasedLDV() {} +InstrRefBasedLDV::InstrRefBasedLDV() = default; bool InstrRefBasedLDV::isCalleeSaved(LocIdx L) const { unsigned Reg = MTracker->LocIdxToLocID[L]; @@ -898,7 +978,7 @@ bool InstrRefBasedLDV::isCalleeSaved(LocIdx L) const { // void InstrRefBasedLDV::printVarLocInMBB(..) #endif -SpillLocationNo +Optional<SpillLocationNo> InstrRefBasedLDV::extractSpillBaseRegAndOffset(const MachineInstr &MI) { assert(MI.hasOneMemOperand() && "Spill instruction does not have exactly one memory operand?"); @@ -913,8 +993,11 @@ InstrRefBasedLDV::extractSpillBaseRegAndOffset(const MachineInstr &MI) { return MTracker->getOrTrackSpillLoc({Reg, Offset}); } -Optional<LocIdx> InstrRefBasedLDV::findLocationForMemOperand(const MachineInstr &MI) { - SpillLocationNo SpillLoc = extractSpillBaseRegAndOffset(MI); +Optional<LocIdx> +InstrRefBasedLDV::findLocationForMemOperand(const MachineInstr &MI) { + Optional<SpillLocationNo> SpillLoc = extractSpillBaseRegAndOffset(MI); + if (!SpillLoc) + return None; // Where in the stack slot is this value defined -- i.e., what size of value // is this? An important question, because it could be loaded into a register @@ -930,7 +1013,7 @@ Optional<LocIdx> InstrRefBasedLDV::findLocationForMemOperand(const MachineInstr // occur, but the safe action is to indicate the variable is optimised out. return None; - unsigned SpillID = MTracker->getSpillIDWithIdx(SpillLoc, IdxIt->second); + unsigned SpillID = MTracker->getSpillIDWithIdx(*SpillLoc, IdxIt->second); return MTracker->getSpillMLoc(SpillID); } @@ -999,14 +1082,14 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) { } bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, - ValueIDNum **MLiveOuts, - ValueIDNum **MLiveIns) { + const ValueTable *MLiveOuts, + const ValueTable *MLiveIns) { if (!MI.isDebugRef()) return false; // Only handle this instruction when we are building the variable value // transfer function. - if (!VTracker) + if (!VTracker && !TTracker) return false; unsigned InstNo = MI.getOperand(0).getImm(); @@ -1068,15 +1151,25 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, if (L) NewID = ValueIDNum(BlockNo, InstrIt->second.second, *L); } else if (OpNo != MachineFunction::DebugOperandMemNumber) { - assert(OpNo < TargetInstr.getNumOperands()); - const MachineOperand &MO = TargetInstr.getOperand(OpNo); + // Permit the debug-info to be completely wrong: identifying a nonexistant + // operand, or one that is not a register definition, means something + // unexpected happened during optimisation. Broken debug-info, however, + // shouldn't crash the compiler -- instead leave the variable value as + // None, which will make it appear "optimised out". + if (OpNo < TargetInstr.getNumOperands()) { + const MachineOperand &MO = TargetInstr.getOperand(OpNo); - // Today, this can only be a register. - assert(MO.isReg() && MO.isDef()); + if (MO.isReg() && MO.isDef() && MO.getReg()) { + unsigned LocID = MTracker->getLocID(MO.getReg()); + LocIdx L = MTracker->LocIDToLocIdx[LocID]; + NewID = ValueIDNum(BlockNo, InstrIt->second.second, L); + } + } - unsigned LocID = MTracker->getLocID(MO.getReg()); - LocIdx L = MTracker->LocIDToLocIdx[LocID]; - NewID = ValueIDNum(BlockNo, InstrIt->second.second, L); + if (!NewID) { + LLVM_DEBUG( + { dbgs() << "Seen instruction reference to illegal operand\n"; }); + } } // else: NewID is left as None. } else if (PHIIt != DebugPHINumToValue.end() && PHIIt->InstrNum == InstNo) { @@ -1162,7 +1255,8 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, // for DBG_INSTR_REFs as DBG_VALUEs (just, the former can refer to values that // aren't immediately available). DbgValueProperties Properties(Expr, false); - VTracker->defVar(MI, Properties, NewID); + if (VTracker) + VTracker->defVar(MI, Properties, NewID); // If we're on the final pass through the function, decompose this INSTR_REF // into a plain DBG_VALUE. @@ -1225,7 +1319,16 @@ bool InstrRefBasedLDV::transferDebugPHI(MachineInstr &MI) { const MachineOperand &MO = MI.getOperand(0); unsigned InstrNum = MI.getOperand(1).getImm(); - if (MO.isReg()) { + auto EmitBadPHI = [this, &MI, InstrNum](void) -> bool { + // Helper lambda to do any accounting when we fail to find a location for + // a DBG_PHI. This can happen if DBG_PHIs are malformed, or refer to a + // dead stack slot, for example. + // Record a DebugPHIRecord with an empty value + location. + DebugPHINumToValue.push_back({InstrNum, MI.getParent(), None, None}); + return true; + }; + + if (MO.isReg() && MO.getReg()) { // The value is whatever's currently in the register. Read and record it, // to be analysed later. Register Reg = MO.getReg(); @@ -1237,57 +1340,45 @@ bool InstrRefBasedLDV::transferDebugPHI(MachineInstr &MI) { // Ensure this register is tracked. for (MCRegAliasIterator RAI(MO.getReg(), TRI, true); RAI.isValid(); ++RAI) MTracker->lookupOrTrackRegister(*RAI); - } else { + } else if (MO.isFI()) { // The value is whatever's in this stack slot. - assert(MO.isFI()); unsigned FI = MO.getIndex(); // If the stack slot is dead, then this was optimized away. // FIXME: stack slot colouring should account for slots that get merged. if (MFI->isDeadObjectIndex(FI)) - return true; + return EmitBadPHI(); // Identify this spill slot, ensure it's tracked. Register Base; StackOffset Offs = TFI->getFrameIndexReference(*MI.getMF(), FI, Base); SpillLoc SL = {Base, Offs}; - SpillLocationNo SpillNo = MTracker->getOrTrackSpillLoc(SL); + Optional<SpillLocationNo> SpillNo = MTracker->getOrTrackSpillLoc(SL); - // Problem: what value should we extract from the stack? LLVM does not - // record what size the last store to the slot was, and it would become - // sketchy after stack slot colouring anyway. Take a look at what values - // are stored on the stack, and pick the largest one that wasn't def'd - // by a spill (i.e., the value most likely to have been def'd in a register - // and then spilt. - std::array<unsigned, 4> CandidateSizes = {64, 32, 16, 8}; - Optional<ValueIDNum> Result = None; - Optional<LocIdx> SpillLoc = None; - for (unsigned CS : CandidateSizes) { - unsigned SpillID = MTracker->getLocID(SpillNo, {CS, 0}); - SpillLoc = MTracker->getSpillMLoc(SpillID); - ValueIDNum Val = MTracker->readMLoc(*SpillLoc); - // If this value was defined in it's own position, then it was probably - // an aliasing index of a small value that was spilt. - if (Val.getLoc() != SpillLoc->asU64()) { - Result = Val; - break; - } - } + // We might be able to find a value, but have chosen not to, to avoid + // tracking too much stack information. + if (!SpillNo) + return EmitBadPHI(); - // If we didn't find anything, we're probably looking at a PHI, or a memory - // store folded into an instruction. FIXME: Take a guess that's it's 64 - // bits. This isn't ideal, but tracking the size that the spill is - // "supposed" to be is more complex, and benefits a small number of - // locations. - if (!Result) { - unsigned SpillID = MTracker->getLocID(SpillNo, {64, 0}); - SpillLoc = MTracker->getSpillMLoc(SpillID); - Result = MTracker->readMLoc(*SpillLoc); - } + // Any stack location DBG_PHI should have an associate bit-size. + assert(MI.getNumOperands() == 3 && "Stack DBG_PHI with no size?"); + unsigned slotBitSize = MI.getOperand(2).getImm(); + + unsigned SpillID = MTracker->getLocID(*SpillNo, {slotBitSize, 0}); + LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID); + ValueIDNum Result = MTracker->readMLoc(SpillLoc); // Record this DBG_PHI for later analysis. - auto DbgPHI = DebugPHIRecord({InstrNum, MI.getParent(), *Result, *SpillLoc}); + auto DbgPHI = DebugPHIRecord({InstrNum, MI.getParent(), Result, SpillLoc}); DebugPHINumToValue.push_back(DbgPHI); + } else { + // Else: if the operand is neither a legal register or a stack slot, then + // we're being fed illegal debug-info. Record an empty PHI, so that any + // debug users trying to read this number will be put off trying to + // interpret the value. + LLVM_DEBUG( + { dbgs() << "Seen DBG_PHI with unrecognised operand format\n"; }); + return EmitBadPHI(); } return true; @@ -1357,11 +1448,12 @@ void InstrRefBasedLDV::transferRegisterDef(MachineInstr &MI) { // If this instruction writes to a spill slot, def that slot. if (hasFoldedStackStore(MI)) { - SpillLocationNo SpillNo = extractSpillBaseRegAndOffset(MI); - for (unsigned int I = 0; I < MTracker->NumSlotIdxes; ++I) { - unsigned SpillID = MTracker->getSpillIDWithIdx(SpillNo, I); - LocIdx L = MTracker->getSpillMLoc(SpillID); - MTracker->setMLoc(L, ValueIDNum(CurBB, CurInst, L)); + if (Optional<SpillLocationNo> SpillNo = extractSpillBaseRegAndOffset(MI)) { + for (unsigned int I = 0; I < MTracker->NumSlotIdxes; ++I) { + unsigned SpillID = MTracker->getSpillIDWithIdx(*SpillNo, I); + LocIdx L = MTracker->getSpillMLoc(SpillID); + MTracker->setMLoc(L, ValueIDNum(CurBB, CurInst, L)); + } } } @@ -1398,11 +1490,12 @@ void InstrRefBasedLDV::transferRegisterDef(MachineInstr &MI) { // Tell TTracker about any folded stack store. if (hasFoldedStackStore(MI)) { - SpillLocationNo SpillNo = extractSpillBaseRegAndOffset(MI); - for (unsigned int I = 0; I < MTracker->NumSlotIdxes; ++I) { - unsigned SpillID = MTracker->getSpillIDWithIdx(SpillNo, I); - LocIdx L = MTracker->getSpillMLoc(SpillID); - TTracker->clobberMloc(L, MI.getIterator(), true); + if (Optional<SpillLocationNo> SpillNo = extractSpillBaseRegAndOffset(MI)) { + for (unsigned int I = 0; I < MTracker->NumSlotIdxes; ++I) { + unsigned SpillID = MTracker->getSpillIDWithIdx(*SpillNo, I); + LocIdx L = MTracker->getSpillMLoc(SpillID); + TTracker->clobberMloc(L, MI.getIterator(), true); + } } } } @@ -1438,23 +1531,24 @@ void InstrRefBasedLDV::performCopy(Register SrcRegNum, Register DstRegNum) { } } -bool InstrRefBasedLDV::isSpillInstruction(const MachineInstr &MI, - MachineFunction *MF) { +Optional<SpillLocationNo> +InstrRefBasedLDV::isSpillInstruction(const MachineInstr &MI, + MachineFunction *MF) { // TODO: Handle multiple stores folded into one. if (!MI.hasOneMemOperand()) - return false; + return None; // Reject any memory operand that's aliased -- we can't guarantee its value. auto MMOI = MI.memoperands_begin(); const PseudoSourceValue *PVal = (*MMOI)->getPseudoValue(); if (PVal->isAliased(MFI)) - return false; + return None; if (!MI.getSpillSize(TII) && !MI.getFoldedSpillSize(TII)) - return false; // This is not a spill instruction, since no valid size was - // returned from either function. + return None; // This is not a spill instruction, since no valid size was + // returned from either function. - return true; + return extractSpillBaseRegAndOffset(MI); } bool InstrRefBasedLDV::isLocationSpill(const MachineInstr &MI, @@ -1511,13 +1605,11 @@ bool InstrRefBasedLDV::transferSpillOrRestoreInst(MachineInstr &MI) { // First, if there are any DBG_VALUEs pointing at a spill slot that is // written to, terminate that variable location. The value in memory // will have changed. DbgEntityHistoryCalculator doesn't try to detect this. - if (isSpillInstruction(MI, MF)) { - SpillLocationNo Loc = extractSpillBaseRegAndOffset(MI); - + if (Optional<SpillLocationNo> Loc = isSpillInstruction(MI, MF)) { // Un-set this location and clobber, so that earlier locations don't // continue past this store. for (unsigned SlotIdx = 0; SlotIdx < MTracker->NumSlotIdxes; ++SlotIdx) { - unsigned SpillID = MTracker->getSpillIDWithIdx(Loc, SlotIdx); + unsigned SpillID = MTracker->getSpillIDWithIdx(*Loc, SlotIdx); Optional<LocIdx> MLoc = MTracker->getSpillMLoc(SpillID); if (!MLoc) continue; @@ -1535,7 +1627,9 @@ bool InstrRefBasedLDV::transferSpillOrRestoreInst(MachineInstr &MI) { // Try to recognise spill and restore instructions that may transfer a value. if (isLocationSpill(MI, MF, Reg)) { - SpillLocationNo Loc = extractSpillBaseRegAndOffset(MI); + // isLocationSpill returning true should guarantee we can extract a + // location. + SpillLocationNo Loc = *extractSpillBaseRegAndOffset(MI); auto DoTransfer = [&](Register SrcReg, unsigned SpillID) { auto ReadValue = MTracker->readReg(SrcReg); @@ -1562,10 +1656,9 @@ bool InstrRefBasedLDV::transferSpillOrRestoreInst(MachineInstr &MI) { unsigned SpillID = MTracker->getLocID(Loc, {Size, 0}); DoTransfer(Reg, SpillID); } else { - Optional<SpillLocationNo> OptLoc = isRestoreInstruction(MI, MF, Reg); - if (!OptLoc) + Optional<SpillLocationNo> Loc = isRestoreInstruction(MI, MF, Reg); + if (!Loc) return false; - SpillLocationNo Loc = *OptLoc; // Assumption: we're reading from the base of the stack slot, not some // offset into it. It seems very unlikely LLVM would ever generate @@ -1583,22 +1676,17 @@ bool InstrRefBasedLDV::transferSpillOrRestoreInst(MachineInstr &MI) { LocIdx SrcIdx = MTracker->getSpillMLoc(SpillID); auto ReadValue = MTracker->readMLoc(SrcIdx); MTracker->setReg(DestReg, ReadValue); - - if (TTracker) { - LocIdx DstLoc = MTracker->getRegMLoc(DestReg); - TTracker->transferMlocs(SrcIdx, DstLoc, MI.getIterator()); - } }; for (MCSubRegIterator SRI(Reg, TRI, false); SRI.isValid(); ++SRI) { unsigned Subreg = TRI->getSubRegIndex(Reg, *SRI); - unsigned SpillID = MTracker->getLocID(Loc, Subreg); + unsigned SpillID = MTracker->getLocID(*Loc, Subreg); DoTransfer(*SRI, SpillID); } // Directly look up this registers slot idx by size, and transfer. unsigned Size = TRI->getRegSizeInBits(Reg, *MRI); - unsigned SpillID = MTracker->getLocID(Loc, {Size, 0}); + unsigned SpillID = MTracker->getLocID(*Loc, {Size, 0}); DoTransfer(Reg, SpillID); } return true; @@ -1724,8 +1812,8 @@ void InstrRefBasedLDV::accumulateFragmentMap(MachineInstr &MI) { AllSeenFragments.insert(ThisFragment); } -void InstrRefBasedLDV::process(MachineInstr &MI, ValueIDNum **MLiveOuts, - ValueIDNum **MLiveIns) { +void InstrRefBasedLDV::process(MachineInstr &MI, const ValueTable *MLiveOuts, + const ValueTable *MLiveIns) { // Try to interpret an MI as a debug or transfer instruction. Only if it's // none of these should we interpret it's register defs as new value // definitions. @@ -1775,7 +1863,10 @@ void InstrRefBasedLDV::produceMLocTransferFunction( // Step through each instruction in this block. for (auto &MI : MBB) { - process(MI); + // Pass in an empty unique_ptr for the value tables when accumulating the + // machine transfer function. + process(MI, nullptr, nullptr); + // Also accumulate fragment map. if (MI.isDebugValue() || MI.isDebugRef()) accumulateFragmentMap(MI); @@ -1864,7 +1955,7 @@ void InstrRefBasedLDV::produceMLocTransferFunction( bool InstrRefBasedLDV::mlocJoin( MachineBasicBlock &MBB, SmallPtrSet<const MachineBasicBlock *, 16> &Visited, - ValueIDNum **OutLocs, ValueIDNum *InLocs) { + FuncValueTable &OutLocs, ValueTable &InLocs) { LLVM_DEBUG(dbgs() << "join MBB: " << MBB.getNumber() << "\n"); bool Changed = false; @@ -1965,7 +2056,7 @@ void InstrRefBasedLDV::findStackIndexInterference( void InstrRefBasedLDV::placeMLocPHIs( MachineFunction &MF, SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks, - ValueIDNum **MInLocs, SmallVectorImpl<MLocTransferMap> &MLocTransfer) { + FuncValueTable &MInLocs, SmallVectorImpl<MLocTransferMap> &MLocTransfer) { SmallVector<unsigned, 4> StackUnits; findStackIndexInterference(StackUnits); @@ -2094,7 +2185,7 @@ void InstrRefBasedLDV::placeMLocPHIs( } void InstrRefBasedLDV::buildMLocValueMap( - MachineFunction &MF, ValueIDNum **MInLocs, ValueIDNum **MOutLocs, + MachineFunction &MF, FuncValueTable &MInLocs, FuncValueTable &MOutLocs, SmallVectorImpl<MLocTransferMap> &MLocTransfer) { std::priority_queue<unsigned int, std::vector<unsigned int>, std::greater<unsigned int>> @@ -2236,7 +2327,7 @@ void InstrRefBasedLDV::BlockPHIPlacement( Optional<ValueIDNum> InstrRefBasedLDV::pickVPHILoc( const MachineBasicBlock &MBB, const DebugVariable &Var, - const LiveIdxT &LiveOuts, ValueIDNum **MOutLocs, + const LiveIdxT &LiveOuts, FuncValueTable &MOutLocs, const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) { // Collect a set of locations from predecessor where its live-out value can // be found. @@ -2504,7 +2595,7 @@ void InstrRefBasedLDV::getBlocksForScope( void InstrRefBasedLDV::buildVLocValueMap( const DILocation *DILoc, const SmallSet<DebugVariable, 4> &VarsWeCareAbout, SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks, LiveInsT &Output, - ValueIDNum **MOutLocs, ValueIDNum **MInLocs, + FuncValueTable &MOutLocs, FuncValueTable &MInLocs, SmallVectorImpl<VLocTracker> &AllTheVLocs) { // This method is much like buildMLocValueMap: but focuses on a single // LexicalScope at a time. Pick out a set of blocks and variables that are @@ -2765,6 +2856,11 @@ void InstrRefBasedLDV::placePHIsForSingleVarDefinition( auto ValueIt = VLocs.Vars.find(Var); const DbgValue &Value = ValueIt->second; + // If it's an explicit assignment of "undef", that means there is no location + // anyway, anywhere. + if (Value.Kind == DbgValue::Undef) + return; + // Assign the variable value to entry to each dominated block that's in scope. // Skip the definition block -- it's assigned the variable value in the middle // of the block somewhere. @@ -2790,35 +2886,6 @@ void InstrRefBasedLDV::dump_mloc_transfer( } #endif -void InstrRefBasedLDV::emitLocations( - MachineFunction &MF, LiveInsT SavedLiveIns, ValueIDNum **MOutLocs, - ValueIDNum **MInLocs, DenseMap<DebugVariable, unsigned> &AllVarsNumbering, - const TargetPassConfig &TPC) { - TTracker = new TransferTracker(TII, MTracker, MF, *TRI, CalleeSavedRegs, TPC); - unsigned NumLocs = MTracker->getNumLocs(); - - // For each block, load in the machine value locations and variable value - // live-ins, then step through each instruction in the block. New DBG_VALUEs - // to be inserted will be created along the way. - for (MachineBasicBlock &MBB : MF) { - unsigned bbnum = MBB.getNumber(); - MTracker->reset(); - MTracker->loadFromArray(MInLocs[bbnum], bbnum); - TTracker->loadInlocs(MBB, MInLocs[bbnum], SavedLiveIns[MBB.getNumber()], - NumLocs); - - CurBB = bbnum; - CurInst = 1; - for (auto &MI : MBB) { - process(MI, MOutLocs, MInLocs); - TTracker->checkInstForNewValues(CurInst, MI.getIterator()); - ++CurInst; - } - } - - emitTransfers(AllVarsNumbering); -} - void InstrRefBasedLDV::initialSetup(MachineFunction &MF) { // Build some useful data structures. @@ -2861,8 +2928,172 @@ void InstrRefBasedLDV::initialSetup(MachineFunction &MF) { #endif } +// Produce an "ejection map" for blocks, i.e., what's the highest-numbered +// lexical scope it's used in. When exploring in DFS order and we pass that +// scope, the block can be processed and any tracking information freed. +void InstrRefBasedLDV::makeDepthFirstEjectionMap( + SmallVectorImpl<unsigned> &EjectionMap, + const ScopeToDILocT &ScopeToDILocation, + ScopeToAssignBlocksT &ScopeToAssignBlocks) { + SmallPtrSet<const MachineBasicBlock *, 8> BlocksToExplore; + SmallVector<std::pair<LexicalScope *, ssize_t>, 4> WorkStack; + auto *TopScope = LS.getCurrentFunctionScope(); + + // Unlike lexical scope explorers, we explore in reverse order, to find the + // "last" lexical scope used for each block early. + WorkStack.push_back({TopScope, TopScope->getChildren().size() - 1}); + + while (!WorkStack.empty()) { + auto &ScopePosition = WorkStack.back(); + LexicalScope *WS = ScopePosition.first; + ssize_t ChildNum = ScopePosition.second--; + + const SmallVectorImpl<LexicalScope *> &Children = WS->getChildren(); + if (ChildNum >= 0) { + // If ChildNum is positive, there are remaining children to explore. + // Push the child and its children-count onto the stack. + auto &ChildScope = Children[ChildNum]; + WorkStack.push_back( + std::make_pair(ChildScope, ChildScope->getChildren().size() - 1)); + } else { + WorkStack.pop_back(); + + // We've explored all children and any later blocks: examine all blocks + // in our scope. If they haven't yet had an ejection number set, then + // this scope will be the last to use that block. + auto DILocationIt = ScopeToDILocation.find(WS); + if (DILocationIt != ScopeToDILocation.end()) { + getBlocksForScope(DILocationIt->second, BlocksToExplore, + ScopeToAssignBlocks.find(WS)->second); + for (auto *MBB : BlocksToExplore) { + unsigned BBNum = MBB->getNumber(); + if (EjectionMap[BBNum] == 0) + EjectionMap[BBNum] = WS->getDFSOut(); + } + + BlocksToExplore.clear(); + } + } + } +} + +bool InstrRefBasedLDV::depthFirstVLocAndEmit( + unsigned MaxNumBlocks, const ScopeToDILocT &ScopeToDILocation, + const ScopeToVarsT &ScopeToVars, ScopeToAssignBlocksT &ScopeToAssignBlocks, + LiveInsT &Output, FuncValueTable &MOutLocs, FuncValueTable &MInLocs, + SmallVectorImpl<VLocTracker> &AllTheVLocs, MachineFunction &MF, + DenseMap<DebugVariable, unsigned> &AllVarsNumbering, + const TargetPassConfig &TPC) { + TTracker = new TransferTracker(TII, MTracker, MF, *TRI, CalleeSavedRegs, TPC); + unsigned NumLocs = MTracker->getNumLocs(); + VTracker = nullptr; + + // No scopes? No variable locations. + if (!LS.getCurrentFunctionScope()) + return false; + + // Build map from block number to the last scope that uses the block. + SmallVector<unsigned, 16> EjectionMap; + EjectionMap.resize(MaxNumBlocks, 0); + makeDepthFirstEjectionMap(EjectionMap, ScopeToDILocation, + ScopeToAssignBlocks); + + // Helper lambda for ejecting a block -- if nothing is going to use the block, + // we can translate the variable location information into DBG_VALUEs and then + // free all of InstrRefBasedLDV's data structures. + auto EjectBlock = [&](MachineBasicBlock &MBB) -> void { + unsigned BBNum = MBB.getNumber(); + AllTheVLocs[BBNum].clear(); + + // Prime the transfer-tracker, and then step through all the block + // instructions, installing transfers. + MTracker->reset(); + MTracker->loadFromArray(MInLocs[BBNum], BBNum); + TTracker->loadInlocs(MBB, MInLocs[BBNum], Output[BBNum], NumLocs); + + CurBB = BBNum; + CurInst = 1; + for (auto &MI : MBB) { + process(MI, MOutLocs.get(), MInLocs.get()); + TTracker->checkInstForNewValues(CurInst, MI.getIterator()); + ++CurInst; + } + + // Free machine-location tables for this block. + MInLocs[BBNum].reset(); + MOutLocs[BBNum].reset(); + // We don't need live-in variable values for this block either. + Output[BBNum].clear(); + AllTheVLocs[BBNum].clear(); + }; + + SmallPtrSet<const MachineBasicBlock *, 8> BlocksToExplore; + SmallVector<std::pair<LexicalScope *, ssize_t>, 4> WorkStack; + WorkStack.push_back({LS.getCurrentFunctionScope(), 0}); + unsigned HighestDFSIn = 0; + + // Proceed to explore in depth first order. + while (!WorkStack.empty()) { + auto &ScopePosition = WorkStack.back(); + LexicalScope *WS = ScopePosition.first; + ssize_t ChildNum = ScopePosition.second++; + + // We obesrve scopes with children twice here, once descending in, once + // ascending out of the scope nest. Use HighestDFSIn as a ratchet to ensure + // we don't process a scope twice. Additionally, ignore scopes that don't + // have a DILocation -- by proxy, this means we never tracked any variable + // assignments in that scope. + auto DILocIt = ScopeToDILocation.find(WS); + if (HighestDFSIn <= WS->getDFSIn() && DILocIt != ScopeToDILocation.end()) { + const DILocation *DILoc = DILocIt->second; + auto &VarsWeCareAbout = ScopeToVars.find(WS)->second; + auto &BlocksInScope = ScopeToAssignBlocks.find(WS)->second; + + buildVLocValueMap(DILoc, VarsWeCareAbout, BlocksInScope, Output, MOutLocs, + MInLocs, AllTheVLocs); + } + + HighestDFSIn = std::max(HighestDFSIn, WS->getDFSIn()); + + // Descend into any scope nests. + const SmallVectorImpl<LexicalScope *> &Children = WS->getChildren(); + if (ChildNum < (ssize_t)Children.size()) { + // There are children to explore -- push onto stack and continue. + auto &ChildScope = Children[ChildNum]; + WorkStack.push_back(std::make_pair(ChildScope, 0)); + } else { + WorkStack.pop_back(); + + // We've explored a leaf, or have explored all the children of a scope. + // Try to eject any blocks where this is the last scope it's relevant to. + auto DILocationIt = ScopeToDILocation.find(WS); + if (DILocationIt == ScopeToDILocation.end()) + continue; + + getBlocksForScope(DILocationIt->second, BlocksToExplore, + ScopeToAssignBlocks.find(WS)->second); + for (auto *MBB : BlocksToExplore) + if (WS->getDFSOut() == EjectionMap[MBB->getNumber()]) + EjectBlock(const_cast<MachineBasicBlock &>(*MBB)); + + BlocksToExplore.clear(); + } + } + + // Some artificial blocks may not have been ejected, meaning they're not + // connected to an actual legitimate scope. This can technically happen + // with things like the entry block. In theory, we shouldn't need to do + // anything for such out-of-scope blocks, but for the sake of being similar + // to VarLocBasedLDV, eject these too. + for (auto *MBB : ArtificialBlocks) + if (MOutLocs[MBB->getNumber()]) + EjectBlock(*MBB); + + return emitTransfers(AllVarsNumbering); +} + bool InstrRefBasedLDV::emitTransfers( - DenseMap<DebugVariable, unsigned> &AllVarsNumbering) { + DenseMap<DebugVariable, unsigned> &AllVarsNumbering) { // Go through all the transfers recorded in the TransferTracker -- this is // both the live-ins to a block, and any movements of values that happen // in the middle. @@ -2944,24 +3175,24 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF, assert(MaxNumBlocks >= 0); ++MaxNumBlocks; + initialSetup(MF); + MLocTransfer.resize(MaxNumBlocks); vlocs.resize(MaxNumBlocks, VLocTracker(OverlapFragments, EmptyExpr)); SavedLiveIns.resize(MaxNumBlocks); - initialSetup(MF); - produceMLocTransferFunction(MF, MLocTransfer, MaxNumBlocks); // Allocate and initialize two array-of-arrays for the live-in and live-out // machine values. The outer dimension is the block number; while the inner // dimension is a LocIdx from MLocTracker. - ValueIDNum **MOutLocs = new ValueIDNum *[MaxNumBlocks]; - ValueIDNum **MInLocs = new ValueIDNum *[MaxNumBlocks]; + FuncValueTable MOutLocs = std::make_unique<ValueTable[]>(MaxNumBlocks); + FuncValueTable MInLocs = std::make_unique<ValueTable[]>(MaxNumBlocks); unsigned NumLocs = MTracker->getNumLocs(); for (int i = 0; i < MaxNumBlocks; ++i) { // These all auto-initialize to ValueIDNum::EmptyValue - MOutLocs[i] = new ValueIDNum[NumLocs]; - MInLocs[i] = new ValueIDNum[NumLocs]; + MOutLocs[i] = std::make_unique<ValueIDNum[]>(NumLocs); + MInLocs[i] = std::make_unique<ValueIDNum[]>(NumLocs); } // Solve the machine value dataflow problem using the MLocTransfer function, @@ -2974,7 +3205,10 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF, // either live-through machine values, or PHIs. for (auto &DBG_PHI : DebugPHINumToValue) { // Identify unresolved block-live-ins. - ValueIDNum &Num = DBG_PHI.ValueRead; + if (!DBG_PHI.ValueRead) + continue; + + ValueIDNum &Num = *DBG_PHI.ValueRead; if (!Num.isPHI()) continue; @@ -2995,7 +3229,7 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF, MTracker->loadFromArray(MInLocs[CurBB], CurBB); CurInst = 1; for (auto &MI : MBB) { - process(MI, MOutLocs, MInLocs); + process(MI, MOutLocs.get(), MInLocs.get()); ++CurInst; } MTracker->reset(); @@ -3051,33 +3285,14 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF, << VarAssignCount << " variable assignments, exceeding limits.\n"); } else { - // Compute the extended ranges, iterating over scopes. There might be - // something to be said for ordering them by size/locality, but that's for - // the future. For each scope, solve the variable value problem, producing - // a map of variables to values in SavedLiveIns. - for (auto &P : ScopeToVars) { - buildVLocValueMap(ScopeToDILocation[P.first], P.second, - ScopeToAssignBlocks[P.first], SavedLiveIns, MOutLocs, MInLocs, - vlocs); - } - - // Using the computed value locations and variable values for each block, - // create the DBG_VALUE instructions representing the extended variable - // locations. - emitLocations(MF, SavedLiveIns, MOutLocs, MInLocs, AllVarsNumbering, *TPC); - - // Did we actually make any changes? If we created any DBG_VALUEs, then yes. - Changed = TTracker->Transfers.size() != 0; + // Optionally, solve the variable value problem and emit to blocks by using + // a lexical-scope-depth search. It should be functionally identical to + // the "else" block of this condition. + Changed = depthFirstVLocAndEmit( + MaxNumBlocks, ScopeToDILocation, ScopeToVars, ScopeToAssignBlocks, + SavedLiveIns, MOutLocs, MInLocs, vlocs, MF, AllVarsNumbering, *TPC); } - // Common clean-up of memory. - for (int Idx = 0; Idx < MaxNumBlocks; ++Idx) { - delete[] MOutLocs[Idx]; - delete[] MInLocs[Idx]; - } - delete[] MOutLocs; - delete[] MInLocs; - delete MTracker; delete TTracker; MTracker = nullptr; @@ -3092,6 +3307,7 @@ bool InstrRefBasedLDV::ExtendRanges(MachineFunction &MF, DebugPHINumToValue.clear(); OverlapFragments.clear(); SeenFragments.clear(); + SeenDbgPHIs.clear(); return Changed; } @@ -3193,9 +3409,10 @@ public: /// Machine location where any PHI must occur. LocIdx Loc; /// Table of live-in machine value numbers for blocks / locations. - ValueIDNum **MLiveIns; + const ValueTable *MLiveIns; - LDVSSAUpdater(LocIdx L, ValueIDNum **MLiveIns) : Loc(L), MLiveIns(MLiveIns) {} + LDVSSAUpdater(LocIdx L, const ValueTable *MLiveIns) + : Loc(L), MLiveIns(MLiveIns) {} void reset() { for (auto &Block : BlockMap) @@ -3352,11 +3569,28 @@ public: } // end namespace llvm -Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(MachineFunction &MF, - ValueIDNum **MLiveOuts, - ValueIDNum **MLiveIns, - MachineInstr &Here, - uint64_t InstrNum) { +Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs( + MachineFunction &MF, const ValueTable *MLiveOuts, + const ValueTable *MLiveIns, MachineInstr &Here, uint64_t InstrNum) { + assert(MLiveOuts && MLiveIns && + "Tried to resolve DBG_PHI before location " + "tables allocated?"); + + // This function will be called twice per DBG_INSTR_REF, and might end up + // computing lots of SSA information: memoize it. + auto SeenDbgPHIIt = SeenDbgPHIs.find(&Here); + if (SeenDbgPHIIt != SeenDbgPHIs.end()) + return SeenDbgPHIIt->second; + + Optional<ValueIDNum> Result = + resolveDbgPHIsImpl(MF, MLiveOuts, MLiveIns, Here, InstrNum); + SeenDbgPHIs.insert({&Here, Result}); + return Result; +} + +Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIsImpl( + MachineFunction &MF, const ValueTable *MLiveOuts, + const ValueTable *MLiveIns, MachineInstr &Here, uint64_t InstrNum) { // Pick out records of DBG_PHI instructions that have been observed. If there // are none, then we cannot compute a value number. auto RangePair = std::equal_range(DebugPHINumToValue.begin(), @@ -3368,17 +3602,24 @@ Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(MachineFunction &MF, if (LowerIt == UpperIt) return None; + // If any DBG_PHIs referred to a location we didn't understand, don't try to + // compute a value. There might be scenarios where we could recover a value + // for some range of DBG_INSTR_REFs, but at this point we can have high + // confidence that we've seen a bug. + auto DBGPHIRange = make_range(LowerIt, UpperIt); + for (const DebugPHIRecord &DBG_PHI : DBGPHIRange) + if (!DBG_PHI.ValueRead) + return None; + // If there's only one DBG_PHI, then that is our value number. if (std::distance(LowerIt, UpperIt) == 1) - return LowerIt->ValueRead; - - auto DBGPHIRange = make_range(LowerIt, UpperIt); + return *LowerIt->ValueRead; // Pick out the location (physreg, slot) where any PHIs must occur. It's // technically possible for us to merge values in different registers in each // block, but highly unlikely that LLVM will generate such code after register // allocation. - LocIdx Loc = LowerIt->ReadLoc; + LocIdx Loc = *LowerIt->ReadLoc; // We have several DBG_PHIs, and a use position (the Here inst). All each // DBG_PHI does is identify a value at a program position. We can treat each @@ -3397,7 +3638,7 @@ Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(MachineFunction &MF, // for the SSAUpdater. for (const auto &DBG_PHI : DBGPHIRange) { LDVSSABlock *Block = Updater.getSSALDVBlock(DBG_PHI.MBB); - const ValueIDNum &Num = DBG_PHI.ValueRead; + const ValueIDNum &Num = *DBG_PHI.ValueRead; AvailableValues.insert(std::make_pair(Block, Num.asU64())); } @@ -3431,7 +3672,7 @@ Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(MachineFunction &MF, // Define all the input DBG_PHI values in ValidatedValues. for (const auto &DBG_PHI : DBGPHIRange) { LDVSSABlock *Block = Updater.getSSALDVBlock(DBG_PHI.MBB); - const ValueIDNum &Num = DBG_PHI.ValueRead; + const ValueIDNum &Num = *DBG_PHI.ValueRead; ValidatedValues.insert(std::make_pair(Block, Num)); } @@ -3456,7 +3697,7 @@ Optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs(MachineFunction &MF, return None; ValueIDNum ValueToCheck; - ValueIDNum *BlockLiveOuts = MLiveOuts[PHIIt.first->BB.getNumber()]; + const ValueTable &BlockLiveOuts = MLiveOuts[PHIIt.first->BB.getNumber()]; auto VVal = ValidatedValues.find(PHIIt.first); if (VVal == ValidatedValues.end()) { |
