diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h @@ -1187,6 +1187,11 @@ Optional extractSpillBaseRegAndOffset(const MachineInstr &MI); + Optional getValueForInstrRef(unsigned InstNo, unsigned OpNo, + MachineInstr &MI, + const ValueTable *MLiveOuts, + const ValueTable *MLiveIns); + /// Observe a single instruction while stepping through a block. void process(MachineInstr &MI, const ValueTable *MLiveOuts, const ValueTable *MLiveIns); diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -1373,39 +1373,14 @@ return true; } -bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, - 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 && !TTracker) - return false; - - unsigned InstNo = MI.getDebugOperand(0).getInstrIdx(); - unsigned OpNo = MI.getDebugOperand(0).getOpIdx(); - - const DILocalVariable *Var = MI.getDebugVariable(); - const DIExpression *Expr = MI.getDebugExpression(); - const DILocation *DebugLoc = MI.getDebugLoc(); - const DILocation *InlinedAt = DebugLoc->getInlinedAt(); - assert(Var->isValidLocationForIntrinsic(DebugLoc) && - "Expected inlined-at fields to agree"); - - DebugVariable V(Var, Expr, InlinedAt); - - auto *Scope = LS.findLexicalScope(MI.getDebugLoc().get()); - if (Scope == nullptr) - return true; // Handled by doing nothing. This variable is never in scope. - - const MachineFunction &MF = *MI.getParent()->getParent(); - +Optional InstrRefBasedLDV::getValueForInstrRef( + unsigned InstNo, unsigned OpNo, MachineInstr &MI, + const ValueTable *MLiveOuts, const ValueTable *MLiveIns) { // Various optimizations may have happened to the value during codegen, // recorded in the value substitution table. Apply any substitutions to // the instruction / operand number in this DBG_INSTR_REF, and collect // any subregister extractions performed during optimization. + const MachineFunction &MF = *MI.getParent()->getParent(); // Create dummy substitution with Src set, for lookup. auto SoughtSub = @@ -1541,14 +1516,66 @@ } } - // 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 - // for DBG_INSTR_REFs as DBG_VALUEs (just, the former can refer to values that - // aren't immediately available). - DbgValueProperties Properties(Expr, false, false); + return NewID; +} + +bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, + 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 && !TTracker) + return false; + + const DILocalVariable *Var = MI.getDebugVariable(); + const DIExpression *Expr = MI.getDebugExpression(); + const DILocation *DebugLoc = MI.getDebugLoc(); + const DILocation *InlinedAt = DebugLoc->getInlinedAt(); + assert(Var->isValidLocationForIntrinsic(DebugLoc) && + "Expected inlined-at fields to agree"); + + DebugVariable V(Var, Expr, InlinedAt); + + auto *Scope = LS.findLexicalScope(MI.getDebugLoc().get()); + if (Scope == nullptr) + return true; // Handled by doing nothing. This variable is never in scope. + SmallVector DbgOpIDs; - if (NewID) + for (const MachineOperand &MO : MI.debug_operands()) { + if (!MO.isDbgInstrRef()) { + // TODO: A DBG_INSTR_REF could contain a frame index, which would be a + // register at this point. + assert(!MO.isReg() && "DBG_INSTR_REF should not contain registers"); + DbgOpID ConstOpID = DbgOpStore.insert(DbgOp(MO)); + DbgOpIDs.push_back(ConstOpID); + continue; + } + + unsigned InstNo = MO.getInstrIdx(); + unsigned OpNo = MO.getOpIdx(); + + // Default machine value number is -- if no instruction defines + // the corresponding value, it must have been optimized out. + Optional NewID = + getValueForInstrRef(InstNo, OpNo, MI, MLiveOuts, MLiveIns); + // We have a value number or None. If the latter, then kill the entire debug + // value. + if (NewID) { DbgOpIDs.push_back(DbgOpStore.insert(*NewID)); + } else { + DbgOpIDs.clear(); + break; + } + } + + // We have a DbgOpID for every value or for none. Tell the variable value + // tracker about 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 aren't immediately available). + DbgValueProperties Properties(Expr, false, true); if (VTracker) VTracker->defVar(MI, Properties, DbgOpIDs); @@ -1557,44 +1584,82 @@ if (!TTracker) return true; + // Fetch the concrete DbgOps now, as we will need them later. + SmallVector DbgOps; + for (DbgOpID OpID : DbgOpIDs) { + DbgOps.push_back(DbgOpStore.find(OpID)); + } + // Pick a location for the machine value number, if such a location exists. // (This information could be stored in TransferTracker to make it faster). - Optional FoundLoc; + DenseMap FoundLocs; + // Initialized the preferred-location map with illegal locations, to be + // filled in later. + for (DbgOp DbgOp : DbgOps) { + if (!DbgOp.IsConst) + FoundLocs.insert({DbgOp.ID, LocIdx::MakeIllegalLoc()}); + } + for (auto Location : MTracker->locations()) { LocIdx CurL = Location.Idx; ValueIDNum ID = MTracker->readMLoc(CurL); - if (NewID && ID == NewID) { + if (!FoundLocs.count(ID)) + continue; + auto FoundLocIt = FoundLocs.find(ID); // If this is the first location with that value, pick it. Otherwise, // consider whether it's a "longer term" location. - if (!FoundLoc) { - FoundLoc = CurL; + if (FoundLocIt->second.isIllegal()) { + FoundLocIt->second = CurL; continue; } if (MTracker->isSpill(CurL)) - FoundLoc = CurL; // Spills are a longer term location. - else if (!MTracker->isSpill(*FoundLoc) && - !MTracker->isSpill(CurL) && - !isCalleeSaved(*FoundLoc) && + FoundLocIt->second = CurL; // Spills are a longer term location. + else if (!MTracker->isSpill(FoundLocIt->second) && + !MTracker->isSpill(CurL) && !isCalleeSaved(FoundLocIt->second) && isCalleeSaved(CurL)) - FoundLoc = CurL; // Callee saved regs are longer term than normal. - } + FoundLocIt->second = + CurL; // Callee saved regs are longer term than normal. } SmallVector NewLocs; - if (FoundLoc) - NewLocs.push_back(*FoundLoc); + for (DbgOp DbgOp : DbgOps) { + if (DbgOp.IsConst) { + NewLocs.push_back(DbgOp.MO); + continue; + } + LocIdx FoundLoc = FoundLocs.find(DbgOp.ID)->second; + if (FoundLoc.isIllegal()) { + NewLocs.clear(); + break; + } + NewLocs.push_back(FoundLoc); + } // Tell transfer tracker that the variable value has changed. TTracker->redefVar(MI, Properties, NewLocs); - // 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. - if (!FoundLoc && NewID && NewID->getBlock() == CurBB && - NewID->getInst() > CurInst) { - SmallVector UseBeforeDefLocs; - UseBeforeDefLocs.push_back(*NewID); - TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false, false}, - UseBeforeDefLocs, NewID->getInst()); + // If there were values with no location, but all such values are defined in + // later instructions in this block, this is a block-local use-before-def. + if (!DbgOps.empty() && NewLocs.empty()) { + bool IsValidUseBeforeDef = true; + uint64_t LastUseBeforeDef = 0; + for (auto ValueLoc : FoundLocs) { + ValueIDNum NewID = ValueLoc.first; + LocIdx FoundLoc = ValueLoc.second; + if (!FoundLoc.isIllegal()) + continue; + // If we have an value with no location that is not defined in this block, + // then it has no location in this block, leaving this value undefined. + if (NewID.getBlock() != CurBB || NewID.getInst() <= CurInst) { + IsValidUseBeforeDef = false; + break; + } + LastUseBeforeDef = std::max(LastUseBeforeDef, NewID.getInst()); + } + if (IsValidUseBeforeDef) { + TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false, true}, + DbgOps, LastUseBeforeDef); + } } // Produce a DBG_VALUE representing what this DBG_INSTR_REF meant.