@@ -2075,7 +2075,8 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2075
2075
bool PrevInstInSameSection =
2076
2076
(!PrevInstBB ||
2077
2077
PrevInstBB->getSectionID () == MI->getParent ()->getSectionID ());
2078
- if (DL == PrevInstLoc && PrevInstInSameSection) {
2078
+ bool ForceIsStmt = ForceIsStmtInstrs.contains (MI);
2079
+ if (DL == PrevInstLoc && PrevInstInSameSection && !ForceIsStmt) {
2079
2080
// If we have an ongoing unspecified location, nothing to do here.
2080
2081
if (!DL)
2081
2082
return ;
@@ -2132,7 +2133,7 @@ void DwarfDebug::beginInstruction(const MachineInstr *MI) {
2132
2133
// If the line changed, we call that a new statement; unless we went to
2133
2134
// line 0 and came back, in which case it is not a new statement.
2134
2135
unsigned OldLine = PrevInstLoc ? PrevInstLoc.getLine () : LastAsmLine;
2135
- if (DL.getLine () && DL.getLine () != OldLine)
2136
+ if (DL.getLine () && ( DL.getLine () != OldLine || ForceIsStmt) )
2136
2137
Flags |= DWARF2_FLAG_IS_STMT;
2137
2138
2138
2139
const MDNode *Scope = DL.getScope ();
@@ -2308,6 +2309,143 @@ DwarfDebug::emitInitialLocDirective(const MachineFunction &MF, unsigned CUID) {
2308
2309
return PrologEndLoc;
2309
2310
}
2310
2311
2312
+ // / For the function \p MF, finds the set of instructions which may represent a
2313
+ // / change in line number from one or more of the preceding MBBs. Stores the
2314
+ // / resulting set of instructions, which should have is_stmt set, in
2315
+ // / ForceIsStmtInstrs.
2316
+ void DwarfDebug::findForceIsStmtInstrs (const MachineFunction *MF) {
2317
+ ForceIsStmtInstrs.clear ();
2318
+
2319
+ // For this function, we try to find MBBs where the last source line in every
2320
+ // block predecessor matches the first line seen in the block itself; for
2321
+ // every such MBB, we set is_stmt=false on the first line in the block, and
2322
+ // for every other block we set is_stmt=true on the first line.
2323
+ // For example, if we have the block %bb.3, which has 2 predecesors %bb.1 and
2324
+ // %bb.2:
2325
+ // bb.1:
2326
+ // $r3 = MOV64ri 12, debug-location !DILocation(line: 4)
2327
+ // JMP %bb.3, debug-location !DILocation(line: 5)
2328
+ // bb.2:
2329
+ // $r3 = MOV64ri 24, debug-location !DILocation(line: 5)
2330
+ // JMP %bb.3
2331
+ // bb.3:
2332
+ // $r2 = MOV64ri 1
2333
+ // $r1 = ADD $r2, $r3, debug-location !DILocation(line: 5)
2334
+ // When we examine %bb.3, we first check to see if it contains any
2335
+ // instructions with debug locations, and select the first such instruction;
2336
+ // in this case, the ADD, with line=5. We then examine both of its
2337
+ // predecessors to see what the last debug-location in them is. For each
2338
+ // predecessor, if they do not contain any debug-locations, or if the last
2339
+ // debug-location before jumping to %bb.3 does not have line=5, then the ADD
2340
+ // in %bb.3 must use IsStmt. In this case, all predecessors have a
2341
+ // debug-location with line=5 as the last debug-location before jumping to
2342
+ // %bb.3, so we do not set is_stmt for the ADD instruction - we know that
2343
+ // whichever MBB we have arrived from, the line has not changed.
2344
+
2345
+ const auto *TII = MF->getSubtarget ().getInstrInfo ();
2346
+
2347
+ // We only need to the predecessors of MBBs that could have is_stmt set by
2348
+ // this logic.
2349
+ SmallDenseSet<MachineBasicBlock *, 4 > PredMBBsToExamine;
2350
+ SmallDenseMap<MachineBasicBlock *, MachineInstr *> PotentialIsStmtMBBInstrs;
2351
+ // We use const_cast even though we won't actually modify MF, because some
2352
+ // methods we need take a non-const MBB.
2353
+ for (auto &MBB : *const_cast <MachineFunction *>(MF)) {
2354
+ if (MBB.empty () || MBB.pred_empty ())
2355
+ continue ;
2356
+ for (auto &MI : MBB) {
2357
+ if (MI.getDebugLoc () && MI.getDebugLoc ()->getLine ()) {
2358
+ for (auto *Pred : MBB.predecessors ())
2359
+ PredMBBsToExamine.insert (Pred);
2360
+ PotentialIsStmtMBBInstrs.insert ({&MBB, &MI});
2361
+ break ;
2362
+ }
2363
+ }
2364
+ }
2365
+
2366
+ // For each predecessor MBB, we examine the last line seen before each branch
2367
+ // or logical fallthrough. We use analyzeBranch to handle cases where
2368
+ // different branches have different outgoing lines (i.e. if there are
2369
+ // multiple branches that each have their own source location); otherwise we
2370
+ // just use the last line in the block.
2371
+ for (auto *MBB : PredMBBsToExamine) {
2372
+ auto CheckMBBEdge = [&](MachineBasicBlock *Succ, unsigned OutgoingLine) {
2373
+ auto MBBInstrIt = PotentialIsStmtMBBInstrs.find (Succ);
2374
+ if (MBBInstrIt == PotentialIsStmtMBBInstrs.end ())
2375
+ return ;
2376
+ MachineInstr *MI = MBBInstrIt->second ;
2377
+ if (MI->getDebugLoc ()->getLine () == OutgoingLine)
2378
+ return ;
2379
+ PotentialIsStmtMBBInstrs.erase (MBBInstrIt);
2380
+ ForceIsStmtInstrs.insert (MI);
2381
+ };
2382
+ // If this block is empty, we conservatively assume that its fallthrough
2383
+ // successor needs is_stmt; we could check MBB's predecessors to see if it
2384
+ // has a consistent entry line, but this seems unlikely to be worthwhile.
2385
+ if (MBB->empty ()) {
2386
+ for (auto *Succ : MBB->successors ())
2387
+ CheckMBBEdge (Succ, 0 );
2388
+ continue ;
2389
+ }
2390
+ // If MBB has no successors that are in the "potential" set, due to one or
2391
+ // more of them having confirmed is_stmt, we can skip this check early.
2392
+ if (none_of (MBB->successors (), [&](auto *SuccMBB) {
2393
+ return PotentialIsStmtMBBInstrs.contains (SuccMBB);
2394
+ }))
2395
+ continue ;
2396
+ // If we can't determine what DLs this branch's successors use, just treat
2397
+ // all the successors as coming from the last DebugLoc.
2398
+ SmallVector<MachineBasicBlock *, 2 > SuccessorBBs;
2399
+ auto MIIt = MBB->rbegin ();
2400
+ {
2401
+ MachineBasicBlock *TBB = nullptr , *FBB = nullptr ;
2402
+ SmallVector<MachineOperand, 4 > Cond;
2403
+ bool AnalyzeFailed = TII->analyzeBranch (*MBB, TBB, FBB, Cond);
2404
+ // For a conditional branch followed by unconditional branch where the
2405
+ // unconditional branch has a DebugLoc, that loc is the outgoing loc to
2406
+ // the the false destination only; otherwise, both destinations share an
2407
+ // outgoing loc.
2408
+ if (!AnalyzeFailed && !Cond.empty () && FBB != nullptr &&
2409
+ MBB->back ().getDebugLoc () && MBB->back ().getDebugLoc ()->getLine ()) {
2410
+ unsigned FBBLine = MBB->back ().getDebugLoc ()->getLine ();
2411
+ assert (MIIt->isBranch () && " Bad result from analyzeBranch?" );
2412
+ CheckMBBEdge (FBB, FBBLine);
2413
+ ++MIIt;
2414
+ SuccessorBBs.push_back (TBB);
2415
+ } else {
2416
+ // For all other cases, all successors share the last outgoing DebugLoc.
2417
+ SuccessorBBs.assign (MBB->succ_begin (), MBB->succ_end ());
2418
+ }
2419
+ }
2420
+
2421
+ // If we don't find an outgoing loc, this block will start with a line 0.
2422
+ // It is possible that we have a block that has no DebugLoc, but acts as a
2423
+ // simple passthrough between two blocks that end and start with the same
2424
+ // line, e.g.:
2425
+ // bb.1:
2426
+ // JMP %bb.2, debug-location !10
2427
+ // bb.2:
2428
+ // JMP %bb.3
2429
+ // bb.3:
2430
+ // $r1 = ADD $r2, $r3, debug-location !10
2431
+ // If these blocks were merged into a single block, we would not attach
2432
+ // is_stmt to the ADD, but with this logic that only checks the immediate
2433
+ // predecessor, we will; we make this tradeoff because doing a full dataflow
2434
+ // analysis would be expensive, and these situations are probably not common
2435
+ // enough for this to be worthwhile.
2436
+ unsigned LastLine = 0 ;
2437
+ while (MIIt != MBB->rend ()) {
2438
+ if (auto DL = MIIt->getDebugLoc (); DL && DL->getLine ()) {
2439
+ LastLine = DL->getLine ();
2440
+ break ;
2441
+ }
2442
+ ++MIIt;
2443
+ }
2444
+ for (auto *Succ : SuccessorBBs)
2445
+ CheckMBBEdge (Succ, LastLine);
2446
+ }
2447
+ }
2448
+
2311
2449
// Gather pre-function debug information. Assumes being called immediately
2312
2450
// after the function entry point has been emitted.
2313
2451
void DwarfDebug::beginFunctionImpl (const MachineFunction *MF) {
@@ -2326,6 +2464,8 @@ void DwarfDebug::beginFunctionImpl(const MachineFunction *MF) {
2326
2464
// Record beginning of function.
2327
2465
PrologEndLoc = emitInitialLocDirective (
2328
2466
*MF, Asm->OutStreamer ->getContext ().getDwarfCompileUnitID ());
2467
+
2468
+ findForceIsStmtInstrs (MF);
2329
2469
}
2330
2470
2331
2471
unsigned
0 commit comments