[llvm] r311057 - Reapply: [ADCE][Dominators] Teach ADCE to preserve dominators

Jakub (Kuba) Kuderski via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 22 09:37:08 PDT 2017


I reapplied this patch in r311467. I added Daniel's IR as a new regression
test. Turns out I forgot to update it to use the batch updater, but it
worked well enough to stay unnoticed for a couple of days...

On Tue, Aug 22, 2017 at 2:16 PM, Daniel Sanders <daniel_l_sanders at apple.com>
wrote:

> Thanks
>
>
> On 21 Aug 2017, at 22:01, Jakub (Kuba) Kuderski <kubakuderski at gmail.com>
> wrote:
>
> This patch is temporarily reverted by r311381.
>
> On Mon, Aug 21, 2017 at 7:24 PM, Jakub (Kuba) Kuderski <
> kubakuderski at gmail.com> wrote:
>
>> Hi Daniel,
>>
>> Thanks for reporting the bug.
>>
>> Would I be right in thinking that TreeNodePtr::getLevel() returns the
>>> depth in the dominator tree?
>>
>> Correct.
>>
>>  If so, I think that the update to indicate that %four dominates %exit
>>> when the %switch->%default path is deleted is causing %exit to be
>>> misidentified as unreachable in the later updates because
>>> DescendAndCollect() is only checking the depth of the successors it finds.
>>> If %exit had been updated after all the removals then it would have turned
>>> out ok.
>>
>> I don't have any recent LLVM revision on my machine at the moment, so
>> it's a bit difficult for me to follow just the description. I'll take a
>> look at it tomorrow. In the meanwhile, feel free to revert the ADCE patch.
>>
>> Best,
>> Kuba
>>
>> On Mon, Aug 21, 2017 at 7:11 PM, Daniel Sanders <
>> daniel_l_sanders at apple.com> wrote:
>>
>>> Hi,
>>>
>>> I'm currently seeing a crash in ADCE which I've narrowed down to this
>>> commit. Given this bugpoint-reduced test case:
>>> define void @foo() {
>>> entry:
>>>   br label %switch
>>> switch:                    ; preds = %entry
>>>   switch i32 undef, label %default [
>>>     i32 2, label %two
>>>     i32 5, label %five
>>>     i32 4, label %four
>>>   ]
>>> four:                      ; preds = %switch
>>>   br label %exit
>>> five:                      ; preds = %switch
>>>   br label %exit
>>> two:                       ; preds = %switch
>>>   br label %exit
>>> default:                   ; preds = %switch
>>>   br label %exit
>>> exit:                      ; preds = %default, %two, %five, %four
>>>   ret void
>>> }
>>> the command './bin/opt bugpoint-reduced-simplified.ll -adce -S -o -'
>>> asserts with:
>>> Assertion failed: (TN), function operator(), file
>>> ../llvm/include/llvm/Support/GenericDomTreeConstruction.h, line 1031.
>>> Stack dump:
>>> 0. Program arguments: ./bin/opt bugpoint-reduced-simplified.ll -adce -S
>>> -o -
>>> 1. Running pass 'Function Pass Manager' on module
>>> 'bugpoint-reduced-simplified.ll'.
>>> 2. Running pass 'Aggressive Dead Code Elimination' on function '@foo'
>>> Abort trap: 6
>>>
>>> According to the -debug output and some additional instrumentation, ADCE
>>> starts by re-writing the switch to a 'br label %four'. I was expecting it
>>> to choose %default but all choices are equivalent so it doesn't matter
>>> much. At this point it deletes the %switch->%default CFG edge, erases
>>> %default, and updates the dominator tree to indicate that %four dominates
>>> %exit. It then deletes the %switch->%two CFG edge and it's at this point
>>> that things start to go wrong.
>>>
>>> After deleting the %switch->%two edge it erases %two but it also erases
>>> %exit which is still being used by %four (as well as %default, %two, and
>>> %five). The dominator tree is correctly updated to reflect the removal of
>>> both %two and %exit. It then proceeds to delete the %switch->%five edge and
>>> hits the assertion when it attempts to look up a TreeNodePtr for %exit and
>>> doesn't find one.
>>>
>>> I'm currently thinking that this is a processing order issue. Would I be
>>> right in thinking that TreeNodePtr::getLevel() returns the depth in the
>>> dominator tree? If so, I think that the update to indicate that %four
>>> dominates %exit when the %switch->%default path is deleted is causing %exit
>>> to be misidentified as unreachable in the later updates because
>>> DescendAndCollect() is only checking the depth of the successors it finds.
>>> If %exit had been updated after all the removals then it would have turned
>>> out ok.
>>>
>>> On 17 Aug 2017, at 02:41, Jakub Kuderski via llvm-commits <
>>> llvm-commits at lists.llvm.org> wrote:
>>>
>>> Author: kuhar
>>> Date: Wed Aug 16 18:41:49 2017
>>> New Revision: 311057
>>>
>>> URL: http://llvm.org/viewvc/llvm-project?rev=311057&view=rev
>>> Log:
>>> Reapply: [ADCE][Dominators] Teach ADCE to preserve dominators
>>>
>>> Summary:
>>> This patch teaches ADCE to preserve both DominatorTrees and
>>> PostDominatorTrees.
>>>
>>> I didn't notice any performance impact when bootstrapping clang with
>>> this patch.
>>>
>>> The patch was originally committed in r311039 and reverted in r311049.
>>> This revision fixes the problem with not adding a dependency on the
>>> DominatorTreeWrapperPass for the LegacyPassManager.
>>>
>>> Reviewers: dberlin, chandlerc, sanjoy, davide, grosser, brzycki
>>>
>>> Reviewed By: davide
>>>
>>> Subscribers: grandinj, zhendongsu, llvm-commits, david2050
>>>
>>> Differential Revision: https://reviews.llvm.org/D35869
>>>
>>> Added:
>>>    llvm/trunk/test/Transforms/ADCE/domtree-DoubleDeletion.ll
>>>    llvm/trunk/test/Transforms/ADCE/unreachable.ll
>>> Modified:
>>>    llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h
>>>    llvm/trunk/lib/Transforms/Scalar/ADCE.cpp
>>>
>>> Modified: llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/
>>> Support/GenericDomTreeConstruction.h?rev=311057&r1=311056&r2
>>> =311057&view=diff
>>> ============================================================
>>> ==================
>>> --- llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h
>>> (original)
>>> +++ llvm/trunk/include/llvm/Support/GenericDomTreeConstruction.h Wed
>>> Aug 16 18:41:49 2017
>>> @@ -914,7 +914,12 @@ struct SemiNCAInfo {
>>>     if (!FromTN) return;
>>>
>>>     const TreeNodePtr ToTN = DT.getNode(To);
>>> -    assert(ToTN && "To already unreachable -- there is no edge to
>>> delete");
>>> +    if (!ToTN) {
>>> +      DEBUG(dbgs() << "\tTo (" << BlockNamePrinter(To)
>>> +                   << ") already unreachable -- there is no edge to
>>> delete\n");
>>> +      return;
>>> +    }
>>> +
>>>     const NodePtr NCDBlock = DT.findNearestCommonDominator(From, To);
>>>     const TreeNodePtr NCD = DT.getNode(NCDBlock);
>>>
>>>
>>> Modified: llvm/trunk/lib/Transforms/Scalar/ADCE.cpp
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transform
>>> s/Scalar/ADCE.cpp?rev=311057&r1=311056&r2=311057&view=diff
>>> ============================================================
>>> ==================
>>> --- llvm/trunk/lib/Transforms/Scalar/ADCE.cpp (original)
>>> +++ llvm/trunk/lib/Transforms/Scalar/ADCE.cpp Wed Aug 16 18:41:49 2017
>>> @@ -27,6 +27,7 @@
>>> #include "llvm/IR/BasicBlock.h"
>>> #include "llvm/IR/CFG.h"
>>> #include "llvm/IR/DebugInfoMetadata.h"
>>> +#include "llvm/IR/Dominators.h"
>>> #include "llvm/IR/IRBuilder.h"
>>> #include "llvm/IR/InstIterator.h"
>>> #include "llvm/IR/Instructions.h"
>>> @@ -89,6 +90,10 @@ struct BlockInfoType {
>>>
>>> class AggressiveDeadCodeElimination {
>>>   Function &F;
>>> +
>>> +  // ADCE does not use DominatorTree per se, but it updates it to
>>> preserve the
>>> +  // analysis.
>>> +  DominatorTree &DT;
>>>   PostDominatorTree &PDT;
>>>
>>>   /// Mapping of blocks to associated information, an element in
>>> BlockInfoVec.
>>> @@ -157,9 +162,10 @@ class AggressiveDeadCodeElimination {
>>>   void makeUnconditional(BasicBlock *BB, BasicBlock *Target);
>>>
>>> public:
>>> -  AggressiveDeadCodeElimination(Function &F, PostDominatorTree &PDT)
>>> -      : F(F), PDT(PDT) {}
>>> -  bool performDeadCodeElimination();
>>> + AggressiveDeadCodeElimination(Function &F, DominatorTree &DT,
>>> +                               PostDominatorTree &PDT)
>>> +     : F(F), DT(DT), PDT(PDT) {}
>>> + bool performDeadCodeElimination();
>>> };
>>> }
>>>
>>> @@ -557,14 +563,31 @@ void AggressiveDeadCodeElimination::upda
>>>     }
>>>     assert((PreferredSucc && PreferredSucc->PostOrder > 0) &&
>>>            "Failed to find safe successor for dead branch");
>>> +
>>> +    // Collect removed successors to update the (Post)DominatorTrees.
>>> +    SmallPtrSet<BasicBlock *, 4> RemovedSuccessors;
>>>     bool First = true;
>>>     for (auto *Succ : successors(BB)) {
>>> -      if (!First || Succ != PreferredSucc->BB)
>>> +      if (!First || Succ != PreferredSucc->BB) {
>>>         Succ->removePredecessor(BB);
>>> -      else
>>> +        RemovedSuccessors.insert(Succ);
>>> +      } else
>>>         First = false;
>>>     }
>>>     makeUnconditional(BB, PreferredSucc->BB);
>>> +
>>> +    // Inform the dominators about the deleted CFG edges.
>>> +    for (auto *Succ : RemovedSuccessors) {
>>> +      // It might have happened that the same successor appeared
>>> multiple times
>>> +      // and the CFG edge wasn't really removed.
>>> +      if (Succ != PreferredSucc->BB) {
>>> +        DEBUG(dbgs() << "ADCE: Removing (Post)DomTree edge " <<
>>> BB->getName()
>>> +                     << " -> " << Succ->getName() << "\n");
>>> +        DT.deleteEdge(BB, Succ);
>>> +        PDT.deleteEdge(BB, Succ);
>>> +      }
>>> +    }
>>> +
>>>     NumBranchesRemoved += 1;
>>>   }
>>> }
>>> @@ -609,6 +632,9 @@ void AggressiveDeadCodeElimination::make
>>>   InstInfo[NewTerm].Live = true;
>>>   if (const DILocation *DL = PredTerm->getDebugLoc())
>>>     NewTerm->setDebugLoc(DL);
>>> +
>>> +  InstInfo.erase(PredTerm);
>>> +  PredTerm->eraseFromParent();
>>> }
>>>
>>> //===-------------------------------------------------------
>>> ---------------===//
>>> @@ -617,13 +643,16 @@ void AggressiveDeadCodeElimination::make
>>> //
>>> //===-------------------------------------------------------
>>> ---------------===//
>>> PreservedAnalyses ADCEPass::run(Function &F, FunctionAnalysisManager
>>> &FAM) {
>>> +  auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
>>>   auto &PDT = FAM.getResult<PostDominatorTreeAnalysis>(F);
>>> -  if (!AggressiveDeadCodeElimination(F, PDT).performDeadCodeEliminatio
>>> n())
>>> +  if (!AggressiveDeadCodeElimination(F, DT,
>>> PDT).performDeadCodeElimination())
>>>     return PreservedAnalyses::all();
>>>
>>>   PreservedAnalyses PA;
>>>   PA.preserveSet<CFGAnalyses>();
>>>   PA.preserve<GlobalsAA>();
>>> +  PA.preserve<DominatorTreeAnalysis>();
>>> +  PA.preserve<PostDominatorTreeAnalysis>();
>>>   return PA;
>>> }
>>>
>>> @@ -637,14 +666,23 @@ struct ADCELegacyPass : public FunctionP
>>>   bool runOnFunction(Function &F) override {
>>>     if (skipFunction(F))
>>>       return false;
>>> +
>>> +    auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
>>>     auto &PDT = getAnalysis<PostDominatorTreeW
>>> rapperPass>().getPostDomTree();
>>> -    return AggressiveDeadCodeElimination(F,
>>> PDT).performDeadCodeElimination();
>>> +    return AggressiveDeadCodeElimination(F, DT, PDT)
>>> +        .performDeadCodeElimination();
>>>   }
>>>
>>>   void getAnalysisUsage(AnalysisUsage &AU) const override {
>>> +    // We require DominatorTree here only to update and thus preserve
>>> it.
>>> +    AU.addRequired<DominatorTreeWrapperPass>();
>>>     AU.addRequired<PostDominatorTreeWrapperPass>();
>>>     if (!RemoveControlFlowFlag)
>>>       AU.setPreservesCFG();
>>> +    else {
>>> +      AU.addPreserved<DominatorTreeWrapperPass>();
>>> +      AU.addPreserved<PostDominatorTreeWrapperPass>();
>>> +    }
>>>     AU.addPreserved<GlobalsAAWrapperPass>();
>>>   }
>>> };
>>> @@ -653,6 +691,7 @@ struct ADCELegacyPass : public FunctionP
>>> char ADCELegacyPass::ID = 0;
>>> INITIALIZE_PASS_BEGIN(ADCELegacyPass, "adce",
>>>                       "Aggressive Dead Code Elimination", false, false)
>>> +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
>>> INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
>>> INITIALIZE_PASS_END(ADCELegacyPass, "adce", "Aggressive Dead Code
>>> Elimination",
>>>                     false, false)
>>>
>>> Added: llvm/trunk/test/Transforms/ADCE/domtree-DoubleDeletion.ll
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transfor
>>> ms/ADCE/domtree-DoubleDeletion.ll?rev=311057&view=auto
>>> ============================================================
>>> ==================
>>> --- llvm/trunk/test/Transforms/ADCE/domtree-DoubleDeletion.ll (added)
>>> +++ llvm/trunk/test/Transforms/ADCE/domtree-DoubleDeletion.ll Wed Aug
>>> 16 18:41:49 2017
>>> @@ -0,0 +1,39 @@
>>> +; RUN: opt < %s -gvn -simplifycfg -adce | llvm-dis
>>> +; RUN: opt < %s -gvn -simplifycfg -adce -verify-dom-info | llvm-dis
>>> +
>>> +; This test makes sure that the DominatorTree properly handles
>>> +; deletion of edges that go to forward-unreachable regions.
>>> +; In this case, %land.end is already forward unreachable when
>>> +; the DT gets informed about the deletion of %entry -> %land.end.
>>> +
>>> + at a = common global i32 0, align 4
>>> +
>>> +define i32 @main() {
>>> +entry:
>>> +  %retval = alloca i32, align 4
>>> +  store i32 0, i32* %retval, align 4
>>> +  %0 = load i32, i32* @a, align 4
>>> +  %cmp = icmp ne i32 %0, 1
>>> +  br i1 %cmp, label %land.rhs, label %land.end4
>>> +
>>> +land.rhs:                                         ; preds = %entry
>>> +  %1 = load i32, i32* @a, align 4
>>> +  %tobool = icmp ne i32 %1, 0
>>> +  br i1 %tobool, label %land.rhs1, label %land.end
>>> +
>>> +land.rhs1:                                        ; preds = %land.rhs
>>> +  br label %land.end
>>> +
>>> +land.end:                                         ; preds =
>>> %land.rhs1, %land.rhs
>>> +  %2 = phi i1 [ false, %land.rhs ], [ true, %land.rhs1 ]
>>> +  %land.ext = zext i1 %2 to i32
>>> +  %conv = trunc i32 %land.ext to i16
>>> +  %conv2 = sext i16 %conv to i32
>>> +  %tobool3 = icmp ne i32 %conv2, 0
>>> +  br label %land.end4
>>> +
>>> +land.end4:                                        ; preds = %land.end,
>>> %entry
>>> +  %3 = phi i1 [ false, %entry ], [ %tobool3, %land.end ]
>>> +  %land.ext5 = zext i1 %3 to i32
>>> +  ret i32 0
>>> +}
>>>
>>> Added: llvm/trunk/test/Transforms/ADCE/unreachable.ll
>>> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transfor
>>> ms/ADCE/unreachable.ll?rev=311057&view=auto
>>> ============================================================
>>> ==================
>>> --- llvm/trunk/test/Transforms/ADCE/unreachable.ll (added)
>>> +++ llvm/trunk/test/Transforms/ADCE/unreachable.ll Wed Aug 16 18:41:49
>>> 2017
>>> @@ -0,0 +1,18 @@
>>> +; RUN: opt < %s -adce -simplifycfg | llvm-dis
>>> +; RUN: opt < %s -passes=adce | llvm-dis
>>> +
>>> +define i32 @Test(i32 %A, i32 %B) {
>>> +BB1:
>>> +        br label %BB4
>>> +
>>> +BB2:            ; No predecessors!
>>> +        br label %BB3
>>> +
>>> +BB3:            ; preds = %BB4, %BB2
>>> +        %ret = phi i32 [ %X, %BB4 ], [ %B, %BB2 ]               ; <i32>
>>> [#uses=1]
>>> +        ret i32 %ret
>>> +
>>> +BB4:            ; preds = %BB1
>>> +        %X = phi i32 [ %A, %BB1 ]               ; <i32> [#uses=1]
>>> +        br label %BB3
>>> +}
>>>
>>>
>>> _______________________________________________
>>> llvm-commits mailing list
>>> llvm-commits at lists.llvm.org
>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>>>
>>>
>>>
>>
>>
>> --
>> Jakub Kuderski
>>
>
>
>
> --
> Jakub Kuderski
>
>
>


-- 
Jakub Kuderski
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170822/7bb80ce8/attachment.html>


More information about the llvm-commits mailing list