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) {
@@ -2070,6 +2074,10 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
20702074 unsigned LastAsmLine =
20712075 Asm->OutStreamer ->getContext ().getCurrentDwarfLoc ().getLine ();
20722076
2077+ bool IsKey = false ;
2078+ if (KeyInstructionsAreStmts && DL && DL.getLine ())
2079+ IsKey = KeyInstructions.contains (MI);
2080+
20732081 if (!DL && MI == PrologEndLoc) {
20742082 // In rare situations, we might want to place the end of the prologue
20752083 // somewhere that doesn't have a source location already. It should be in
@@ -2088,13 +2096,18 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
20882096 // If we have an ongoing unspecified location, nothing to do here.
20892097 if (!DL)
20902098 return ;
2091- // We have an explicit location, same as the previous location.
2092- // But we might be coming back to it after a line 0 record.
2093- if ((LastAsmLine == 0 && DL.getLine () != 0 ) || Flags) {
2094- // Reinstate the source location but not marked as a statement.
2095- RecordSourceLine (DL, Flags);
2099+
2100+ // Skip this if the instruction is Key, else we might accidentally miss an
2101+ // is_stmt.
2102+ if (!IsKey) {
2103+ // We have an explicit location, same as the previous location.
2104+ // But we might be coming back to it after a line 0 record.
2105+ if ((LastAsmLine == 0 && DL.getLine () != 0 ) || Flags) {
2106+ // Reinstate the source location but not marked as a statement.
2107+ RecordSourceLine (DL, Flags);
2108+ }
2109+ return ;
20962110 }
2097- return ;
20982111 }
20992112
21002113 if (!DL) {
@@ -2141,11 +2154,17 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
21412154 Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT;
21422155 PrologEndLoc = nullptr ;
21432156 }
2144- // If the line changed, we call that a new statement; unless we went to
2145- // line 0 and came back, in which case it is not a new statement.
2146- unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine () : LastAsmLine;
2147- if (DL.getLine () && (DL.getLine () != OldLine || ForceIsStmt))
2148- Flags |= DWARF2_FLAG_IS_STMT;
2157+
2158+ if (KeyInstructionsAreStmts) {
2159+ if (IsKey)
2160+ Flags |= DWARF2_FLAG_IS_STMT;
2161+ } else {
2162+ // If the line changed, we call that a new statement; unless we went to
2163+ // line 0 and came back, in which case it is not a new statement.
2164+ unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine () : LastAsmLine;
2165+ if (DL.getLine () && (DL.getLine () != OldLine || ForceIsStmt))
2166+ Flags |= DWARF2_FLAG_IS_STMT;
2167+ }
21492168
21502169 RecordSourceLine (DL, Flags);
21512170
@@ -2338,6 +2357,170 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
23382357 return PrologEndLoc;
23392358}
23402359
2360+ void DwarfDebug::findKeyInstructions (const MachineFunction *MF) {
2361+ // New function - reset KeyInstructions.
2362+ KeyInstructions.clear ();
2363+
2364+ // The current candidate is_stmt instructions for each source atom.
2365+ // Map {(InlinedAt, Group): (Rank, Instructions)}.
2366+ DenseMap<std::pair<DILocation *, uint32_t >,
2367+ std::pair<uint16_t , SmallVector<const MachineInstr *>>>
2368+ GroupCandidates;
2369+
2370+ // For each instruction:
2371+ // * Skip insts without DebugLoc, AtomGroup or AtomRank, and line zeros.
2372+ // * Check if insts in this group have been seen already in GroupCandidates.
2373+ // * If this instr rank is equal, add this instruction to KeyInstructions.
2374+ // Remove existing instructions from KeyInstructions if they have the
2375+ // same parent.
2376+ // * If this instr rank is higher (lower precedence), ignore it.
2377+ // * If this instr rank is lower (higher precedence), erase existing
2378+ // instructions from KeyInstructions. Add this instr to KeyInstructions.
2379+
2380+ for (auto &MBB : *MF) {
2381+ // Rather than apply is_stmt directly to Key Instructions, we "float"
2382+ // is_stmt up to the 1st instruction with the same line number in a
2383+ // contiguous block. That instruction is called the "buoy". The
2384+ // buoy gets reset if we encouner an instruction with an atom
2385+ // group.
2386+ const MachineInstr *Buoy = nullptr ;
2387+ // The atom group number associated with Buoy which may be 0 if we haven't
2388+ // encountered an atom group yet in this blob of instructions with the same
2389+ // line number.
2390+ uint64_t BuoyAtom = 0 ;
2391+
2392+ for (auto &MI : MBB) {
2393+ if (MI.isMetaInstruction ())
2394+ continue ;
2395+
2396+ if (!MI.getDebugLoc () || !MI.getDebugLoc ().getLine ())
2397+ continue ;
2398+
2399+ // Reset the Buoy to this instruciton if it has a different line number.
2400+ if (!Buoy ||
2401+ Buoy->getDebugLoc ().getLine () != MI.getDebugLoc ().getLine ()) {
2402+ Buoy = &MI;
2403+ BuoyAtom = 0 ;
2404+ }
2405+
2406+ // Call instructions are handled specially - we always mark them as key
2407+ // regardless of atom info.
2408+ const auto &TII =
2409+ *MI.getParent ()->getParent ()->getSubtarget ().getInstrInfo ();
2410+ if (MI.isCall () || TII.isTailCall (MI)) {
2411+ assert (MI.getDebugLoc () && " Unexpectedly missing DL" );
2412+
2413+ // Calls are always key.
2414+ KeyInstructions.insert (Buoy);
2415+
2416+ uint64_t Group = MI.getDebugLoc ()->getAtomGroup ();
2417+ uint8_t Rank = MI.getDebugLoc ()->getAtomRank ();
2418+ if (Group && Rank) {
2419+ auto *InlinedAt = MI.getDebugLoc ()->getInlinedAt ();
2420+ auto &[CandidateRank, CandidateInsts] = GroupCandidates[{InlinedAt, Group}];
2421+
2422+ // This looks similar to the non-call handling code, except that
2423+ // we don't put the call into CandidateInsts so that they can't be
2424+ // made un-key. As a result, we also have to take special care not
2425+ // to erase the is_stmt from the buoy, and prevent that happening
2426+ // in the future.
2427+
2428+ if (CandidateRank == Rank) {
2429+ // We've seen other instructions in this group of this rank. Discard
2430+ // ones we've seen in this block, keep the others.
2431+ assert (!CandidateInsts.empty ());
2432+ SmallVector<const MachineInstr *> Insts;
2433+ Insts.reserve (CandidateInsts.size ());
2434+ for (auto &PrevInst : CandidateInsts) {
2435+ if (PrevInst->getParent () != MI.getParent ())
2436+ Insts.push_back (PrevInst);
2437+ else if (PrevInst != Buoy)
2438+ KeyInstructions.erase (PrevInst);
2439+ }
2440+
2441+ if (Insts.empty ()) {
2442+ CandidateInsts.clear ();
2443+ CandidateRank = 0 ;
2444+ } else {
2445+ CandidateInsts = std::move (Insts);
2446+ }
2447+
2448+ } else if (CandidateRank > Rank) {
2449+ // We've seen other instructions in this group of lower precedence
2450+ // (higher rank). Discard them.
2451+ for (auto *Supplanted : CandidateInsts) {
2452+ // Don't erase the is_stmt we're using for this call.
2453+ if (Supplanted != Buoy)
2454+ KeyInstructions.erase (Supplanted);
2455+ }
2456+ CandidateInsts.clear ();
2457+ CandidateRank = 0 ;
2458+ }
2459+ }
2460+
2461+ // Avoid floating any future is_stmts up to the call.
2462+ Buoy = nullptr ;
2463+ continue ;
2464+ }
2465+
2466+ auto *InlinedAt = MI.getDebugLoc ()->getInlinedAt ();
2467+ uint64_t Group = MI.getDebugLoc ()->getAtomGroup ();
2468+ uint8_t Rank = MI.getDebugLoc ()->getAtomRank ();
2469+ if (!Group || !Rank)
2470+ continue ;
2471+
2472+ // Don't let is_stmts float past instructions from different source atoms.
2473+ if (BuoyAtom && BuoyAtom != Group) {
2474+ Buoy = &MI;
2475+ BuoyAtom = MI.getDebugLoc ()->getAtomGroup ();
2476+ }
2477+
2478+ auto &[CandidateRank, CandidateInsts] = GroupCandidates[{InlinedAt, Group}];
2479+
2480+ if (CandidateRank == 0 ) {
2481+ // This is the first time we're seeing an instruction in this atom
2482+ // group. Add it to the map.
2483+ assert (CandidateInsts.empty ());
2484+ CandidateRank = Rank;
2485+ CandidateInsts.push_back (Buoy);
2486+
2487+ } else if (CandidateRank == Rank) {
2488+ // We've seen other instructions in this group of this rank. Discard
2489+ // ones we've seen in this block, keep the others, add this one.
2490+ assert (!CandidateInsts.empty ());
2491+ SmallVector<const MachineInstr *> Insts;
2492+ Insts.reserve (CandidateInsts.size () + 1 );
2493+ for (auto &PrevInst : CandidateInsts) {
2494+ if (PrevInst->getParent () != MI.getParent ())
2495+ Insts.push_back (PrevInst);
2496+ else
2497+ KeyInstructions.erase (PrevInst);
2498+ }
2499+ Insts.push_back (Buoy);
2500+ CandidateInsts = std::move (Insts);
2501+
2502+ } else if (CandidateRank > Rank) {
2503+ // We've seen other instructions in this group of lower precedence
2504+ // (higher rank). Discard them, add this one.
2505+ assert (!CandidateInsts.empty ());
2506+ CandidateRank = Rank;
2507+ for (auto *Supplanted : CandidateInsts)
2508+ KeyInstructions.erase (Supplanted);
2509+ CandidateInsts = {Buoy};
2510+
2511+ } else {
2512+ // We've seen other instructions in this group with higher precedence
2513+ // (lower rank). Discard this one.
2514+ assert (Rank != 0 && CandidateRank < Rank && CandidateRank != 0 );
2515+ continue ;
2516+ }
2517+ KeyInstructions.insert (Buoy);
2518+ assert (!BuoyAtom || BuoyAtom == MI.getDebugLoc ()->getAtomGroup ());
2519+ BuoyAtom = MI.getDebugLoc ()->getAtomGroup ();
2520+ }
2521+ }
2522+ }
2523+
23412524// / For the function \p MF, finds the set of instructions which may represent a
23422525// / change in line number from one or more of the preceding MBBs. Stores the
23432526// / resulting set of instructions, which should have is_stmt set, in
@@ -2496,7 +2679,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
24962679 PrologEndLoc = emitInitialLocDirective (
24972680 *MF, Asm->OutStreamer ->getContext ().getDwarfCompileUnitID ());
24982681
2499- findForceIsStmtInstrs (MF);
2682+ if (KeyInstructionsAreStmts)
2683+ findKeyInstructions (MF);
2684+ else
2685+ findForceIsStmtInstrs (MF);
25002686}
25012687
25022688unsigned
0 commit comments