1717#include " DwarfExpression.h"
1818#include " DwarfUnit.h"
1919#include " llvm/ADT/APInt.h"
20+ #include " llvm/ADT/ScopeExit.h"
2021#include " llvm/ADT/Statistic.h"
2122#include " llvm/ADT/StringExtras.h"
2223#include " llvm/ADT/Twine.h"
@@ -170,6 +171,9 @@ static cl::opt<DwarfDebug::MinimizeAddrInV5> MinimizeAddrInV5Option(
170171 " Stuff" )),
171172 cl::init(DwarfDebug::MinimizeAddrInV5::Default));
172173
174+ static cl::opt<bool > KeyInstructionsAreStmts (" dwarf-use-key-instructions" ,
175+ cl::Hidden, cl::init(false ));
176+
173177static constexpr unsigned ULEB128PadSize = 4 ;
174178
175179void DebugLocDwarfExpression::emitOp (uint8_t Op, const char *Comment) {
@@ -2075,6 +2079,10 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
20752079 unsigned LastAsmLine =
20762080 Asm->OutStreamer ->getContext ().getCurrentDwarfLoc ().getLine ();
20772081
2082+ bool IsKey = false ;
2083+ if (KeyInstructionsAreStmts && DL && DL.getLine ())
2084+ IsKey = KeyInstructions.contains (MI);
2085+
20782086 if (!DL && MI == PrologEndLoc) {
20792087 // In rare situations, we might want to place the end of the prologue
20802088 // somewhere that doesn't have a source location already. It should be in
@@ -2089,17 +2097,22 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
20892097 (!PrevInstBB ||
20902098 PrevInstBB->getSectionID () == MI->getParent ()->getSectionID ());
20912099 bool ForceIsStmt = ForceIsStmtInstrs.contains (MI);
2092- if (DL == PrevInstLoc && PrevInstInSameSection && !ForceIsStmt ) {
2100+ if (PrevInstInSameSection && !ForceIsStmt && DL. isSameSourceLocation (PrevInstLoc) ) {
20932101 // If we have an ongoing unspecified location, nothing to do here.
20942102 if (!DL)
20952103 return ;
2096- // We have an explicit location, same as the previous location.
2097- // But we might be coming back to it after a line 0 record.
2098- if ((LastAsmLine == 0 && DL.getLine () != 0 ) || Flags) {
2099- // Reinstate the source location but not marked as a statement.
2100- RecordSourceLine (DL, Flags);
2104+
2105+ // Skip this if the instruction is Key, else we might accidentally miss an
2106+ // is_stmt.
2107+ if (!IsKey) {
2108+ // We have an explicit location, same as the previous location.
2109+ // But we might be coming back to it after a line 0 record.
2110+ if ((LastAsmLine == 0 && DL.getLine () != 0 ) || Flags) {
2111+ // Reinstate the source location but not marked as a statement.
2112+ RecordSourceLine (DL, Flags);
2113+ }
2114+ return ;
21012115 }
2102- return ;
21032116 }
21042117
21052118 if (!DL) {
@@ -2146,11 +2159,17 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
21462159 Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT;
21472160 PrologEndLoc = nullptr ;
21482161 }
2149- // If the line changed, we call that a new statement; unless we went to
2150- // line 0 and came back, in which case it is not a new statement.
2151- unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine () : LastAsmLine;
2152- if (DL.getLine () && (DL.getLine () != OldLine || ForceIsStmt))
2153- Flags |= DWARF2_FLAG_IS_STMT;
2162+
2163+ if (KeyInstructionsAreStmts) {
2164+ if (IsKey)
2165+ Flags |= DWARF2_FLAG_IS_STMT;
2166+ } else {
2167+ // If the line changed, we call that a new statement; unless we went to
2168+ // line 0 and came back, in which case it is not a new statement.
2169+ unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine () : LastAsmLine;
2170+ if (DL.getLine () && (DL.getLine () != OldLine || ForceIsStmt))
2171+ Flags |= DWARF2_FLAG_IS_STMT;
2172+ }
21542173
21552174 RecordSourceLine (DL, Flags);
21562175
@@ -2343,6 +2362,139 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
23432362 return PrologEndLoc;
23442363}
23452364
2365+ void DwarfDebug::computeKeyInstructions (const MachineFunction *MF) {
2366+ // New function - reset KeyInstructions.
2367+ KeyInstructions.clear ();
2368+
2369+ // The current candidate is_stmt instructions for each source atom.
2370+ // Map {(InlinedAt, Group): (Rank, Instructions)}.
2371+ // NOTE: Anecdotally, for a large C++ blob, 99% of the instruction
2372+ // SmallVectors contain 2 or fewer elements; use 2 inline elements.
2373+ DenseMap<std::pair<DILocation *, uint32_t >,
2374+ std::pair<uint16_t , SmallVector<const MachineInstr *, 2 >>>
2375+ GroupCandidates;
2376+
2377+ // For each instruction:
2378+ // * Skip insts without DebugLoc, AtomGroup or AtomRank, and line zeros.
2379+ // * Check if insts in this group have been seen already in GroupCandidates.
2380+ // * If this instr rank is equal, add this instruction to GroupCandidates.
2381+ // Remove existing instructions from GroupCandidates if they have the
2382+ // same parent.
2383+ // * If this instr rank is higher (lower precedence), ignore it.
2384+ // * If this instr rank is lower (higher precedence), erase existing
2385+ // instructions from GroupCandidates and add this one.
2386+ //
2387+ // Then insert each GroupCandidates instruction into KeyInstructions.
2388+
2389+ for (auto &MBB : *MF) {
2390+ // Rather than apply is_stmt directly to Key Instructions, we "float"
2391+ // is_stmt up to the 1st instruction with the same line number in a
2392+ // contiguous block. That instruction is called the "buoy". The
2393+ // buoy gets reset if we encouner an instruction with an atom
2394+ // group.
2395+ const MachineInstr *Buoy = nullptr ;
2396+ // The atom group number associated with Buoy which may be 0 if we haven't
2397+ // encountered an atom group yet in this blob of instructions with the same
2398+ // line number.
2399+ uint64_t BuoyAtom = 0 ;
2400+
2401+ for (auto &MI : MBB) {
2402+ if (MI.isMetaInstruction ())
2403+ continue ;
2404+
2405+ if (!MI.getDebugLoc () || !MI.getDebugLoc ().getLine ())
2406+ continue ;
2407+
2408+ // Reset the Buoy to this instruction if it has a different line number.
2409+ if (!Buoy ||
2410+ Buoy->getDebugLoc ().getLine () != MI.getDebugLoc ().getLine ()) {
2411+ Buoy = &MI;
2412+ BuoyAtom = 0 ; // Set later when we know which atom the buoy is used by.
2413+ }
2414+
2415+ // Call instructions are handled specially - we always mark them as key
2416+ // regardless of atom info.
2417+ const auto &TII =
2418+ *MI.getParent ()->getParent ()->getSubtarget ().getInstrInfo ();
2419+ bool IsCallLike = MI.isCall () || TII.isTailCall (MI);
2420+ if (IsCallLike) {
2421+ assert (MI.getDebugLoc () && " Unexpectedly missing DL" );
2422+
2423+ // Calls are always key. Put the buoy (may not be the call) into
2424+ // KeyInstructions directly rather than the candidate map to avoid it
2425+ // being erased (and we may not have a group number for the call).
2426+ KeyInstructions.insert (Buoy);
2427+
2428+ // Avoid floating any future is_stmts up to the call.
2429+ Buoy = nullptr ;
2430+ BuoyAtom = 0 ;
2431+
2432+ if (!MI.getDebugLoc ()->getAtomGroup () ||
2433+ !MI.getDebugLoc ()->getAtomRank ())
2434+ continue ;
2435+ }
2436+
2437+ auto *InlinedAt = MI.getDebugLoc ()->getInlinedAt ();
2438+ uint64_t Group = MI.getDebugLoc ()->getAtomGroup ();
2439+ uint8_t Rank = MI.getDebugLoc ()->getAtomRank ();
2440+ if (!Group || !Rank)
2441+ continue ;
2442+
2443+ // Don't let is_stmts float past instructions from different source atoms.
2444+ if (BuoyAtom && BuoyAtom != Group) {
2445+ Buoy = &MI;
2446+ BuoyAtom = Group;
2447+ }
2448+
2449+ auto &[CandidateRank, CandidateInsts] =
2450+ GroupCandidates[{InlinedAt, Group}];
2451+
2452+ // If CandidateRank is zero then CandidateInsts should be empty: there
2453+ // are no other candidates for this group yet. If CandidateRank is nonzero
2454+ // then CandidateInsts shouldn't be empty: we've got existing candidate
2455+ // instructions.
2456+ assert ((CandidateRank == 0 && CandidateInsts.empty ()) ||
2457+ (CandidateRank != 0 && !CandidateInsts.empty ()));
2458+
2459+ assert (Rank && " expected nonzero rank" );
2460+ // If we've seen other instructions in this group with higher precedence
2461+ // (lower nonzero rank), don't add this one as a candidate.
2462+ if (CandidateRank && CandidateRank < Rank)
2463+ continue ;
2464+
2465+ // If we've seen other instructions in this group of the same rank,
2466+ // discard any from this block (keeping the others). Else if we've
2467+ // seen other instructions in this group of lower precedence (higher
2468+ // rank), discard them all.
2469+ if (CandidateRank == Rank)
2470+ llvm::remove_if (CandidateInsts, [&MI](const MachineInstr *Candidate) {
2471+ return MI.getParent () == Candidate->getParent ();
2472+ });
2473+ else if (CandidateRank > Rank)
2474+ CandidateInsts.clear ();
2475+
2476+ if (Buoy) {
2477+ // Add this candidate.
2478+ CandidateInsts.push_back (Buoy);
2479+ CandidateRank = Rank;
2480+
2481+ assert (!BuoyAtom || BuoyAtom == MI.getDebugLoc ()->getAtomGroup ());
2482+ BuoyAtom = MI.getDebugLoc ()->getAtomGroup ();
2483+ } else {
2484+ // Don't add calls, because they've been dealt with already. This means
2485+ // CandidateInsts might now be empty - handle that.
2486+ assert (IsCallLike);
2487+ if (CandidateInsts.empty ())
2488+ CandidateRank = 0 ;
2489+ }
2490+ }
2491+ }
2492+
2493+ for (const auto &[_, Insts] : GroupCandidates.values ())
2494+ for (auto *I : Insts)
2495+ KeyInstructions.insert (I);
2496+ }
2497+
23462498// / For the function \p MF, finds the set of instructions which may represent a
23472499// / change in line number from one or more of the preceding MBBs. Stores the
23482500// / resulting set of instructions, which should have is_stmt set, in
@@ -2501,7 +2653,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
25012653 PrologEndLoc = emitInitialLocDirective (
25022654 *MF, Asm->OutStreamer ->getContext ().getDwarfCompileUnitID ());
25032655
2504- findForceIsStmtInstrs (MF);
2656+ if (KeyInstructionsAreStmts)
2657+ computeKeyInstructions (MF);
2658+ else
2659+ findForceIsStmtInstrs (MF);
25052660}
25062661
25072662unsigned
0 commit comments