Index: llvm/lib/CodeGen/LiveDebugVariables.cpp =================================================================== --- llvm/lib/CodeGen/LiveDebugVariables.cpp +++ llvm/lib/CodeGen/LiveDebugVariables.cpp @@ -95,31 +95,32 @@ enum : unsigned { UndefLocNo = ~0U }; -/// Describes a location by number along with some flags about the original -/// usage of the location. +/// Describes a location by number. Keeps track of the original DIExpression +/// to prevent adjacent locations coalescing in the interval map if they +/// don't have the same expression. In addition, a nullptr Expression and undef +/// location represents a dummy blocker value. This is acts like an undef except +/// it will not be emitted as a DBG_VALUE. class DbgValueLocation { public: - DbgValueLocation(unsigned LocNo) - : LocNo(LocNo) { - static_assert(sizeof(*this) == sizeof(unsigned), "bad bitfield packing"); - assert(locNo() == LocNo && "location truncation"); - } + DbgValueLocation(unsigned LocNo, const DIExpression *Expr) + : LocNo(LocNo), Expression(Expr) {} - DbgValueLocation() : LocNo(0) {} + DbgValueLocation() : LocNo(0), Expression(nullptr) {} - unsigned locNo() const { - // Fix up the undef location number, which gets truncated. - return LocNo == INT_MAX ? UndefLocNo : LocNo; - } - bool isUndef() const { return locNo() == UndefLocNo; } + /// May return nullptr if this is a dummy value. + const DIExpression *getExpression() const { return Expression; } + + unsigned getLocNo() const { return LocNo; } + + bool isUndef() const { return getLocNo() == UndefLocNo; } DbgValueLocation changeLocNo(unsigned NewLocNo) const { - return DbgValueLocation(NewLocNo); + return DbgValueLocation(NewLocNo, Expression); } friend inline bool operator==(const DbgValueLocation &LHS, const DbgValueLocation &RHS) { - return LHS.LocNo == RHS.LocNo; + return LHS.LocNo == RHS.LocNo && LHS.Expression == RHS.Expression; } friend inline bool operator!=(const DbgValueLocation &LHS, @@ -129,6 +130,7 @@ private: unsigned LocNo; + const DIExpression *Expression; }; /// Map of where a user value is live, and its location. @@ -139,26 +141,21 @@ using SpillOffsetMap = DenseMap; namespace { +/// Return a MO which represents a DBG_VALUE undef. +static MachineOperand getUndefMO() { + MachineOperand MO = MachineOperand::CreateReg(0U, false); + MO.setIsDebug(); + return MO; +} class LDVImpl; +class UserValueGroup; /// A user value is a part of a debug info user variable. /// /// A DBG_VALUE instruction notes that (a sub-register of) a virtual register /// holds part of a user variable. The part is identified by a byte offset. -/// -/// UserValues are grouped into equivalence classes for easier searching. Two -/// user values are related if they refer to the same variable, or if they are -/// held by the same virtual register. The equivalence class is the transitive -/// closure of that relation. class UserValue { - const DILocalVariable *Variable; ///< The debug info variable we are part of. - const DIExpression *Expression; ///< Any complex address expression. - DebugLoc dl; ///< The debug location for the variable. This is - ///< used by dwarf writer to find lexical scope. - UserValue *leader; ///< Equivalence class leader. - UserValue *next = nullptr; ///< Next value in equivalence class, or null. - /// Numbered locations referenced by locmap. SmallVector locations; @@ -166,7 +163,8 @@ LocMap locInts; /// Insert a DBG_VALUE into MBB at Idx for LocNo. - void insertDebugValue(MachineBasicBlock *MBB, SlotIndex StartIdx, + void insertDebugValue(const DIVariable *Variable, const DebugLoc &DebugLoc, + MachineBasicBlock *MBB, SlotIndex StartIdx, SlotIndex StopIdx, DbgValueLocation Loc, bool Spilled, unsigned SpillOffset, LiveIntervals &LIS, const TargetInstrInfo &TII, @@ -178,50 +176,11 @@ LiveIntervals &LIS); public: - /// Create a new UserValue. - UserValue(const DILocalVariable *var, const DIExpression *expr, DebugLoc L, - LocMap::Allocator &alloc) - : Variable(var), Expression(expr), dl(std::move(L)), leader(this), - locInts(alloc) {} - - /// Get the leader of this value's equivalence class. - UserValue *getLeader() { - UserValue *l = leader; - while (l != l->leader) - l = l->leader; - return leader = l; - } - - /// Return the next UserValue in the equivalence class. - UserValue *getNext() const { return next; } - - /// Does this UserValue match the parameters? - bool match(const DILocalVariable *Var, const DIExpression *Expr, - const DILocation *IA) const { - // FIXME: The fragment should be part of the equivalence class, but not - // other things in the expression like stack values. - return Var == Variable && Expr == Expression && dl->getInlinedAt() == IA; - } + UserValue(const UserValue &) = delete; - /// Merge equivalence classes. - static UserValue *merge(UserValue *L1, UserValue *L2) { - L2 = L2->getLeader(); - if (!L1) - return L2; - L1 = L1->getLeader(); - if (L1 == L2) - return L1; - // Splice L2 before L1's members. - UserValue *End = L2; - while (End->next) { - End->leader = L1; - End = End->next; - } - End->leader = L1; - End->next = L1->next; - L1->next = L2; - return L1; - } + /// Create a new UserValue. + UserValue(const DILocalVariable *var, DebugLoc L, LocMap::Allocator &alloc) + : locInts(alloc) {} /// Return the location number that matches Loc. /// @@ -261,7 +220,7 @@ // Bail out if LocNo still is used. for (LocMap::const_iterator I = locInts.begin(); I.valid(); ++I) { DbgValueLocation Loc = I.value(); - if (Loc.locNo() == LocNo) + if (Loc.getLocNo() == LocNo) return; } // Remove the entry in the locations vector, and adjust all references to @@ -269,8 +228,8 @@ locations.erase(locations.begin() + LocNo); for (LocMap::iterator I = locInts.begin(); I.valid(); ++I) { DbgValueLocation Loc = I.value(); - if (!Loc.isUndef() && Loc.locNo() > LocNo) - I.setValueUnchecked(Loc.changeLocNo(Loc.locNo() - 1)); + if (!Loc.isUndef() && Loc.getLocNo() > LocNo) + I.setValueUnchecked(Loc.changeLocNo(Loc.getLocNo() - 1)); } } @@ -278,8 +237,9 @@ void mapVirtRegs(LDVImpl *LDV); /// Add a definition point to this value. - void addDef(SlotIndex Idx, const MachineOperand &LocMO) { - DbgValueLocation Loc(getLocationNo(LocMO)); + void addDef(SlotIndex Idx, const MachineOperand &LocMO, + const DIExpression *Expr) { + DbgValueLocation Loc(getLocationNo(LocMO), Expr); // Add a singular (Idx,Idx) -> Loc mapping. LocMap::iterator I = locInts.find(Idx); if (!I.valid() || I.start() != Idx) @@ -289,6 +249,9 @@ I.setValue(Loc); } + /// Add a fake definition point which prevents adjacent locations coalescing. + void addBlocker(SlotIndex Idx) { addDef(Idx, getUndefMO(), nullptr); } + /// Extend the current definition as far as possible down. /// /// Stop when meeting an existing def or when leaving the live @@ -312,20 +275,22 @@ /// any of the copies are available at the kill points, and add defs if /// possible. /// + /// \param UVG Block overlapping fragment definition intervals. /// \param LI Scan for copies of the value in LI->reg. /// \param LocNo Location number of LI->reg. /// \param Kills Points where the range of LocNo could be extended. /// \param [in,out] NewDefs Append (Idx, LocNo) of inserted defs here. void addDefsFromCopies( - LiveInterval *LI, unsigned LocNo, + UserValueGroup &UVG, LiveInterval *LI, DbgValueLocation Loc, const SmallVectorImpl &Kills, SmallVectorImpl> &NewDefs, MachineRegisterInfo &MRI, LiveIntervals &LIS); /// Compute the live intervals of all locations after collecting all their /// def points. - void computeIntervals(MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, - LiveIntervals &LIS, LexicalScopes &LS); + void computeIntervals(UserValueGroup &UVG, MachineRegisterInfo &MRI, + const TargetRegisterInfo &TRI, LiveIntervals &LIS, + LexicalScopes &LS); /// Replace OldReg ranges with NewRegs ranges where NewRegs is /// live. Returns true if any changes were made. @@ -341,13 +306,68 @@ SpillOffsetMap &SpillOffsets); /// Recreate DBG_VALUE instruction from data structures. - void emitDebugValues(VirtRegMap *VRM, LiveIntervals &LIS, + void emitDebugValues(const DIVariable *Variable, const DebugLoc &DebugLoc, + VirtRegMap *VRM, LiveIntervals &LIS, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const SpillOffsetMap &SpillOffsets); - /// Return DebugLoc of this UserValue. - DebugLoc getDebugLoc() { return dl;} + void print(raw_ostream &, const TargetRegisterInfo *); + void print(raw_ostream &, const DIVariable *, const DebugLoc &, + const TargetRegisterInfo *); +}; + +/// A user value group contains the set of UserValues which +/// refer to the same source variable in the same inlining scope. +class UserValueGroup { + using FragmentInfo = DIExpression::FragmentInfo; + + /// A DefaultFragment covers the full debug variable. + static const FragmentInfo DefaultFragment; + + /// The debug info variable we are part of. + const DILocalVariable *Variable; + + /// The debug location for the variable. + DebugLoc DL; + + /// All allocated UserValues for this group. + SmallVector, 4> UserValues; + + /// Fragment for each UserValue in this->UserValues. + /// 'Empty' fragments are converted to UserValueGroup::DefaultFragments. + SmallVector Fragments; + + /// Allocator required for our UserValues. + LocMap::Allocator &Allocator; + + /// Get Fragment from Expr, return DefaultFragment if there isn't one. + static FragmentInfo getFragment(const DIExpression *Expr); + +public: + using iterator = SmallVectorImpl>::iterator; + + UserValueGroup() = delete; + UserValueGroup(const DILocalVariable *Var, DebugLoc L, + LocMap::Allocator &MapAllocator) + : Variable(Var), DL(std::move(L)), Allocator(MapAllocator) {} + + /// Add a definition point to and block UserValues with overlapping fragments. + void addDef(SlotIndex Idx, const MachineOperand &LocMO, + const DIExpression *Expr); + + /// Block interval map for UserValues overlapping with fragment in Expr. + void addBlockerForOverlaps(SlotIndex Idx, const DIExpression *Expr); + + const DIVariable *getVariable() const { return Variable; } + + DebugLoc getDebugLoc() const { return DL; } + + /// Iterate over UserValues in this group. + iterator begin() { return UserValues.begin(); } + + /// Iterate over UserValues in this group. + iterator end() { return UserValues.end(); } void print(raw_ostream &, const TargetRegisterInfo *); }; @@ -398,25 +418,28 @@ bool ModifiedMF = false; /// All allocated UserValue instances. - SmallVector, 8> userValues; + SmallVector, 8> userValueGroups; /// All allocated UserLabel instances. SmallVector, 2> userLabels; - /// Map virtual register to eq class leader. - using VRMap = DenseMap; - VRMap virtRegToEqClass; + /// Map virtual register to UserValues which use it. + using VRMap = std::unordered_map>; + VRMap VirtRegToUserVals; - /// Map user variable to eq class leader. - using UVMap = DenseMap; - UVMap userVarMap; + /// Map unique UserValue identity to UserValueGroup. + /// UserValues are grouped into the same UserValueGroup if they refer to the + /// same Variable in the same scope. + using UserValueGroupId = std::pair; + using UVMap = DenseMap; + UVMap UserVarMap; /// Find or create a UserValue. - UserValue *getUserValue(const DILocalVariable *Var, const DIExpression *Expr, - const DebugLoc &DL); + UserValueGroup *getUserValueGroup(const DILocalVariable *Var, + const DebugLoc &DL); - /// Find the EC leader for VirtReg or null. - UserValue *lookupVirtReg(unsigned VirtReg); + /// Find the UserValues for VirtReg or null. + SmallVectorImpl *lookupVirtReg(unsigned VirtReg); /// Add DBG_VALUE instruction to our maps. /// @@ -454,10 +477,10 @@ /// Release all memory. void clear() { MF = nullptr; - userValues.clear(); + userValueGroups.clear(); userLabels.clear(); - virtRegToEqClass.clear(); - userVarMap.clear(); + VirtRegToUserVals.clear(); + UserVarMap.clear(); // Make sure we call emitDebugValues if the machine function was modified. assert((!ModifiedMF || EmitDone) && "Dbg values are not emitted in LDV"); @@ -465,8 +488,8 @@ ModifiedMF = false; } - /// Map virtual register to an equivalence class. - void mapVirtReg(unsigned VirtReg, UserValue *EC); + /// Map virtual register to a UserValue. + void mapVirtReg(unsigned VirtReg, UserValue *UV); /// Replace all references to OldReg with NewRegs. void splitRegister(unsigned OldReg, ArrayRef NewRegs); @@ -526,17 +549,22 @@ } } -void UserValue::print(raw_ostream &OS, const TargetRegisterInfo *TRI) { +void UserValue::print(raw_ostream &OS, const DIVariable *V, const DebugLoc &DL, + const TargetRegisterInfo *TRI) { OS << "!\""; - printExtendedName(OS, Variable, dl); + printExtendedName(OS, V, DL); + OS << "\""; + print(OS, TRI); +} - OS << "\"\t"; +void UserValue::print(raw_ostream &OS, const TargetRegisterInfo *TRI) { + OS << "\t"; for (LocMap::const_iterator I = locInts.begin(); I.valid(); ++I) { OS << " [" << I.start() << ';' << I.stop() << "):"; if (I.value().isUndef()) OS << "undef"; else { - OS << I.value().locNo(); + OS << I.value().getLocNo() << " " << *I.value().getExpression(); } } for (unsigned i = 0, e = locations.size(); i != e; ++i) { @@ -546,6 +574,11 @@ OS << '\n'; } +void UserValueGroup::print(raw_ostream &OS, const TargetRegisterInfo *TRI) { + for (auto &UV : UserValues) + UV->print(OS, Variable, DL, TRI); +} + void UserLabel::print(raw_ostream &OS, const TargetRegisterInfo *TRI) { OS << "!\""; printExtendedName(OS, Label, dl); @@ -557,8 +590,8 @@ void LDVImpl::print(raw_ostream &OS) { OS << "********** DEBUG VARIABLES **********\n"; - for (auto &userValue : userValues) - userValue->print(OS, TRI); + for (auto &UVG : userValueGroups) + UVG->print(OS, TRI); OS << "********** DEBUG LABELS **********\n"; for (auto &userLabel : userLabels) userLabel->print(OS, TRI); @@ -572,33 +605,72 @@ LDV->mapVirtReg(locations[i].getReg(), this); } -UserValue *LDVImpl::getUserValue(const DILocalVariable *Var, - const DIExpression *Expr, const DebugLoc &DL) { - UserValue *&Leader = userVarMap[Var]; - if (Leader) { - UserValue *UV = Leader->getLeader(); - Leader = UV; - for (; UV; UV = UV->getNext()) - if (UV->match(Var, Expr, DL->getInlinedAt())) - return UV; +const DIExpression::FragmentInfo UserValueGroup::DefaultFragment = { + std::numeric_limits::max(), std::numeric_limits::min()}; + +UserValueGroup::FragmentInfo +UserValueGroup::getFragment(const DIExpression *Expr) { + return Expr->getFragmentInfo().getValueOr(DefaultFragment); +} + +void UserValueGroup::addDef(SlotIndex Idx, const MachineOperand &LocMO, + const DIExpression *Expr) { + FragmentInfo Fragment = UserValueGroup::getFragment(Expr); + // Search for exact matching Fragment. + UserValue *ExactMatch = nullptr; + for (unsigned i = 0; i < Fragments.size(); ++i) { + if (Fragments[i] == Fragment) + ExactMatch = UserValues[i].get(); + // Add blocker def for any overlaps. + else if (DIExpression::fragmentsOverlap(Fragments[i], Fragment)) + UserValues[i]->addBlocker(Idx); + } + + // Create a new UserValue if there wans't one for this Fragment. + if (!ExactMatch) { + UserValues.push_back(std::make_unique(Variable, DL, Allocator)); + ExactMatch = UserValues.back().get(); + Fragments.push_back(Fragment); + } + + // Add def for the fragment range. + ExactMatch->addDef(Idx, LocMO, Expr); +} + +void UserValueGroup::addBlockerForOverlaps(SlotIndex Idx, + const DIExpression *Expr) { + FragmentInfo Fragment = UserValueGroup::getFragment(Expr); + for (unsigned i = 0; i < Fragments.size(); ++i) { + if (!DIExpression::fragmentsOverlap(Fragments[i], Fragment)) + continue; + if (Fragments[i] == Fragment) + continue; + UserValues[i]->addBlocker(Idx); } +} + +UserValueGroup *LDVImpl::getUserValueGroup(const DILocalVariable *Var, + const DebugLoc &DL) { + auto Ident = std::make_pair(Var, DL->getInlinedAt()); + UserValueGroup *&UVEntry = UserVarMap[Ident]; - userValues.push_back( - std::make_unique(Var, Expr, DL, allocator)); - UserValue *UV = userValues.back().get(); - Leader = UserValue::merge(Leader, UV); - return UV; + if (UVEntry) + return UVEntry; + + userValueGroups.push_back( + std::make_unique(Var, DL, allocator)); + return UVEntry = userValueGroups.back().get(); } -void LDVImpl::mapVirtReg(unsigned VirtReg, UserValue *EC) { +void LDVImpl::mapVirtReg(unsigned VirtReg, UserValue *UV) { assert(Register::isVirtualRegister(VirtReg) && "Only map VirtRegs"); - UserValue *&Leader = virtRegToEqClass[VirtReg]; - Leader = UserValue::merge(Leader, EC); + VirtRegToUserVals[VirtReg].push_back(UV); } -UserValue *LDVImpl::lookupVirtReg(unsigned VirtReg) { - if (UserValue *UV = virtRegToEqClass.lookup(VirtReg)) - return UV->getLeader(); +SmallVectorImpl *LDVImpl::lookupVirtReg(unsigned VirtReg) { + VRMap::iterator Itr = VirtRegToUserVals.find(VirtReg); + if (Itr != VirtRegToUserVals.end()) + return &Itr->second; return nullptr; } @@ -649,14 +721,11 @@ "LiveDebugVariables"); const DILocalVariable *Var = MI.getDebugVariable(); const DIExpression *Expr = MI.getDebugExpression(); - UserValue *UV = - getUserValue(Var, Expr, MI.getDebugLoc()); + UserValueGroup *UVG = getUserValueGroup(Var, MI.getDebugLoc()); if (!Discard) - UV->addDef(Idx, MI.getOperand(0)); + UVG->addDef(Idx, MI.getOperand(0), Expr); else { - MachineOperand MO = MachineOperand::CreateReg(0U, false); - MO.setIsDebug(); - UV->addDef(Idx, MO); + UVG->addDef(Idx, getUndefMO(), Expr); } return true; } @@ -764,7 +833,7 @@ } void UserValue::addDefsFromCopies( - LiveInterval *LI, unsigned LocNo, + UserValueGroup &UVG, LiveInterval *LI, DbgValueLocation Loc, const SmallVectorImpl &Kills, SmallVectorImpl> &NewDefs, MachineRegisterInfo &MRI, LiveIntervals &LIS) { @@ -794,7 +863,7 @@ // it, or we are looking at a wrong value of LI. SlotIndex Idx = LIS.getInstructionIndex(*MI); LocMap::iterator I = locInts.find(Idx.getRegSlot(true)); - if (!I.valid() || I.value().locNo() != LocNo) + if (!I.valid() || I.value().getLocNo() != Loc.getLocNo()) continue; if (!LIS.hasInterval(DstReg)) @@ -828,15 +897,16 @@ MachineInstr *CopyMI = LIS.getInstructionFromIndex(DstVNI->def); assert(CopyMI && CopyMI->isCopy() && "Bad copy value"); unsigned LocNo = getLocationNo(CopyMI->getOperand(0)); - DbgValueLocation NewLoc(LocNo); + DbgValueLocation NewLoc = Loc.changeLocNo(LocNo); I.insert(Idx, Idx.getNextSlot(), NewLoc); NewDefs.push_back(std::make_pair(Idx, NewLoc)); + UVG.addBlockerForOverlaps(Idx, Loc.getExpression()); break; } } } -void UserValue::computeIntervals(MachineRegisterInfo &MRI, +void UserValue::computeIntervals(UserValueGroup &UVG, MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI, LiveIntervals &LIS, LexicalScopes &LS) { SmallVector, 16> Defs; @@ -850,7 +920,7 @@ for (unsigned i = 0; i != Defs.size(); ++i) { SlotIndex Idx = Defs[i].first; DbgValueLocation Loc = Defs[i].second; - const MachineOperand &LocMO = locations[Loc.locNo()]; + const MachineOperand &LocMO = locations[Loc.getLocNo()]; if (!LocMO.isReg()) { extendDef(Idx, Loc, nullptr, nullptr, nullptr, LIS); @@ -876,7 +946,7 @@ // sub-register in that regclass). For now, simply skip handling copies if // a sub-register is involved. if (LI && !LocMO.getSubReg()) - addDefsFromCopies(LI, Loc.locNo(), Kills, Defs, MRI, LIS); + addDefsFromCopies(UVG, LI, Loc, Kills, Defs, MRI, LIS); continue; } @@ -894,7 +964,7 @@ // causing extra unnecessary DBG_VALUEs to be emitted. To prevent // this, trim the intervals to the lexical scope. - LexicalScope *Scope = LS.findLexicalScope(dl); + LexicalScope *Scope = LS.findLexicalScope(UVG.getDebugLoc()); if (!Scope) return; @@ -949,13 +1019,18 @@ I.setStopUnchecked(PrevEnd); } + void LDVImpl::computeIntervals() { LexicalScopes LS; LS.initialize(*MF); - for (unsigned i = 0, e = userValues.size(); i != e; ++i) { - userValues[i]->computeIntervals(MF->getRegInfo(), *TRI, *LIS, LS); - userValues[i]->mapVirtRegs(this); + for (auto &UVG : userValueGroups) { + for (const auto &UV : *UVG) { + UV->computeIntervals(*UVG, MF->getRegInfo(), *TRI, *LIS, LS); + // We can map regs now because only blockers can be added to this UV + // from others in the group in computeIntervals. + UV->mapVirtRegs(this); + } } } @@ -1043,7 +1118,7 @@ break; // Now LII->end > LocMapI.start(). Do we have an overlap? - if (LocMapI.value().locNo() == OldLocNo && LII->start < LocMapI.stop()) { + if (LocMapI.value().getLocNo() == OldLocNo && LII->start < LocMapI.stop()) { // Overlapping correct location. Allocate NewLocNo now. if (NewLocNo == UndefLocNo) { MachineOperand MO = MachineOperand::CreateReg(LI->reg, false); @@ -1126,16 +1201,18 @@ void LDVImpl::splitRegister(unsigned OldReg, ArrayRef NewRegs) { bool DidChange = false; - for (UserValue *UV = lookupVirtReg(OldReg); UV; UV = UV->getNext()) - DidChange |= UV->splitRegister(OldReg, NewRegs, *LIS); + if (auto *UserVals = lookupVirtReg(OldReg)) + for (auto *UV : *UserVals) + DidChange |= UV->splitRegister(OldReg, NewRegs, *LIS); if (!DidChange) return; // Map all of the new virtual registers. - UserValue *UV = lookupVirtReg(OldReg); - for (unsigned i = 0; i != NewRegs.size(); ++i) - mapVirtReg(NewRegs[i], UV); + if (auto *UserVals = lookupVirtReg(OldReg)) + for (auto *UV : *UserVals) + for (unsigned i = 0; i != NewRegs.size(); ++i) + mapVirtReg(NewRegs[i], UV); } void LiveDebugVariables:: @@ -1222,7 +1299,7 @@ // so skip over them. See getLocationNo(). if (Loc.isUndef()) continue; - unsigned NewLocNo = LocNoMap[Loc.locNo()]; + unsigned NewLocNo = LocNoMap[Loc.getLocNo()]; I.setValueUnchecked(Loc.changeLocNo(NewLocNo)); I.setStart(I.start()); } @@ -1276,7 +1353,8 @@ return MBB->end(); } -void UserValue::insertDebugValue(MachineBasicBlock *MBB, SlotIndex StartIdx, +void UserValue::insertDebugValue(const DIVariable *Variable, const DebugLoc &DL, + MachineBasicBlock *MBB, SlotIndex StartIdx, SlotIndex StopIdx, DbgValueLocation Loc, bool Spilled, unsigned SpillOffset, LiveIntervals &LIS, const TargetInstrInfo &TII, @@ -1288,7 +1366,7 @@ // Undef values don't exist in locations so create new "noreg" register MOs // for them. See getLocationNo(). MachineOperand MO = !Loc.isUndef() ? - locations[Loc.locNo()] : + locations[Loc.getLocNo()] : MachineOperand::CreateReg(/* Reg */ 0, /* isDef */ false, /* isImp */ false, /* isKill */ false, /* isDead */ false, /* isUndef */ false, /* isEarlyClobber */ false, @@ -1300,19 +1378,20 @@ ->isValidLocationForIntrinsic(getDebugLoc()) && "Expected inlined-at fields to agree"); + const DIExpression *Expr = Loc.getExpression(); + assert(Expr && "nullptr represents dummy value."); // If the location was spilled, the new DBG_VALUE will be indirect. If the // original DBG_VALUE was indirect, we need to add DW_OP_deref to indicate // that the original virtual register was a pointer. Also, add the stack slot // offset for the spilled register to the expression. - const DIExpression *Expr = Expression; if (Spilled) Expr = DIExpression::prepend(Expr, DIExpression::ApplyOffset, SpillOffset); assert((!Spilled || MO.isFI()) && "a spilled location must be a frame index"); do { - BuildMI(*MBB, I, getDebugLoc(), TII.get(TargetOpcode::DBG_VALUE), - Spilled, MO, Variable, Expr); + BuildMI(*MBB, I, DL, TII.get(TargetOpcode::DBG_VALUE), Spilled, MO, + Variable, Expr); // Continue and insert DBG_VALUES after every redefinition of register // associated with the debug value within the range @@ -1329,7 +1408,8 @@ .addMetadata(Label); } -void UserValue::emitDebugValues(VirtRegMap *VRM, LiveIntervals &LIS, +void UserValue::emitDebugValues(const DIVariable *Variable, const DebugLoc &DL, + VirtRegMap *VRM, LiveIntervals &LIS, const TargetInstrInfo &TII, const TargetRegisterInfo &TRI, const SpillOffsetMap &SpillOffsets) { @@ -1339,18 +1419,24 @@ SlotIndex Start = I.start(); SlotIndex Stop = I.stop(); DbgValueLocation Loc = I.value(); + + ++I; + // Skip dummy values. + if (!Loc.getExpression()) + continue; + auto SpillIt = - !Loc.isUndef() ? SpillOffsets.find(Loc.locNo()) : SpillOffsets.end(); + !Loc.isUndef() ? SpillOffsets.find(Loc.getLocNo()) : SpillOffsets.end(); bool Spilled = SpillIt != SpillOffsets.end(); unsigned SpillOffset = Spilled ? SpillIt->second : 0; - LLVM_DEBUG(dbgs() << "\t[" << Start << ';' << Stop << "):" << Loc.locNo()); + LLVM_DEBUG(dbgs() << "\t[" << Start << ';' << Stop << "):" << Loc.getLocNo()); MachineFunction::iterator MBB = LIS.getMBBFromIndex(Start)->getIterator(); SlotIndex MBBEnd = LIS.getMBBEndIdx(&*MBB); LLVM_DEBUG(dbgs() << ' ' << printMBBReference(*MBB) << '-' << MBBEnd); - insertDebugValue(&*MBB, Start, Stop, Loc, Spilled, SpillOffset, LIS, TII, - TRI); + insertDebugValue(Variable, DL, &*MBB, Start, Stop, Loc, Spilled, + SpillOffset, LIS, TII, TRI); // This interval may span multiple basic blocks. // Insert a DBG_VALUE into each one. while (Stop > MBBEnd) { @@ -1360,14 +1446,12 @@ break; MBBEnd = LIS.getMBBEndIdx(&*MBB); LLVM_DEBUG(dbgs() << ' ' << printMBBReference(*MBB) << '-' << MBBEnd); - insertDebugValue(&*MBB, Start, Stop, Loc, Spilled, SpillOffset, LIS, TII, - TRI); + insertDebugValue(Variable, DL, &*MBB, Start, Stop, Loc, Spilled, + SpillOffset, LIS, TII, TRI); } LLVM_DEBUG(dbgs() << '\n'); if (MBB == MFEnd) break; - - ++I; } } @@ -1387,10 +1471,14 @@ return; const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo(); SpillOffsetMap SpillOffsets; - for (auto &userValue : userValues) { - LLVM_DEBUG(userValue->print(dbgs(), TRI)); - userValue->rewriteLocations(*VRM, *MF, *TII, *TRI, SpillOffsets); - userValue->emitDebugValues(VRM, *LIS, *TII, *TRI, SpillOffsets); + for (auto &UVG : userValueGroups) { + for (const auto &UV : *UVG) { + LLVM_DEBUG( + UV->print(dbgs(), UVG->getVariable(), UVG->getDebugLoc(), TRI)); + UV->rewriteLocations(*VRM, *MF, *TII, *TRI, SpillOffsets); + UV->emitDebugValues(UVG->getVariable(), UVG->getDebugLoc(), VRM, *LIS, + *TII, *TRI, SpillOffsets); + } } LLVM_DEBUG(dbgs() << "********** EMITTING LIVE DEBUG LABELS **********\n"); for (auto &userLabel : userLabels) { Index: llvm/test/DebugInfo/ARM/PR26163.ll =================================================================== --- llvm/test/DebugInfo/ARM/PR26163.ll +++ llvm/test/DebugInfo/ARM/PR26163.ll @@ -10,8 +10,7 @@ ; ; CHECK: DW_TAG_inlined_subroutine ; CHECK: DW_TAG_variable -; CHECK: DW_AT_location [DW_FORM_sec_offset] ({{.*}} -; CHECK-NEXT: [0x00000004, 0x00000014): DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x4) +; CHECK: DW_AT_location [DW_FORM_exprloc] (DW_OP_lit0, DW_OP_stack_value, DW_OP_piece 0x4) ; Created form the following test case (PR26163) with ; clang -cc1 -triple armv4t--freebsd11.0-gnueabi -emit-obj -debug-info-kind=standalone -O2 -x c test.c Index: llvm/test/DebugInfo/X86/dbg-addr-dse.ll =================================================================== --- llvm/test/DebugInfo/X86/dbg-addr-dse.ll +++ llvm/test/DebugInfo/X86/dbg-addr-dse.ll @@ -3,10 +3,6 @@ ; RUN: FileCheck %s < %t.s --check-prefix=ASM ; RUN: llvm-dwarfdump %t.o | FileCheck %s --check-prefix=DWARF -; XFAIL: * -; See PR41992, the third and final dbg.value disappears after -; LiveDebugVariables. - ; In this example, the variable lives mostly in memory, but at the point of the ; assignment to global, it lives nowhere, and is described as the constant ; value 1. Index: llvm/test/DebugInfo/X86/live-debug-vars-dse.mir =================================================================== --- llvm/test/DebugInfo/X86/live-debug-vars-dse.mir +++ llvm/test/DebugInfo/X86/live-debug-vars-dse.mir @@ -1,9 +1,5 @@ # RUN: llc -start-after=machine-scheduler %s -o - | FileCheck %s -# XFAIL: * -# See PR41992, the third and final dbg.value disappears after -# LiveDebugVariables. - # C source: # void escape(int *); # extern int global; Index: llvm/test/DebugInfo/pr41992.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/pr41992.ll @@ -0,0 +1,105 @@ +; Test that identical DBG_VALUES are correctly coalesced (or not). +; NOTE: The IR in this file has been modified by hand and is based off the IR +; in the top comment here https://bugs.llvm.org/show_bug.cgi?id=41992 + +; RUN: llc %s -stop-after=virtregrewriter -o - | FileCheck %s --implicit-check-not=DBG_VALUE + +; Test that two identical DBG_VALUEs are not coalesced when another used to +; describe the same source variable fragment but with a different DIExpression +; is found between them. +; +; CHECK: name: f1 +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16) +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR]], !DIExpression(DW_OP_LLVM_fragment, 0, 16) +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16) + + +; Test that two identical DBG_VALUEs are not coalesced when another used to +; describe overlapping fragments of the same variable but with a different DIExpression +; is found between them. +; +; CHECK: name: f2 +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16) +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR]], !DIExpression(DW_OP_LLVM_fragment, 8, 16) +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16) + + +; Test that two identical DBG_VALUEs are coalesced when another used to +; describe another fragment of the same source variable s found between them. +; +; CHECK: name: f3 +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR:[0-9]+]], !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16) +; CHECK: DBG_VALUE %stack.0.x.addr, $noreg, ![[DBG_VAR]], !DIExpression(DW_OP_LLVM_fragment, 16, 16) + + +declare void @llvm.dbg.addr(metadata, metadata, metadata) +declare void @llvm.dbg.value(metadata, metadata, metadata) +declare void @escape(i32*) + +@global = external global i32, align 4 + +define void @f1(i32 %x) !dbg !8 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !13, metadata !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16)), !dbg !18 + call void @escape(i32* %x.addr), !dbg !18 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !13, metadata !DIExpression(DW_OP_LLVM_fragment, 0, 16)), !dbg !18 + store i32 1, i32* @global, align 4, !dbg !18 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !13, metadata !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16)), !dbg !18 + store i32 2, i32* %x.addr, align 4, !dbg !18 + call void @escape(i32* %x.addr), !dbg !18 + ret void, !dbg !18 +} + +define void @f2(i32 %x) !dbg !22 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !24, metadata !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16)), !dbg !23 + call void @escape(i32* %x.addr) + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !24, metadata !DIExpression(DW_OP_LLVM_fragment, 8, 16)), !dbg !23 + store i32 1, i32* @global, align 4 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !24, metadata !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16)), !dbg !23 + store i32 2, i32* %x.addr, align 4 + call void @escape(i32* %x.addr) + ret void +} + +define void @f3(i32 %x) !dbg !19 { +entry: + %x.addr = alloca i32, align 4 + store i32 %x, i32* %x.addr, align 4 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !21, metadata !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16)), !dbg !20 + call void @escape(i32* %x.addr) + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !21, metadata !DIExpression(DW_OP_LLVM_fragment, 16, 16)), !dbg !20 + store i32 1, i32* @global, align 4 + call void @llvm.dbg.value(metadata i32* %x.addr, metadata !21, metadata !DIExpression(DW_OP_deref, DW_OP_LLVM_fragment, 0, 16)), !dbg !20 + store i32 2, i32* %x.addr, align 4 + call void @escape(i32* %x.addr) + ret void +} + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4} +!llvm.ident = !{!7} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 6.0.0 ", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "dse.c", directory: "") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!7 = !{!"clang version 6.0.0 "} +!8 = distinct !DISubprogram(name: "f1", scope: !1, file: !1, line: 3, type: !9, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!9 = !DISubroutineType(types: !10) +!10 = !{null, !11} +!11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!12 = !{!13} +!13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 3, type: !11) +!18 = !DILocation(line: 3, column: 12, scope: !8) +!19 = distinct !DISubprogram(name: "f2", scope: !1, file: !1, line: 20, type: !9, isLocal: false, isDefinition: true, scopeLine: 20, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!20 = !DILocation(line: 23, column: 12, scope: !19) +!21 = !DILocalVariable(name: "x", arg: 1, scope: !19, file: !1, line: 21, type: !11) +!22 = distinct !DISubprogram(name: "f3", scope: !1, file: !1, line: 20, type: !9, isLocal: false, isDefinition: true, scopeLine: 30, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12) +!23 = !DILocation(line: 23, column: 12, scope: !22) +!24 = !DILocalVariable(name: "x", arg: 1, scope: !22, file: !1, line: 31, type: !11)