diff options
Diffstat (limited to 'llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp')
-rw-r--r-- | llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp | 208 |
1 files changed, 143 insertions, 65 deletions
diff --git a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp index 01e810e..cf724c1 100644 --- a/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp +++ b/llvm/lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.cpp @@ -630,12 +630,21 @@ public: if (!ShouldEmitDebugEntryValues) return false; + const DIExpression *DIExpr = Prop.DIExpr; + // We don't currently emit entry values for DBG_VALUE_LISTs. - if (Prop.IsVariadic) - return false; + if (Prop.IsVariadic) { + // If this debug value can be converted to be non-variadic, then do so; + // otherwise give up. + auto NonVariadicExpression = + DIExpression::convertToNonVariadicExpression(DIExpr); + if (!NonVariadicExpression) + return false; + DIExpr = *NonVariadicExpression; + } // Is the variable appropriate for entry values (i.e., is a parameter). - if (!isEntryValueVariable(Var, Prop.DIExpr)) + if (!isEntryValueVariable(Var, DIExpr)) return false; // Is the value assigned to this variable still the entry value? @@ -644,12 +653,12 @@ public: // Emit a variable location using an entry value expression. DIExpression *NewExpr = - DIExpression::prepend(Prop.DIExpr, DIExpression::EntryValue); + DIExpression::prepend(DIExpr, DIExpression::EntryValue); Register Reg = MTracker->LocIdxToLocID[Num.getLoc()]; MachineOperand MO = MachineOperand::CreateReg(Reg, false); PendingDbgValues.push_back( - emitMOLoc(MO, Var, {NewExpr, Prop.Indirect, Prop.IsVariadic})); + emitMOLoc(MO, Var, {NewExpr, Prop.Indirect, false})); return true; } @@ -809,8 +818,8 @@ public: for (const auto &Var : ActiveMLocIt->second) { auto ActiveVLocIt = ActiveVLocs.find(Var); // Re-state the variable location: if there's no replacement then NewLoc - // is None and a $noreg DBG_VALUE will be created. Otherwise, a DBG_VALUE - // identifying the alternative location will be emitted. + // is std::nullopt and a $noreg DBG_VALUE will be created. Otherwise, a + // DBG_VALUE identifying the alternative location will be emitted. const DbgValueProperties &Properties = ActiveVLocIt->second.Properties; // Produce the new list of debug ops - an empty list if no new location @@ -1418,39 +1427,14 @@ bool InstrRefBasedLDV::transferDebugValue(const MachineInstr &MI) { 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).getInstrRefInstrIndex(); - unsigned OpNo = MI.getDebugOperand(0).getInstrRefOpIndex(); - - 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(); - +std::optional<ValueIDNum> 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 = @@ -1586,14 +1570,64 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, } } - // We, we have a value number or std::nullopt. 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); + 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<DbgOpID> DbgOpIDs; - if (NewID) - DbgOpIDs.push_back(DbgOpStore.insert(*NewID)); + for (const MachineOperand &MO : MI.debug_operands()) { + if (!MO.isDbgInstrRef()) { + assert(!MO.isReg() && "DBG_INSTR_REF should not contain registers"); + DbgOpID ConstOpID = DbgOpStore.insert(DbgOp(MO)); + DbgOpIDs.push_back(ConstOpID); + continue; + } + + unsigned InstNo = MO.getInstrRefInstrIndex(); + unsigned OpNo = MO.getInstrRefOpIndex(); + + // Default machine value number is <None> -- if no instruction defines + // the corresponding value, it must have been optimized out. + std::optional<ValueIDNum> NewID = + getValueForInstrRef(InstNo, OpNo, MI, MLiveOuts, MLiveIns); + // We have a value number or std::nullopt. 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); @@ -1602,40 +1636,84 @@ bool InstrRefBasedLDV::transferDebugInstrRef(MachineInstr &MI, if (!TTracker) return true; + // Fetch the concrete DbgOps now, as we will need them later. + SmallVector<DbgOp> 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). - TransferTracker::LocationAndQuality FoundLoc; + SmallDenseMap<ValueIDNum, TransferTracker::LocationAndQuality> FoundLocs; + SmallVector<ValueIDNum> ValuesToFind; + // Initialized the preferred-location map with illegal locations, to be + // filled in later. + for (const DbgOp &Op : DbgOps) { + if (!Op.IsConst) + if (FoundLocs.insert({Op.ID, TransferTracker::LocationAndQuality()}) + .second) + ValuesToFind.push_back(Op.ID); + } + for (auto Location : MTracker->locations()) { LocIdx CurL = Location.Idx; ValueIDNum ID = MTracker->readMLoc(CurL); - if (NewID && ID == NewID) { - // If this is the first location with that value, pick it. Otherwise, - // consider whether it's a "longer term" location. - std::optional<TransferTracker::LocationQuality> ReplacementQuality = - TTracker->getLocQualityIfBetter(CurL, FoundLoc.getQuality()); - if (ReplacementQuality) { - FoundLoc = - TransferTracker::LocationAndQuality(CurL, *ReplacementQuality); - if (FoundLoc.isBest()) + auto ValueToFindIt = find(ValuesToFind, ID); + if (ValueToFindIt == ValuesToFind.end()) + continue; + auto &Previous = FoundLocs.find(ID)->second; + // If this is the first location with that value, pick it. Otherwise, + // consider whether it's a "longer term" location. + std::optional<TransferTracker::LocationQuality> ReplacementQuality = + TTracker->getLocQualityIfBetter(CurL, Previous.getQuality()); + if (ReplacementQuality) { + Previous = TransferTracker::LocationAndQuality(CurL, *ReplacementQuality); + if (Previous.isBest()) { + ValuesToFind.erase(ValueToFindIt); + if (ValuesToFind.empty()) break; } } } SmallVector<ResolvedDbgOp> NewLocs; - if (!FoundLoc.isIllegal()) - NewLocs.push_back(FoundLoc.getLoc()); + for (const DbgOp &DbgOp : DbgOps) { + if (DbgOp.IsConst) { + NewLocs.push_back(DbgOp.MO); + continue; + } + LocIdx FoundLoc = FoundLocs.find(DbgOp.ID)->second.getLoc(); + 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.isIllegal() && NewID && NewID->getBlock() == CurBB && - NewID->getInst() > CurInst) { - SmallVector<DbgOp> UseBeforeDefLocs; - UseBeforeDefLocs.push_back(*NewID); - TTracker->addUseBeforeDef(V, {MI.getDebugExpression(), false, true}, - 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.getLoc(); + 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. @@ -4004,13 +4082,13 @@ std::optional<ValueIDNum> InstrRefBasedLDV::resolveDbgPHIs( // 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); + auto SeenDbgPHIIt = SeenDbgPHIs.find(std::make_pair(&Here, InstrNum)); if (SeenDbgPHIIt != SeenDbgPHIs.end()) return SeenDbgPHIIt->second; std::optional<ValueIDNum> Result = resolveDbgPHIsImpl(MF, MLiveOuts, MLiveIns, Here, InstrNum); - SeenDbgPHIs.insert({&Here, Result}); + SeenDbgPHIs.insert({std::make_pair(&Here, InstrNum), Result}); return Result; } |