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