This is an archive of the discontinued LLVM Phabricator instance.

[DSE] Fix a case of invalid dead store elimination
ClosedPublic

Authored by mamai on Dec 17 2021, 12:08 PM.

Details

Summary

Fix isGuaranteedLoopInvariant() check for invariance. The checks for alloca and alloc-like instructions was not valid when the 'KillingDef' was outside of the loop, while the 'CurrentDef' was inside the loop. In that case, the 'KillingDef' only overwrites the definition from the last iteration of the loop, and not the ones of all iterations, therefor it does not make the 'CurrentDef' to be dead.

Fixing issue : https://github.com/llvm/llvm-project/issues/52774

Diff Detail

Event Timeline

mamai created this revision.Dec 17 2021, 12:08 PM
mamai requested review of this revision.Dec 17 2021, 12:08 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 17 2021, 12:08 PM
nikic added a reviewer: nikic.Dec 17 2021, 2:48 PM
nikic added a subscriber: nikic.

From a cursory look, isn't the actual problem here that the malloc() is treated as loop invariant, even though it isn't?

mamai added a comment.Dec 20 2021, 5:58 AM

From a cursory look, isn't the actual problem here that the malloc() is treated as loop invariant, even though it isn't?

Maybe. What I had been told was that this code was not really looking at invariance but at cross iteration dependencies.

mamai updated this revision to Diff 395448.Dec 20 2021, 7:41 AM
mamai edited the summary of this revision. (Show Details)

I realized I didn't ran the tests correctly when I ran it locally, and my patch was breaking a lot of tests. I have modified the patch to not affect the code stores that are not in loops.

Thanks for the patch!

From a cursory look, isn't the actual problem here that the malloc() is treated as loop invariant, even though it isn't?

Maybe. What I had been told was that this code was not really looking at invariance but at cross iteration dependencies.

I originally made the comment about cross-iteration-dependencies (in the same loop), but that was before I had a look at the full test case and the actual problem.

It looks like our handling of alloca/alloc-like instructions is not correct (as @mamai mentioned in Discord as well). Instead of the current check, we should probably just check whether the object is defined in the entry block for now:

   /// Returns true if \p Ptr is guaranteed to be loop invariant for any possible
   /// loop. In particular, this guarantees that it only references a single
   /// MemoryLocation during execution of the containing function.
   bool isGuaranteedLoopInvariant(const Value *Ptr) {
-    auto IsGuaranteedLoopInvariantBase = [this](const Value *Ptr) {
+    auto IsGuaranteedLoopInvariantBase = [](const Value *Ptr) {
       Ptr = Ptr->stripPointerCasts();
-      if (auto *I = dyn_cast<Instruction>(Ptr)) {
-        if (isa<AllocaInst>(Ptr))
-          return true;
-
-        if (isAllocLikeFn(I, &TLI))
-          return true;
-
-        return false;
-      }
+      if (auto *I = dyn_cast<Instruction>(Ptr))
+        return I->getParent() == &I->getFunction()->getEntryBlock();
       return true;
     };
llvm/test/Transforms/DeadStoreElimination/store-after-loop.ll
1

please use the new pass manager syntax (-passes=dse)

22

nit: no need for dse_local or the attributes.

26

imo it would make reading the test easier if that was between %loop1 and %loop2.

33

nit: imo it would improve readability if the values would be explicitly named with descriptive names, .e.g %iv this one and iv.next for %13 and so on.

38

This doesn't seem necessary for the test. Could we just set the field to a constant?

48

Can this loop be simplified so it doesn't need 2 pointer phis? The problem should also be exposed with an integer induction, as long as we use a pointer based on %6?

58

This function should probably return a pointer to the list, otherwise the memory is not used and the stores are practically dead?

62

nit: no need for dso_local.

65

nit: only retain the attributes needed for DSE to treat malloc as 'alloc-like'

66

not used?

mamai updated this revision to Diff 395898.Dec 22 2021, 10:32 AM
mamai edited the summary of this revision. (Show Details)

Thanks @fhahn for your suggestions. I modified both the fix and test case as suggested. I tried to make the testcase as concise and readable as possible while still showing the issue.

Thanks for the update! After addressing the final comments for the test, could you pre-commit the test (with check lines generated using llvm/utils/update_test_checks.py and then update this patch to just show the impact of your fix?

llvm/test/Transforms/DeadStoreElimination/store-after-loop.ll
7

Could you also reference the bug report as PR52774? Could also be included in the file name.

9

This is a case where auto-generating the check lines with llvm/utils/update_test_checks.py would be helpful.

43

nit: this is not a loop any more :)

Also, this probably doesn't need to be in separate BB.

Thanks for the update! After addressing the final comments for the test, could you pre-commit the test (with check lines generated using llvm/utils/update_test_checks.py and then update this patch to just show the impact of your fix?

Do you mean making a first commit with the test case (with the store missing, so that it pass) and the this patch will contain the fix and add the missing store in the test case ?

Thanks for the update! After addressing the final comments for the test, could you pre-commit the test (with check lines generated using llvm/utils/update_test_checks.py and then update this patch to just show the impact of your fix?

Do you mean making a first commit with the test case (with the store missing, so that it pass) and the this patch will contain the fix and add the missing store in the test case ?

exactly

This revision was not accepted when it landed; it landed in state Needs Review.Dec 22 2021, 11:56 AM
This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
fhahn reopened this revision.Dec 22 2021, 12:33 PM
fhahn accepted this revision.

LGTM, thanks!

It would be good to make the title/commit message a bit more descriptive

Instead of

[DSE] Fix a case of invalid dead store elimination

perhaps something like '[DSE] Fix handling of alloc-like instructions in isGuaranteedLoopInvariant`?

This revision is now accepted and ready to land.Dec 22 2021, 12:35 PM
nikic added inline comments.Dec 22 2021, 12:49 PM
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
1215

The code structure in this function no longer makes sense. Please rewrite the whole function to first strip offsets / GEP and then do a single entry block check.

This revision was landed with ongoing or failed builds.Dec 22 2021, 1:16 PM
This revision was automatically updated to reflect the committed changes.
mamai added inline comments.Dec 22 2021, 1:23 PM
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
1215

Sorry, I just saw your comment after comiting. I could change it, but should I open a new differential for that ?

fhahn added inline comments.Dec 23 2021, 8:13 AM
llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp
1215

It's probably easiest to just put up a new review with the requested changes