This is an archive of the discontinued LLVM Phabricator instance.

[DebugInfo] Replace debug uses in replaceUsesOutsideBlock
ClosedPublic

Authored by Orlando on Mar 23 2021, 3:46 AM.

Details

Summary

Value::replaceUsesOutsideBlock doesn't replace debug uses which leads to an
unnecessary reduction in variable location coverage. Fix this, add a unittest for
it, and add a regression test demonstrating the change through instcombine's
replacedSelectWithOperand.

Diff Detail

Event Timeline

Orlando created this revision.Mar 23 2021, 3:46 AM
Orlando requested review of this revision.Mar 23 2021, 3:46 AM
Orlando added a comment.EditedMar 23 2021, 3:58 AM

I wonder if it would be better update Value::replaceUsesWithIf instead, which would reach more code. Though that shape of that change might need some discussion. For instance, would we pass in the MetadataAsValue-ValueAsMetadata-Value debug uses to the predicate, or alternatively, have a a separate predicate for debug uses? wdyt?

Unrelated to my question, here are some fun stats for this patch since I have them to hand. llvm-locstats summary for RelWithDebInfo clang-3.4 built with clang main (@ 9c16621):

=================================================
-the number of debug variables processed: 2635805
-PC ranges covered: 66%
-------------------------------------------------
-total availability: 63%
=================================================

llvm-locstats summary for RelWithDebInfo clang-3.4 built with clang (@ 9c16621) with this patch applied:

=================================================
-the number of debug variables processed: 2655643 (+19,838)
-PC ranges covered: 66% (+1%)
-------------------------------------------------
-total availability: 64% (+1%)
=================================================

Thanks for this! The results are amazing.

llvm/lib/IR/Value.cpp
556–562

Can we factor out this into a separate predicate?

llvm/test/DebugInfo/Generic/instcombine-replaced-select-with-operand.ll
109–112

I guess we don't need tbaa

Thanks for this! The results are amazing.

Thanks for taking a look. And thanks to @jmorse for pointing out this bug to me offline!

llvm/lib/IR/Value.cpp
556–562

Just to check I understand - your suggestion is to change replaceUsesWithIf to accept a new additional predicate which handles these debug uses?

llvm/test/DebugInfo/Generic/instcombine-replaced-select-with-operand.ll
109–112

Probably not, I'll remove it in the next update.

djtodoro added inline comments.Apr 6 2021, 6:37 AM
llvm/lib/IR/Value.cpp
556–562

I vote either for extending the replaceUsesWithIf() or creating a separate static function that has this code.

Orlando updated this revision to Diff 336089.Apr 8 2021, 7:27 AM
Orlando marked an inline comment as done.

+ Remove tbaa metadata from lit test.
+ Fix clang-tidy warning in unittest.
+ Move the code into a new function replaceDbgUsesOutsideBlock.

Hi @djtodoro, is this what you meant?

Sorry for the delay, I was investigating what we could do with replaceUsesWithIf as an alternative. replaceUsesWithIf takes a predicate function which has a Use parameter. Looking at current replaceUsesWithIf call sites I noticed that most of the predicates actually only look at the Use's User rather than the Use itself. I came up with an overload (code below) which accepts a predicate with a User parameter rather than Use. This allows s to use that single predicate for both normal uses and llvm.dbg.* (metadata-as-value value-as-metadata) uses.

Existing replaceUsesWithIf declaration in Value.h:

void replaceUsesWithIf(Value *New, llvm::function_ref<bool(Use &U)> ShouldReplace)

New replaceUsesWithIf overload:

void Value::replaceUsesWithIf(
    Value *New, llvm::function_ref<bool(User *U)> ShouldReplaceIn) {
  assert(New && "Value::replaceUsesWithIf(<null>) is invalid!");
  assert(New->getType() == getType() &&
         "replaceUses of value with new value of different type!");
  SmallVector<User *> Users(users());
  for (auto *U : Users) {
    if (ShouldReplaceIn(U))
      U->replaceUsesOfWith(this, New);
  }
  SmallVector<DbgVariableIntrinsic *> DbgUsers;
  findDbgUsers(DbgUsers, this);
  for (auto *DVI : DbgUsers) {
    if (ShouldReplaceIn(DVI))
      DVI->replaceVariableLocationOp(this, New);
  }
}

Existing replaceUsesWithIf call sites can be updated to use the new User predicate, e.g. the change to this patch would be:

@@ -564,8 +555,9 @@ void Value::replaceUsesOutsideBlock(Value *New, BasicBlock *BB) {
          "replaceUses of value with new value of different type!");
   assert(BB && "Basic block that may contain a use of 'New' must be defined\n");
 
+  replaceUsesWithIf(New, [BB](User *U) {
+      auto *I = dyn_cast<Instruction>(U);
-  replaceDbgUsesOutsideBlock(this, New, BB);
-  replaceUsesWithIf(New, [BB](Use &U) {
-    auto *I = dyn_cast<Instruction>(U.getUser());
     // Don't replace if it's an instruction in the BB basic block.
     return !I || I->getParent() != BB;
   });

The benefit of this is that most replaceUsesWithIf calls can handle llvm.dbg.* updates with a minimal change. The downsides are that it touches more code, and creates a slightly confusing interface where one replaceUsesWithIf overload updates debug uses and the other does not. So, maybe it's better to keep the fix simple (the patch as it exists in review now) - I'm unsure. wdyt?

Thanks! LGTM like this...

(I vote for this simple code change rather than introducing this overloading, but please wait for couple of more days, so we can see if someone else has a different opinion.)

Orlando marked 2 inline comments as done.Apr 12 2021, 7:33 AM

Thanks! LGTM like this...

(I vote for this simple code change rather than introducing this overloading, but please wait for couple of more days, so we can see if someone else has a different opinion.)

Thanks @djtodoro. Sure, I will leave this up a few days before landing.

Thanks! LGTM like this...

(I vote for this simple code change rather than introducing this overloading, but please wait for couple of more days, so we can see if someone else has a different opinion.)

Thanks @djtodoro. Sure, I will leave this up a few days before landing.

I came to do this just now but noticed that this patch isn't "Accepted". @djtodoro is this intentional? I'm happy to wait for another reviewer if so but I just wanted to check.

djtodoro accepted this revision.Apr 15 2021, 7:12 AM

LGTM from my side :)

This revision is now accepted and ready to land.Apr 15 2021, 7:12 AM
This revision was landed with ongoing or failed builds.Apr 15 2021, 8:20 AM
This revision was automatically updated to reflect the committed changes.

Landing this tripped up some build bots (e.g. https://lab.llvm.org/buildbot/#/builders/109/builds/12664). I've created D100632 which should fix the issue iiuc.

nikic added a subscriber: nikic.Apr 5 2023, 7:54 AM

Please either convert the llvm/test/DebugInfo/Generic/instcombine-replaced-select-with-operand.ll test to use opaque pointers, or delete it if it's not relevant anymore (the thing it currently tests is based on pointer bitcasts).

Herald added a project: Restricted Project. · View Herald TranscriptApr 5 2023, 7:54 AM

Please either convert the llvm/test/DebugInfo/Generic/instcombine-replaced-select-with-operand.ll test to use opaque pointers, or delete it if it's not relevant anymore (the thing it currently tests is based on pointer bitcasts).

Done in 1a0653a80dee2b0db5fb44f50777153fb7690a4f. I just replaced the typed pointers with opaque pointers because that still stimulates the code-path we want to test here (I checked the test still fails when the code change is reverted). If that's weird or not in keeping, the next option is to regenerate from the source, and if that doesn't work then I think dropping the test wouldn't be the end of the world given we have unittest coverage of the underlying functionality.

nikic added a comment.Apr 5 2023, 8:32 AM

Please either convert the llvm/test/DebugInfo/Generic/instcombine-replaced-select-with-operand.ll test to use opaque pointers, or delete it if it's not relevant anymore (the thing it currently tests is based on pointer bitcasts).

Done in 1a0653a80dee2b0db5fb44f50777153fb7690a4f. I just replaced the typed pointers with opaque pointers because that still stimulates the code-path we want to test here (I checked the test still fails when the code change is reverted). If that's weird or not in keeping, the next option is to regenerate from the source, and if that doesn't work then I think dropping the test wouldn't be the end of the world given we have unittest coverage of the underlying functionality.

Thanks! I was mainly uncertain because the bitcast will now just get optimized away and not folded into the select or similar. But if this still covers the relevant codepath, that's great.