17
17
#include " DwarfExpression.h"
18
18
#include " DwarfUnit.h"
19
19
#include " llvm/ADT/APInt.h"
20
+ #include " llvm/ADT/ScopeExit.h"
20
21
#include " llvm/ADT/Statistic.h"
21
22
#include " llvm/ADT/StringExtras.h"
22
23
#include " llvm/ADT/Twine.h"
@@ -170,6 +171,9 @@ static cl::opt<DwarfDebug::MinimizeAddrInV5> MinimizeAddrInV5Option(
170
171
" Stuff" )),
171
172
cl::init(DwarfDebug::MinimizeAddrInV5::Default));
172
173
174
+ static cl::opt<bool > KeyInstructionsAreStmts (" dwarf-use-key-instructions" ,
175
+ cl::Hidden, cl::init(false ));
176
+
173
177
static constexpr unsigned ULEB128PadSize = 4 ;
174
178
175
179
void DebugLocDwarfExpression::emitOp (uint8_t Op, const char *Comment) {
@@ -2069,6 +2073,10 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2069
2073
unsigned LastAsmLine =
2070
2074
Asm->OutStreamer ->getContext ().getCurrentDwarfLoc ().getLine ();
2071
2075
2076
+ bool IsKey = false ;
2077
+ if (KeyInstructionsAreStmts && DL && DL.getLine ())
2078
+ IsKey = KeyInstructions.contains (MI);
2079
+
2072
2080
if (!DL && MI == PrologEndLoc) {
2073
2081
// In rare situations, we might want to place the end of the prologue
2074
2082
// somewhere that doesn't have a source location already. It should be in
@@ -2087,13 +2095,18 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2087
2095
// If we have an ongoing unspecified location, nothing to do here.
2088
2096
if (!DL)
2089
2097
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 ;
2095
2109
}
2096
- return ;
2097
2110
}
2098
2111
2099
2112
if (!DL) {
@@ -2136,11 +2149,17 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2136
2149
Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT;
2137
2150
PrologEndLoc = nullptr ;
2138
2151
}
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
+ }
2144
2163
2145
2164
RecordSourceLine (DL, Flags);
2146
2165
@@ -2333,6 +2352,170 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
2333
2352
return PrologEndLoc;
2334
2353
}
2335
2354
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
+
2336
2519
// / For the function \p MF, finds the set of instructions which may represent a
2337
2520
// / change in line number from one or more of the preceding MBBs. Stores the
2338
2521
// / resulting set of instructions, which should have is_stmt set, in
@@ -2491,7 +2674,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
2491
2674
PrologEndLoc = emitInitialLocDirective (
2492
2675
*MF, Asm->OutStreamer ->getContext ().getDwarfCompileUnitID ());
2493
2676
2494
- findForceIsStmtInstrs (MF);
2677
+ if (KeyInstructionsAreStmts)
2678
+ findKeyInstructions (MF);
2679
+ else
2680
+ findForceIsStmtInstrs (MF);
2495
2681
}
2496
2682
2497
2683
unsigned
0 commit comments