This is an archive of the discontinued LLVM Phabricator instance.

[DebugInfo][RemoveDIs] Eliminate some debug-intrinsics-affect-codegen errors
AcceptedPublic

Authored by jmorse on May 25 2023, 3:59 AM.

Details

Summary

This is a patch to reduce the effect that debug intrinsics have on codegen -- there are a few flavours of defect delt with here:

  • Setting the DebugLoc of an instruction to one derived from a debug instruction,
  • Counting the size of a block to include debug intrinsics,
  • Examining debug intrinsics in SLPVectoriser (they should all be ignored)
  • Picking an insertion point at a debug intrinsic in SCEVExpander

Not included in this patch are a few scenarios where we insert an existing instruction at a debug intrinsic position: these can have meaningful effects on the stepping behaviour, so we don't want to address them now. The two SCEVExpander scenarios are where the pass is generating new code and doesn't have an opinion on the line numbers.

I haven't written tests for these changes: IMO these changes are obviously correct, and I'd prefer to not test for behaviours that we're actively trying to design away.

Diff Detail

Unit TestsFailed

Event Timeline

jmorse created this revision.May 25 2023, 3:59 AM
Herald added a project: Restricted Project. · View Herald TranscriptMay 25 2023, 3:59 AM
jmorse requested review of this revision.May 25 2023, 3:59 AM

I know I'm a bit of a stickler for it, but my vote would be/I'd still prefer to see test cases for these. To demonstrate the code is exercised/correct, if nothing else. I realize the chance of regressing these fixes is probably relatively small, but I've certainly come across code before and been "I'm not sure why this is here, let's remove it and see what tests fail" in an effort to understand the code.

jryans added a subscriber: jryans.May 30 2023, 4:27 AM
jryans added inline comments.
llvm/lib/IR/BasicBlock.cpp
423–424

It might be to structure this as an if ... else ... so we always test isa<DbgInfoIntrinsic>(&*I) first, instead of unconditionally calling I->getDebugLoc() and then potentially replacing it...? (If you agree, then the same comment applies to quite a few other changes here.)

fdeazeve added inline comments.
llvm/lib/IR/BasicBlock.cpp
423–424

Not to turn this into a bike-shedding discussion but this seems like an important enough pattern that some helper function could live alongside Intrusction::getNextNonDebugInstruction and friends? Something similar to BasicBlock::skipDebugIntrinsics.

I only mention this because an if/else pattern would necessarily imply declaring an uninitialized loc or having a big if/else block, both of which are undesirable.

(NB, this is still high on my priority list, but I'm swimming through a lot of code-soup right now, will be back on this in a day or two)

jmorse added a comment.Jun 8 2023, 4:45 AM

Will shoe-horn in a utility for easier setDebugLoc usage in the next revision, to be clear though, the intention is to delete all this code in the future if we're living in an intrinsic-free paradise by then,

I know I'm a bit of a stickler for it, but my vote would be/I'd still prefer to see test cases for these. To demonstrate the code is exercised/correct, if nothing else. I realize the chance of regressing these fixes is probably relatively small, but I've certainly come across code before and been "I'm not sure why this is here, let's remove it and see what tests fail" in an effort to understand the code.

This feeds into the other ~30 patches that will appear in this series: as it stands, for a large number of optimisation passes we don't test for the exact placement of debug intrinsics (but we should). Seeing how we're planning on changing the mechanism via which debug-info is preserved, through putting more information in iterators [0], if we went for the every-functional-change-gets-a-test approach then this would expand to fully testing debug-info in every optimisation pass.

I really want to improve the testing in this area (we've got ~130 LLVM-IR inputs that are sensitive to our changes that can be promoted into being tests) and the whole area is under-tested as it stands -- but I'd prefer to put the time into testing the later patches, instead of these specific changes where the ultimate goal is to design-out the behaviour. Ideally in ~six months any tests that would be added in this patch could be deleted!

[0] https://discourse.llvm.org/t/rfc-instruction-api-changes-needed-to-eliminate-debug-intrinsics-from-ir/68939

dblaikie accepted this revision.Jun 8 2023, 7:55 AM

Will shoe-horn in a utility for easier setDebugLoc usage in the next revision, to be clear though, the intention is to delete all this code in the future if we're living in an intrinsic-free paradise by then,

I know I'm a bit of a stickler for it, but my vote would be/I'd still prefer to see test cases for these. To demonstrate the code is exercised/correct, if nothing else. I realize the chance of regressing these fixes is probably relatively small, but I've certainly come across code before and been "I'm not sure why this is here, let's remove it and see what tests fail" in an effort to understand the code.

This feeds into the other ~30 patches that will appear in this series: as it stands, for a large number of optimisation passes we don't test for the exact placement of debug intrinsics (but we should). Seeing how we're planning on changing the mechanism via which debug-info is preserved, through putting more information in iterators [0], if we went for the every-functional-change-gets-a-test approach then this would expand to fully testing debug-info in every optimisation pass.

I really want to improve the testing in this area (we've got ~130 LLVM-IR inputs that are sensitive to our changes that can be promoted into being tests) and the whole area is under-tested as it stands -- but I'd prefer to put the time into testing the later patches, instead of these specific changes where the ultimate goal is to design-out the behaviour. Ideally in ~six months any tests that would be added in this patch could be deleted!

[0] https://discourse.llvm.org/t/rfc-instruction-api-changes-needed-to-eliminate-debug-intrinsics-from-ir/68939

Fair enough, though I'm not especially comfortable with it.

This revision is now accepted and ready to land.Jun 8 2023, 7:55 AM
jmorse updated this revision to Diff 529696.Jun 8 2023, 12:26 PM

Add a "getStableDebugLoc" getter in addition to getDebugLoc, the difference being that the former skips debug intrinsics.

I'm going to upload a few more patches and put them in a stack to illustrate the direction of change we're aiming for -- there are a bunch of open questions about how to go about testing them, similar to the discussion above, which'll probably be easier to describe once the changes are visible.

IIUC you're wanting to not add new tests that check for correct intrinsic-call placement, on the grounds that intrinsics are going away and those tests would ultimately be deleted.
If the tests are deleted, then how do we verify that the debug info (in its new form) is correct? The transforms will still transform the IR, and it would be very helpful when trying to track down future debug-info bugs if we still have a way to follow what the brave new world has in it. -dump-after-all is pretty handy in some of these cases, but if it stops showing debug info then future bug analysis may become much more difficult.

Hopefully the promised related patches will demonstrate this,

jmorse added a comment.Jun 8 2023, 1:41 PM

IIUC you're wanting to not add new tests that check for correct intrinsic-call placement, on the grounds that intrinsics are going away and those tests would ultimately be deleted.

Slight difference -- all the changes in this specific patch are for DebugLocs, to avoid "real" instructions setting their locations from debug-instructions. That legitimately will be designed away,

If the tests are deleted, then how do we verify that the debug info (in its new form) is correct? The transforms will still transform the IR, and it would be very helpful when trying to track down future debug-info bugs if we still have a way to follow what the brave new world has in it. -dump-after-all is pretty handy in some of these cases, but if it stops showing debug info then future bug analysis may become much more difficult.

I agree with the overall point that we need to preserve and improve testing of the placement of variable location debug-info, no matter the format. As it stands, in all the patches produced so far, there's a 1 <=> 1 correspondence between dbg.value intrinsics and the new forms we've been experimenting on, so that the two formats can be trivially switched between, and the existing tests can all work. We've also instrumented the printing-passes and asm writers to always write out dbg.values. IMO: that should continue to be the case through all this development, until we get to a discussion on how to textually represent this information, as that lets us talk purely about how to implement (and test) optimisations rather than everything else.

jmorse added a comment.Jun 9 2023, 8:57 AM

NB: I've solicited some more feedback on the general testing approach here [0], although as with my previous post this specific patch is different, as it's to do with protecting DebugLocs from debug intrinsics rather than the placement of debug intrinsics.

[0] https://discourse.llvm.org/t/rfc-instruction-api-changes-needed-to-eliminate-debug-intrinsics-from-ir/68939/6

Slight difference -- all the changes in this specific patch are for DebugLocs, to avoid "real" instructions setting their locations from debug-instructions. That legitimately will be designed away,

That's not what the patch description says; it's about eliminating codegen errors. Are you mixing two patches into one? I've commented on the ones that look like codegen fixes.

Now, about testing... like @dblaikie I'm not very comfortable with this no-testing business, although I see he accepted the patch already. Are the DebugLoc changes in fact NFC? Taking the DebugLoc from non-debug instructions changes nothing? I know we have next to no tests for this sort of thing, so maybe there's no immediate value in generating a bunch, but I wanted to know whether the intent is just to prep for eliminating debug instructions, or actually making things better in the source-location aspect.

As for the gnochange bits, those are functional changes and we will not reach the Promised Land of no debug instructions for at least one additional release. Given past contentiousness over IR transform tests and debug info, I'd feel a whole lot better if we had tests--with checks generated by the scripts that the IR-transform mavens want to use--to make sure we don't regress in the meantime.

llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp
1889

Looks like a gnochange fix.

llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp
5351

Double semicolon at the end.
Is this strictly a performance improvement? (in which case possibly the "Ignore debug intrinsics" loop a few lines above can go away?)
Or if we find a debug instruction does this prematurely break out of the loop (making it a gnochange bug)? I guess it depends on how isInsertedInstruction responds; I don't mess around inside optimizations enough to know.

llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp
102

This looks like a gnochange fix.

150

This looks like a gnochange fix.

llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
3391

This looks like a gnochange fix.

3424

This looks like a gnochange fix.

11139

Another gnochange fix?

11287

This looks like a gnochange fix.

11329

This looks like a gnochange fix.

11342

This looks like a gnochange fix.

11443

This looks like a gnochange fix.

11463

This looks like a gnochange fix.

11486

This looks like a gnochange fix.

11570

This looks like a gnochange fix.

11610

This looks like a gnochange fix.

11638

This looks like a gnochange fix.

11653

This looks like a gnochange fix.