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) {
@@ -2070,6 +2074,10 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2070
2074
unsigned LastAsmLine =
2071
2075
Asm->OutStreamer ->getContext ().getCurrentDwarfLoc ().getLine ();
2072
2076
2077
+ bool IsKey = false ;
2078
+ if (KeyInstructionsAreStmts && DL && DL.getLine ())
2079
+ IsKey = KeyInstructions.contains (MI);
2080
+
2073
2081
if (!DL && MI == PrologEndLoc) {
2074
2082
// In rare situations, we might want to place the end of the prologue
2075
2083
// somewhere that doesn't have a source location already. It should be in
@@ -2088,13 +2096,18 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2088
2096
// If we have an ongoing unspecified location, nothing to do here.
2089
2097
if (!DL)
2090
2098
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 ;
2096
2110
}
2097
- return ;
2098
2111
}
2099
2112
2100
2113
if (!DL) {
@@ -2141,11 +2154,17 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2141
2154
Flags |= DWARF2_FLAG_PROLOGUE_END | DWARF2_FLAG_IS_STMT;
2142
2155
PrologEndLoc = nullptr ;
2143
2156
}
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
+ }
2149
2168
2150
2169
RecordSourceLine (DL, Flags);
2151
2170
@@ -2338,6 +2357,170 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
2338
2357
return PrologEndLoc;
2339
2358
}
2340
2359
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
+
2341
2524
// / For the function \p MF, finds the set of instructions which may represent a
2342
2525
// / change in line number from one or more of the preceding MBBs. Stores the
2343
2526
// / resulting set of instructions, which should have is_stmt set, in
@@ -2496,7 +2679,10 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
2496
2679
PrologEndLoc = emitInitialLocDirective (
2497
2680
*MF, Asm->OutStreamer ->getContext ().getDwarfCompileUnitID ());
2498
2681
2499
- findForceIsStmtInstrs (MF);
2682
+ if (KeyInstructionsAreStmts)
2683
+ findKeyInstructions (MF);
2684
+ else
2685
+ findForceIsStmtInstrs (MF);
2500
2686
}
2501
2687
2502
2688
unsigned
0 commit comments