@@ -50,11 +50,6 @@ void InlinedFunction::dump(raw_ostream &OS) const {
5050void InlinedFunction::printElementLine (raw_ostream &OS,
5151 object::SectionedAddress Addr,
5252 bool IsEnd) const {
53- bool LiveIn = !IsEnd && Range.LowPC == Addr.Address ;
54- bool LiveOut = IsEnd && Range.HighPC == Addr.Address ;
55- if (!(LiveIn || LiveOut))
56- return ;
57-
5853 uint32_t CallFile, CallLine, CallColumn, CallDiscriminator;
5954 InlinedFuncDie.getCallerFrame (CallFile, CallLine, CallColumn,
6055 CallDiscriminator);
@@ -126,8 +121,41 @@ void LiveElementPrinter::addInlinedFunction(DWARFDie FuncDie,
126121 DWARFUnit *U = InlinedFuncDie.getDwarfUnit ();
127122 const char *InlinedFuncName = InlinedFuncDie.getName (DINameKind::LinkageName);
128123 DWARFAddressRange Range{FuncLowPC, FuncHighPC, SectionIndex};
124+ // Add the new element to the main vector.
129125 LiveElements.emplace_back (std::make_unique<InlinedFunction>(
130126 InlinedFuncName, U, FuncDie, InlinedFuncDie, Range));
127+
128+ LiveElement *LE = LiveElements.back ().get ();
129+ // Map the element's low address (LowPC) to its pointer for fast range start
130+ // lookup.
131+ LiveElementsByAddress[FuncLowPC].push_back (LE);
132+ // Map the element's high address (HighPC) to its pointer for fast range end
133+ // lookup.
134+ LiveElementsByEndAddress[FuncHighPC].push_back (LE);
135+ // Map the pointer to its DWARF discovery index for deterministic
136+ // ordering.
137+ ElementPtrToIndex[LE] = LiveElements.size () - 1 ;
138+ }
139+
140+ // / Registers the most recently added LiveVariable into all data structures.
141+ void LiveElementPrinter::registerNewVariable () {
142+ assert (
143+ !LiveElements.empty () &&
144+ " registerNewVariable called before element was added to LiveElements." );
145+ LiveVariable *CurrentVar =
146+ static_cast <LiveVariable *>(LiveElements.back ().get ());
147+ assert (ElementPtrToIndex.count (CurrentVar) == 0 &&
148+ " Element already registered!" );
149+
150+ // Map from a LiveElement pointer to its index in the LiveElements.
151+ ElementPtrToIndex[CurrentVar] = LiveElements.size () - 1 ;
152+
153+ if (const std::optional<DWARFAddressRange> &Range =
154+ CurrentVar->getLocExpr ().Range ) {
155+ // Add the variable to address-based maps.
156+ LiveElementsByAddress[Range->LowPC ].push_back (CurrentVar);
157+ LiveElementsByEndAddress[Range->HighPC ].push_back (CurrentVar);
158+ }
131159}
132160
133161void LiveElementPrinter::addVariable (DWARFDie FuncDie, DWARFDie VarDie) {
@@ -160,6 +188,9 @@ void LiveElementPrinter::addVariable(DWARFDie FuncDie, DWARFDie VarDie) {
160188 LiveElements.emplace_back (
161189 std::make_unique<LiveVariable>(WholeFuncExpr, VarName, U, FuncDie));
162190 }
191+
192+ // Register the new variable with all data structures.
193+ registerNewVariable ();
163194 }
164195}
165196
@@ -205,14 +236,52 @@ unsigned LiveElementPrinter::moveToFirstVarColumn(formatted_raw_ostream &OS) {
205236 return FirstUnprintedLogicalColumn;
206237}
207238
208- unsigned LiveElementPrinter::findFreeColumn () {
209- for (unsigned ColIdx = 0 ; ColIdx < ActiveCols.size (); ++ColIdx)
210- if (!ActiveCols[ColIdx].isActive ())
211- return ColIdx;
239+ unsigned LiveElementPrinter::getOrCreateColumn (unsigned ElementIdx) {
240+ // Check if the element already has an assigned column.
241+ auto it = ElementToColumn.find (ElementIdx);
242+ if (it != ElementToColumn.end ())
243+ return it->second ;
244+
245+ unsigned ColIdx;
246+ if (!FreeCols.empty ()) {
247+ // Get the smallest available index from the set.
248+ ColIdx = *FreeCols.begin ();
249+ // Remove the index from the set.
250+ FreeCols.erase (FreeCols.begin ());
251+ } else {
252+ // No free columns, so create a new one.
253+ ColIdx = ActiveCols.size ();
254+ ActiveCols.emplace_back ();
255+ }
212256
213- size_t OldSize = ActiveCols.size ();
214- ActiveCols.grow (std::max<size_t >(OldSize * 2 , 1 ));
215- return OldSize;
257+ // Assign the element to the column and update the map.
258+ ElementToColumn[ElementIdx] = ColIdx;
259+ ActiveCols[ColIdx].ElementIdx = ElementIdx;
260+ return ColIdx;
261+ }
262+
263+ void LiveElementPrinter::freeColumn (unsigned ColIdx) {
264+ unsigned ElementIdx = ActiveCols[ColIdx].ElementIdx ;
265+
266+ // Clear the column's data.
267+ ActiveCols[ColIdx].clear ();
268+
269+ // Remove the element's entry from the map and add the column to the free
270+ // list.
271+ ElementToColumn.erase (ElementIdx);
272+ FreeCols.insert (ColIdx);
273+ }
274+
275+ std::vector<unsigned >
276+ LiveElementPrinter::getSortedActiveElementIndices () const {
277+ // Get all element indices that currently have an assigned column.
278+ std::vector<unsigned > Indices;
279+ for (const auto &Pair : ElementToColumn)
280+ Indices.push_back (Pair.first );
281+
282+ // Sort by the DWARF discovery order.
283+ llvm::stable_sort (Indices);
284+ return Indices;
216285}
217286
218287void LiveElementPrinter::dump () const {
@@ -239,57 +308,112 @@ void LiveElementPrinter::addCompileUnit(DWARFDie D) {
239308void LiveElementPrinter::update (object::SectionedAddress ThisAddr,
240309 object::SectionedAddress NextAddr,
241310 bool IncludeDefinedVars) {
242- // Do not create live ranges when debug-inlined-funcs option is provided with
243- // line format option.
311+ // Exit early if only printing function limits.
244312 if (DbgInlinedFunctions == DFLimitsOnly)
245313 return ;
246314
247- // First, check variables which have already been assigned a column, so
248- // that we don't change their order.
249- SmallSet<unsigned , 8 > CheckedElementIdxs;
315+ // Free columns identified in the previous cycle.
316+ for (unsigned ColIdx : ColumnsToFreeNextCycle)
317+ freeColumn (ColIdx);
318+ ColumnsToFreeNextCycle.clear ();
319+
320+ // Update status of active columns and collect those to free next cycle.
250321 for (unsigned ColIdx = 0 , End = ActiveCols.size (); ColIdx < End; ++ColIdx) {
251322 if (!ActiveCols[ColIdx].isActive ())
252323 continue ;
253324
254- CheckedElementIdxs.insert (ActiveCols[ColIdx].ElementIdx );
255325 const std::unique_ptr<LiveElement> &LE =
256326 LiveElements[ActiveCols[ColIdx].ElementIdx ];
257327 ActiveCols[ColIdx].LiveIn = LE->liveAtAddress (ThisAddr);
258328 ActiveCols[ColIdx].LiveOut = LE->liveAtAddress (NextAddr);
259- std::string Name = Demangle ? demangle (LE->getName ()) : LE->getName ();
260- LLVM_DEBUG (dbgs () << " pass 1, " << ThisAddr.Address << " -"
261- << NextAddr.Address << " , " << Name << " , Col " << ColIdx
262- << " : LiveIn=" << ActiveCols[ColIdx].LiveIn
263- << " , LiveOut=" << ActiveCols[ColIdx].LiveOut << " \n " );
264329
265- if (!ActiveCols[ColIdx].LiveIn && !ActiveCols[ColIdx].LiveOut )
330+ LLVM_DEBUG ({
331+ std::string Name = Demangle ? demangle (LE->getName ()) : LE->getName ();
332+ dbgs () << " pass 1, " << ThisAddr.Address << " -" << NextAddr.Address
333+ << " , " << Name << " , Col " << ColIdx
334+ << " : LiveIn=" << ActiveCols[ColIdx].LiveIn
335+ << " , LiveOut=" << ActiveCols[ColIdx].LiveOut << " \n " ;
336+ });
337+
338+ // If element is fully dead, deactivate column immediately.
339+ if (!ActiveCols[ColIdx].LiveIn && !ActiveCols[ColIdx].LiveOut ) {
266340 ActiveCols[ColIdx].ElementIdx = Column::NullElementIdx;
341+ continue ;
342+ }
343+
344+ // Mark for cleanup in the next cycle if range ends here.
345+ if (ActiveCols[ColIdx].LiveIn && !ActiveCols[ColIdx].LiveOut )
346+ ColumnsToFreeNextCycle.push_back (ColIdx);
267347 }
268348
269349 // Next, look for variables which don't already have a column, but which
270- // are now live.
350+ // are now live (those starting at ThisAddr or NextAddr) .
271351 if (IncludeDefinedVars) {
272- for (unsigned ElementIdx = 0 , End = LiveElements.size (); ElementIdx < End;
273- ++ElementIdx) {
274- if (CheckedElementIdxs.count (ElementIdx))
352+ // Collect all elements starting at ThisAddr and NextAddr.
353+ std::vector<std::pair<unsigned , LiveElement *>> NewLiveElements;
354+ auto CollectNewElements = [&](const auto &It) {
355+ if (It == LiveElementsByAddress.end ())
356+ return ;
357+
358+ const std::vector<LiveElement *> &ElementList = It->second ;
359+ for (LiveElement *LE : ElementList) {
360+ auto IndexIt = ElementPtrToIndex.find (LE);
361+ assert (IndexIt != ElementPtrToIndex.end () &&
362+ " LiveElement in address map but missing from index map!" );
363+
364+ // Get the element index for sorting and column management.
365+ unsigned ElementIdx = IndexIt->second ;
366+ // Skip elements that already have a column.
367+ if (ElementToColumn.count (ElementIdx))
368+ continue ;
369+
370+ bool LiveIn = LE->liveAtAddress (ThisAddr);
371+ bool LiveOut = LE->liveAtAddress (NextAddr);
372+ if (!LiveIn && !LiveOut)
373+ continue ;
374+
375+ NewLiveElements.emplace_back (ElementIdx, LE);
376+ }
377+ };
378+
379+ // Collect elements starting at ThisAddr.
380+ CollectNewElements (LiveElementsByAddress.find (ThisAddr.Address ));
381+ // Collect elements starting at NextAddr (the address immediately
382+ // following the instruction).
383+ CollectNewElements (LiveElementsByAddress.find (NextAddr.Address ));
384+ // Sort elements by DWARF discovery order for deterministic column
385+ // assignment.
386+ llvm::stable_sort (NewLiveElements, [](const auto &A, const auto &B) {
387+ return A.first < B.first ;
388+ });
389+
390+ // Assign columns in deterministic order.
391+ for (const auto &ElementPair : NewLiveElements) {
392+ unsigned ElementIdx = ElementPair.first ;
393+ // Skip if element was already added from the first range.
394+ if (ElementToColumn.count (ElementIdx))
275395 continue ;
276396
277- const std::unique_ptr< LiveElement> & LE = LiveElements[ElementIdx] ;
397+ LiveElement * LE = ElementPair. second ;
278398 bool LiveIn = LE->liveAtAddress (ThisAddr);
279399 bool LiveOut = LE->liveAtAddress (NextAddr);
280- if (!LiveIn && !LiveOut)
281- continue ;
282400
283- unsigned ColIdx = findFreeColumn ();
284- std::string Name = Demangle ? demangle (LE->getName ()) : LE->getName ();
285- LLVM_DEBUG (dbgs () << " pass 2, " << ThisAddr.Address << " -"
286- << NextAddr.Address << " , " << Name << " , Col "
287- << ColIdx << " : LiveIn=" << LiveIn
288- << " , LiveOut=" << LiveOut << " \n " );
289- ActiveCols[ColIdx].ElementIdx = ElementIdx;
401+ // Assign or create a column.
402+ unsigned ColIdx = getOrCreateColumn (ElementIdx);
403+ LLVM_DEBUG ({
404+ std::string Name = Demangle ? demangle (LE->getName ()) : LE->getName ();
405+ dbgs () << " pass 2, " << ThisAddr.Address << " -" << NextAddr.Address
406+ << " , " << Name << " , Col " << ColIdx << " : LiveIn=" << LiveIn
407+ << " , LiveOut=" << LiveOut << " \n " ;
408+ });
409+
290410 ActiveCols[ColIdx].LiveIn = LiveIn;
291411 ActiveCols[ColIdx].LiveOut = LiveOut;
292412 ActiveCols[ColIdx].MustDrawLabel = true ;
413+
414+ // Mark for cleanup next cycle if range ends here.
415+ if (ActiveCols[ColIdx].LiveIn && !ActiveCols[ColIdx].LiveOut )
416+ ColumnsToFreeNextCycle.push_back (ColIdx);
293417 }
294418 }
295419}
@@ -360,7 +484,13 @@ void LiveElementPrinter::printAfterOtherLine(formatted_raw_ostream &OS,
360484void LiveElementPrinter::printBetweenInsts (formatted_raw_ostream &OS,
361485 bool MustPrint) {
362486 bool PrintedSomething = false ;
363- for (unsigned ColIdx = 0 , End = ActiveCols.size (); ColIdx < End; ++ColIdx) {
487+ // Get all active elements, sorted by discovery order.
488+ std::vector<unsigned > SortedElementIndices = getSortedActiveElementIndices ();
489+ // The outer loop iterates over the deterministic DWARF discovery order.
490+ for (unsigned ElementIdx : SortedElementIndices) {
491+ // Look up the physical column index (ColIdx) assigned to this
492+ // element. We use .at() because we are certain the element is active.
493+ unsigned ColIdx = ElementToColumn.at (ElementIdx);
364494 if (ActiveCols[ColIdx].isActive () && ActiveCols[ColIdx].MustDrawLabel ) {
365495 // First we need to print the live range markers for any active
366496 // columns to the left of this one.
@@ -375,8 +505,7 @@ void LiveElementPrinter::printBetweenInsts(formatted_raw_ostream &OS,
375505 OS << " " ;
376506 }
377507
378- const std::unique_ptr<LiveElement> &LE =
379- LiveElements[ActiveCols[ColIdx].ElementIdx ];
508+ const std::unique_ptr<LiveElement> &LE = LiveElements[ElementIdx];
380509 // Then print the variable name and location of the new live range,
381510 // with box drawing characters joining it to the live range line.
382511 OS << getLineChar (ActiveCols[ColIdx].LiveIn ? LineChar::LabelCornerActive
@@ -438,22 +567,40 @@ void LiveElementPrinter::printAfterInst(formatted_raw_ostream &OS) {
438567 }
439568}
440569
441- void LiveElementPrinter::printStartLine (formatted_raw_ostream &OS,
442- object::SectionedAddress Addr) {
443- // Print a line to idenfity the start of an inlined function if line format
444- // is specified.
445- if (DbgInlinedFunctions == DFLimitsOnly)
446- for (const std::unique_ptr<LiveElement> &LE : LiveElements)
447- LE->printElementLine (OS, Addr, false );
448- }
570+ void LiveElementPrinter::printBoundaryLine (formatted_raw_ostream &OS,
571+ object::SectionedAddress Addr,
572+ bool IsEnd) {
573+ // Only print the start/end line for inlined functions if DFLimitsOnly is
574+ // enabled.
575+ if (DbgInlinedFunctions != DFLimitsOnly)
576+ return ;
449577
450- void LiveElementPrinter::printEndLine (formatted_raw_ostream &OS,
451- object::SectionedAddress Addr) {
452- // Print a line to idenfity the end of an inlined function if line format is
453- // specified.
454- if (DbgInlinedFunctions == DFLimitsOnly)
455- for (const std::unique_ptr<LiveElement> &LE : LiveElements)
456- LE->printElementLine (OS, Addr, true );
578+ // Select the appropriate map based on whether we are checking the start
579+ // (LowPC) or end (HighPC) address.
580+ const auto &AddressMap =
581+ IsEnd ? LiveElementsByEndAddress : LiveElementsByAddress;
582+
583+ // Use the map to find all elements that start/end at the given address.
584+ std::vector<unsigned > ElementIndices;
585+ auto It = AddressMap.find (Addr.Address );
586+ if (It != AddressMap.end ()) {
587+ for (LiveElement *LE : It->second ) {
588+ // Look up the element index from the pointer.
589+ auto IndexIt = ElementPtrToIndex.find (LE);
590+ assert (IndexIt != ElementPtrToIndex.end () &&
591+ " LiveElement found in address map but missing index!" );
592+ ElementIndices.push_back (IndexIt->second );
593+ }
594+ }
595+
596+ // Sort the indices to ensure deterministic output order (by DWARF discovery
597+ // order).
598+ llvm::stable_sort (ElementIndices);
599+
600+ for (unsigned ElementIdx : ElementIndices) {
601+ LiveElement *LE = LiveElements[ElementIdx].get ();
602+ LE->printElementLine (OS, Addr, IsEnd);
603+ }
457604}
458605
459606bool SourcePrinter::cacheSource (const DILineInfo &LineInfo) {
0 commit comments