[PATCH] D18762: Add Aggressive Control Dead Code Elimination
Mehdi Amini via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 25 16:55:39 PDT 2016
> On Apr 25, 2016, at 4:30 PM, David Callahan <dcallahan at fb.com> wrote:
>
> New to this process so forgive the learningsÅ
> Are the comments below intended to be reflected in phabricator (because
> they are not at the moment) or is it a separate email discussion?
Phabricator does not cope with inlined comments in email. And unfortunately some people seems allergic to the web interface, so it makes the reviews harder.
--
Mehdi
> Comments inline...
>
> On 4/25/16, 3:42 PM, "mehdi.amini at apple.com on behalf of Mehdi Amini"
> <mehdi.amini at apple.com> wrote:
>
>>
>>
>> Sent from my iPhone
>>
>>> On Apr 25, 2016, at 3:38 PM, Justin Bogner <mail at justinbogner.com>
>>> wrote:
>>>
>>> Mehdi AMINI via llvm-commits <llvm-commits at lists.llvm.org> writes:
>>>> (added llvm-commits as subscriber)
>>>
>>> Seems like phab didn't send a patch with the summary, so there isn't any
>>> rationale on the list as to what this is about.
>>>
>>
>> I think I'll never understand this position...
>>
>> https://urldefense.proofpoint.com/v2/url?u=http-3A__reviews.llvm.org_file_
>> data_g5nfdlo5z2lydyefkdsr_PHID-2DFILE-2Dsfs3b7gzuupa35nv2jgg_D18762.diff&d
>> =CwIFAg&c=5VD0RTtNlTh3ycd41b3MUw&r=lFyiPUrFdOHdaobP7i4hoA&m=9JkXH0KSFTIbeS
>> L_jgglMtkxqfMt3c6zp--9Gg9ehIs&s=s9dqiatiE6Z2g28VKpZnFiLQDJRhce3OAL5RKzKZdY
>> k&e=
>>
>>
>> --
>> Mehdi
>
>
> I did not follow this. Was a reference into the patch or a comment about
> phabricator?
>
>
>>
>>
>>> David Callahan <dcallahan at fb.com> writes:
>>>> david2050 updated this revision to Diff 54871.
>>>> david2050 added a comment.
>>>>
>>>> Udate to recent ADCE changes
>>>
>>> I haven't looked at this in detail or thought too much about the
>>> implications, but I have a few drive by comments inline below.
>
>
> Thank you.
>
>
>>>
>>>>
>>>>
>>>> https://urldefense.proofpoint.com/v2/url?=http-3A__reviews.llvm.org_D18
>>>> 762&d=CwIFAg&c=5VD0RTtNlTh3ycd41b3MUw&r=lFyiPUrFdOHdaobP7i4oA&m=9JkXH0K
>>>> SFTIbeSL_jgglMtkxqfMt3c6zp--9Gg9ehIs&s=B84iHrdJiU7pRu4PJQDp5zAP-pfVk6pOc>>>-exRNXciWM&e=
>>>>
>>>> Files:
>>>> include/llvm/InitializePasses.h
>>>> include/llvm/LinkAllPasses.h
>>>> include/llvm/Transforms/Scalar.h
>>>> include/llvm/Transforms/Scalar/ACDCE.h
>>>> lib/Passes/PassBuilder.cpp
>>>> lib/Passes/PassRegistry.def
>>>> lib/Transforms/IPO/PassManagerBuilder.cpp
>>>> lib/Transforms/Scalar/ACDCE.cpp
>>>> lib/Transforms/Scalar/CMakeLists.txt
>>>> lib/Transforms/Scalar/Scalar.cpp
>>>> test/Transforms/ADCE/2002-01-31-UseStuckAroundll
>>>> test/Transforms/ADCE/2002-05-22-PHITest.ll
>>>> test/Transforms/ADCE/2002-05-23-ZeroArgPHITest.ll
>>>> test/Transforms/ADCE/2002-05-28-Crash-distilled.ll
>>>> test/Transforms/ADCE/2002-0-28-Crash.ll
>>>> test/Transforms/ADCE/2002-07-17-AssertionFailure.ll
>>>> tst/Transforms/ADCE/2002-07-17-PHIAssertion.ll
>>>> test/Transforms/ADCE/2002-07-29-Segfault.ll
>>>> tst/Transforms/ADCE/2003-01-22-PredecessorProblem.ll
>>>> test/Transforms/ADCE/2003-0-25-PHIPostDominateProblem.ll
>>>> test/Transforms/ADCE/2003-06-11-InvalidCFG.ll
>>>> test/Transforms/ADCE/2003-06-24-BadSuccessor.ll
>>>> test/Transforms/ADCE/2003-06-24-BasicFunctionality.ll
>>>> test/Transforms/ADCE/2003-09-10-UnwindInstFail.ll
>>>> test/Transforms/ADCE/2003-09-15-InfLoopCrash.ll
>>>> test/Transforms/ADCE/2003-11-16-MissingPostDominanceInfo.ll
>>>> test/Transforms/ADCE/2004-05-04-UnreachableBlock.ll
>>>> test/Transforms/ADCE/2005-02-17-PHI-Invoke-Crash.ll
>>>> test/Transforms/ADCE/basictest.ll
>>>> test/Transforms/ADCE/basictest1.ll
>>>> test/Transforms/ADCE/basictest2.ll
>>>> test/Transforms/ADCE/unreachable-function.ll
>>>>
>>>> Inex: test/Transforms/ADCE/unreachable-function.ll
>>>> ==================================================================
>>>> --- test/Transforms/ADCE/unreachable-function.ll
>>>> ++ test/Transforms/ADCE/unreachable-function.ll
>>>> @@ -1,4 +1,5 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>
>>> Usually each transform gets its own test directory, rather than extra
>>> run lines in an existing one. Where are the tests that show this does
>>> anythng differently than the existing ADCE pass?
>
> Some of the tests just verify compilation without fault and where it
> matters, the FileCheck so where additional
> Work is done beyond the base. There were enough of these that it was not
> clear additional tests were needed.
> I would expect in the fullness of time to completely replace ADCE with
> ACDCE and would rename the tests at that point.
>
>>>
>>>> define void @test() {
>>>> unreachable
>>>> Index: test/Transforms/ADCE/basictest2.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/basictest2.ll
>>>> +++ test/Transforms/ADCE/basictest2.ll
>>>> @@ -1,4 +1,7 @@
>>>> ; RUN: opt < %s -adce -simplifycfg | llvm-dis
>>>> +; RUN: opt < %s -acdce -disable-output
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>> +
>>>> %FILE = type { i32, i8*, i8*, i8, i8, i32, i32, i32 }
>>>> %spec_fd_t = type { i32, i32, i32, i8* }
>>>> @__iob = external global [20 x %FILE] ; <[20 x %FILE]*>
>>>> [#uses=1]
>>>> @@ -26,6 +29,7 @@
>>>> %cond266 = icmp sle i32 %reg109, 4 ; <i1> [#uses=1]
>>>> br i1 %cond266, label %bb3, label %bb2
>>>>
>>>> +; CHECK-NOT: bb2:
>>>> bb2: ; preds = %0
>>>> %cast273 = getelementptr [17 x i8], [17 x i8]* @.LC12, i64 0, i64 0
>>>> ; <i8*> [#uses=0]
>>>> br label %bb3
>>>> @@ -52,6 +56,9 @@
>>>> %cond270 = icmp slt i32 %reg1321, %reg1331 ; <i1> [#uses=1]
>>>> br i1 %cond270, label %bb9, label %bb6
>>>>
>>>> +; CHECK-NOT: bb6:
>>>> +; CHECK-NOT: bb7:
>>>> +; CHECK-NOT: bb:
>>>> bb6: ; preds = %bb5
>>>> %reg134 = load i32, i32* @dbglvl ; <i32> [#uses=1]
>>>> %cond271 = icmp sle i32 %reg134, 4 ; <i1> [#uses=1]
>>>> @@ -79,6 +86,7 @@
>>>> %cond272 = icmp sle i32 %reg163, 4 ; <i1> [#uses=1]
>>>> br i1 %cond272, label %bb11, label %bb10
>>>>
>>>> +; CHECK-NOT: bb10:
>>>> bb10: ; preds = %bb9
>>>> %cast279 = getelementptr [4 x i8], [4 x i8]* @.LC11, i64 0, i64 0
>>>> ; <i8*> [#uses=0]
>>>> br label %bb11
>>>> Index: test/Transforms/ADCE/basictest1.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/basictest1.ll
>>>> +++ test/Transforms/ADCE/basictest1.ll
>>>> @@ -1,4 +1,7 @@
>>>> ; RUN: opt < %s -adce -simplifycfg | llvm-dis
>>>> +; RUN: opt < %s -acdce -S | FileCheck %s
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>> +
>>>> %FILE = type { i32, i8*, i8*, i8, i8, i32, i32, i32 }
>>>> %spec_fd_t = type { i32, i32, i32, i8* }
>>>> @__iob = external global [20 x %FILE] ; <[20 x %FILE]*>
>>>> [#uses=1]
>>>> @@ -26,6 +29,8 @@
>>>> %cond266 = icmp sle i32 %reg109, 4 ; <i1> [#uses=1]
>>>> br i1 %cond266, label %bb3, label %bb2
>>>>
>>>> +; CHECK-NOT: bb2:
>>>> +
>>>> bb2: ; preds = %0
>>>> %cast273 = getelementptr [17 x i8], [17 x i8]* @.LC12, i64 0, i64 0
>>>> ; <i8*> [#uses=0]
>>>> br label %bb3
>>>> @@ -52,6 +57,10 @@
>>>> %cond270 = icmp slt i32 %reg1321, %reg1331 ; <i1> [#uses=1]
>>>> br i1 %cond270, label %bb9, label %bb6
>>>>
>>>> +; CHECK-NOT: bb6:
>>>> +; CHECK-NOT: bb7:
>>>> +; CHECK-NOT: bb8:
>>>> +
>>>> bb6: ; preds = %bb5
>>>> %reg134 = load i32, i32* @dbglvl ; <i32> [#uses=1]
>>>> %cond271 = icmp sle i32 %reg134, 4 ; <i1> [#uses=1]
>>>> @@ -79,6 +88,8 @@
>>>> %cond272 = icmp sle i32 %reg163, 4 ; <i1> [#uses=1]
>>>> br i1 %cond272, label %bb11, label %bb10
>>>>
>>>> +; CHECK-NOT: bb10:
>>>> +
>>>> bb10: ; preds = %bb9
>>>> %cast279 = getelementptr [4 x i8], [4 x i8]* @.LC11, i64 0, i64 0
>>>> ; <i8*> [#uses=0]
>>>> br label %bb11
>>>> Index: test/Transforms/ADCE/basictest.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/basictest.ll
>>>> +++ test/Transforms/ADCE/basictest.ll
>>>> @@ -1,5 +1,7 @@
>>>> ; RUN: opt < %s -adce -simplifycfg | llvm-dis
>>>> ; RUN: opt < %s -passes=adce | llvm-dis
>>>> +; RUN: opt < %s -acdce | llvm-dis
>>>> +; RUN: opt < %s -passes=acdce | llvm-dis
>>>>
>>>> define i32 @Test(i32 %A, i32 %B) {
>>>> BB1:
>>>> Index: test/Transforms/ADCE/2005-02-17-PHI-Invoke-Crash.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2005-02-17-PHI-Invoke-Crash.ll
>>>> +++ test/Transforms/ADCE/2005-02-17-PHI-Invoke-Crash.ll
>>>> @@ -1,4 +1,5 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>>
>>>> declare void @strlen()
>>>>
>>>> Index: test/Transforms/ADCE/2004-05-04-UnreachableBlock.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2004-05-04-UnreachableBlock.ll
>>>> +++ test/Transforms/ADCE/2004-05-04-UnreachableBlock.ll
>>>> @@ -1,4 +1,6 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -disable-output
>>>>
>>>> define void @test() {
>>>> entry:
>>>> Index: test/Transforms/ADCE/2003-11-16-MissingPostDominanceInfo.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-11-16-MissingPostDominanceInfo.ll
>>>> +++ test/Transforms/ADCE/2003-11-16-MissingPostDominanceInfo.ll
>>>> @@ -1,4 +1,7 @@
>>>> ; RUN: opt < %s -adce -simplifycfg -S | grep call
>>>> +; RUN: opt < %s -acdce -simplifycfg -S | grep call
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -simplifycfg -S | grep call
>>>> +
>>>> declare void @exit(i32)
>>>>
>>>> define i32 @main(i32 %argc) {
>>>> Index: test/Transforms/ADCE/2003-09-15-InfLoopCrash.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-09-15-InfLoopCrash.ll
>>>> +++ test/Transforms/ADCE/2003-09-15-InfLoopCrash.ll
>>>> @@ -1,4 +1,6 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -disable-output
>>>>
>>>> define i32 @main() {
>>>> br label %loop
>>>> Index: test/Transforms/ADCE/2003-09-10-UnwindInstFail.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-09-10-UnwindInstFail.ll
>>>> +++ test/Transforms/ADCE/2003-09-10-UnwindInstFail.ll
>>>> @@ -1,4 +1,6 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output -acdce-remove-loops
>>>>
>>>> define void @test() personality i32 (...)* @__gxx_personality_v0 {
>>>> br i1 false, label %then, label %endif
>>>> Index: test/Transforms/ADCE/2003-06-24-BasicFunctionality.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-06-24-BasicFunctionality.ll
>>>> +++ test/Transforms/ADCE/2003-06-24-BasicFunctionality.ll
>>>> @@ -1,4 +1,6 @@
>>>> ; RUN: opt < %s -adce -simplifycfg -S | not grep then:
>>>> +; RUN: opt < %s -acdce -S | FileCheck %s
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>>
>>>> define void @dead_test8(i32* %data.1, i32 %idx.1) {
>>>> entry:
>>>> @@ -20,6 +22,10 @@
>>>> %tmp.161 = icmp ne i32 %k.1, %tmp.14 ; <i1>
>>>> [#uses=1]
>>>> br i1 %tmp.161, label %then, label %else
>>>>
>>>> +; CHECK-NOT: %tmp.161
>>>> +; CHECK-NOT: then:
>>>> +; CHECK-NOT: else
>>>> +
>>>> then: ; preds = %no_exit
>>>> %inc.0 = add i32 %k.1, 1 ; <i32> [#uses=1]
>>>> br label %endif
>>>> Index: test/Transforms/ADCE/2003-06-24-BadSuccessor.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-06-24-BadSuccessor.ll
>>>> +++ test/Transforms/ADCE/2003-06-24-BadSuccessor.ll
>>>> @@ -1,4 +1,7 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>> +
>>>> target datalayout = "e-p:32:32"
>>>> %struct..CppObjTypeDesc = type { i32, i16, i16 }
>>>> %struct..TypeToken = type { i32, i16, i16 }
>>>> @@ -30,6 +33,7 @@
>>>> br i1 false, label %no_exit.1, label %loopentry.0
>>>>
>>>> no_exit.1: ; preds = %loopentry.1
>>>> +; CHECK: switch
>>>> switch i32 0, label %label.17 [
>>>> i32 2, label %label.11
>>>> i32 19, label %label.10
>>>> @@ -80,6 +84,7 @@
>>>> then.53: ; preds = %shortcirc_next.7, %label.17
>>>> %SubArrays.8 = phi i32* [ %SubArrays.10, %shortcirc_next.7 ], [
>>>> %SubArrays.10, %label.17 ] ; <i32*> [#uses=1]
>>>> %tmp.1023 = load i32, i32* null ; <i32> [#uses=1]
>>>> +; CHECK-NOT: switch
>>>> switch i32 %tmp.1023, label %loopentry.1 [
>>>> ]
>>>>
>>>> Index: test/Transforms/ADCE/2003-06-11-InvalidCFG.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-06-11-InvalidCFG.ll
>>>> +++ test/Transforms/ADCE/2003-06-11-InvalidCFG.ll
>>>> @@ -1,4 +1,6 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -disable-output
>>>>
>>>> @G = external global i32* ; <i32**> [#uses=1]
>>>>
>>>> Index: test/Transforms/ADCE/2003-04-25-PHIPostDominateProblem.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-04-25-PHIPostDominateProblem.ll
>>>> +++ test/Transforms/ADCE/2003-04-25-PHIPostDominateProblem.ll
>>>> @@ -3,6 +3,8 @@
>>>> ; PHI node is dead, so we just avoid patching up dead PHI nodes.
>>>>
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -acdce -S | FileCheck %s
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>>
>>>> target datalayout = "e-p:32:32"
>>>>
>>>> @@ -14,6 +16,9 @@
>>>> %k.1 = phi i32 [ %k.0, %endif ], [ 0, %entry ] ;
>>>> <i32> [#uses=1]
>>>> br i1 false, label %no_exit, label %return
>>>>
>>>> +; CHECK-NOT: no_exit:
>>>> +; CHECK-NOT: then:
>>>> +; CHECK-NOT: else:
>>>> no_exit: ; preds = %loopentry
>>>> br i1 false, label %then, label %else
>>>>
>>>> Index: test/Transforms/ADCE/2003-01-22-PredecessorProblem.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2003-01-22-PredecessorProblem.ll
>>>> +++ test/Transforms/ADCE/2003-01-22-PredecessorProblem.ll
>>>> @@ -1,14 +1,18 @@
>>>> ; Testcase reduced from 197.parser by bugpoint
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -acdce -S | FileCheck %s
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>>
>>>> define void @conjunction_prune() {
>>>> ; <label>:0
>>>> br label %bb19
>>>>
>>>> +; CHECK-NOT: bb19:
>>>> bb19: ; preds = %bb23, %bb22, %0
>>>> %reg205 = phi i8* [ null, %bb22 ], [ null, %bb23 ], [ null, %0
>>>> ] ; <i8*> [#uses=1]
>>>> br i1 false, label %bb21, label %bb22
>>>>
>>>> +; CHECK-NOT: bb21:
>>>> bb21: ; preds = %bb19
>>>> %cast455 = bitcast i8* %reg205 to i8** ; <i8**>
>>>> [#uses=0]
>>>> br label %bb22
>>>> Index: test/Transforms/ADCE/2002-07-29-Segfault.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-07-29-Segfault.ll
>>>> +++ test/Transforms/ADCE/2002-07-29-Segfault.ll
>>>> @@ -1,4 +1,6 @@
>>>> ; RUN: opt < %s -adce -disable-output
>>>> +; RUN: opt < %s -acdce -disable-output
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -disable-output
>>>>
>>>> define void @test() {
>>>> br label %BB3
>>>> Index: test/Transforms/ADCE/2002-07-17-PHIAssertion.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-07-17-PHIAssertion.ll
>>>> +++ test/Transforms/ADCE/2002-07-17-PHIAssertion.ll
>>>> @@ -1,6 +1,7 @@
>>>> ; This testcase was extracted from the gzip SPEC benchmark
>>>> ;
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -acdce | FileCheck %s
>>>>
>>>> @bk = external global i32 ; <i32*> [#uses=2]
>>>> @hufts = external global i32 ; <i32*> [#uses=1]
>>>> @@ -16,6 +17,8 @@
>>>> bb3: ; preds = %bb2
>>>> br label %UnifiedExitNode
>>>>
>>>> +; CHECK-NOT: bb4:
>>>> +; CHECK-NOT: bb5:
>>>> bb4: ; preds = %bb2
>>>> %reg117 = load i32, i32* @hufts ; <i32> [#uses=2]
>>>> %cond241 = icmp ule i32 %reg117, %reg128 ; <i1>
>>>> [#uses=1]
>>>> Index: test/Transforms/ADCE/2002-07-17-AssertionFailure.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-07-17-AssertionFailure.ll
>>>> +++ test/Transforms/ADCE/2002-07-17-AssertionFailure.ll
>>>> @@ -4,10 +4,12 @@
>>>> ; have to fix now, wouldn't it....
>>>> ;
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -acdce -S | FileCheck %s
>>>>
>>>> define void @foo(i8* %reg5481) {
>>>> %cast611 = bitcast i8* %reg5481 to i8** ; <i8**>
>>>> [#uses=1]
>>>> %reg162 = load i8*, i8** %cast611 ; <i8*> [#uses=1]
>>>> +; CHECK-NOT: ptrtoint
>>>> ptrtoint i8* %reg162 to i32 ; <i32>:1 [#uses=0]
>>>> ret void
>>>> }
>>>> Index: test/Transforms/ADCE/2002-05-28-Crash.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-05-28-Crash.ll
>>>> +++ test/Transforms/ADCE/2002-05-28-Crash.ll
>>>> @@ -12,6 +12,8 @@
>>>> ;}
>>>> ;
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -acdce
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>>
>>>> define i32 @rx_bitset_empty(i32 %size, i32* %set) {
>>>> bb1:
>>>> @@ -30,6 +32,7 @@
>>>> %cond232 = icmp ne i32 %reg125, 0 ; <i1>
>>>> [#uses=1]
>>>> br i1 %cond232, label %bb3, label %bb2
>>>>
>>>> +; CHECK-NOT: bb2:
>>>> bb2: ; preds = %bb2, %bb1
>>>> %cann-indvar = phi i32 [ 0, %bb1 ], [ %add1-indvar, %bb2 ]
>>>> ; <i32> [#uses=2]
>>>> %reg130-scale = mul i32 %cann-indvar, -1 ;
>>>> <i32> [#uses=1]
>>>> Index: test/Transforms/ADCE/2002-05-28-Crash-distilled.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-05-28-Crash-distilled.ll
>>>> +++ test/Transforms/ADCE/2002-05-28-Crash-distilled.ll
>>>> @@ -1,12 +1,15 @@
>>>> ; This testcase is a distilled form of: 2002-05-28-Crash.ll
>>>>
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -acdce
>>>> +; RUN: opt < %s -acdce -acdce-remove-loops -S | FileCheck %s
>>>>
>>>> define float @test(i32 %i) {
>>>> %F = sitofp i32 %i to float ; <float> [#uses=1]
>>>> %I = bitcast i32 %i to i32 ; <i32> [#uses=1]
>>>> br label %Loop
>>>>
>>>> +; CHECK-NOT: Loop:
>>>> Loop: ; preds = %Loop, %0
>>>> %B = icmp ne i32 %I, 0 ; <i1> [#uses=1]
>>>> br i1 %B, label %Out, label %Loop
>>>> Index: test/Transforms/ADCE/2002-05-23-ZeroArgPHITest.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-05-23-ZeroArgPHITest.ll
>>>> +++ test/Transforms/ADCE/2002-05-23-ZeroArgPHITest.ll
>>>> @@ -5,6 +5,8 @@
>>>> ; in with a dummy value before the PHI is deleted.
>>>> ;
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -S -acdce | grep bb1
>>>> +; RUN: opt < %s -S -acdce -acdce-remove-loops | FileCheck %s
>>>>
>>>> %node_t = type { double*, %node_t*, %node_t**, double**,
>>>> double*, i32, i32 }
>>>>
>>>> @@ -14,6 +16,8 @@
>>>> store %node_t* %nodelist, %node_t** %nodelist.upgrd.1
>>>> br label %bb1
>>>>
>>>> +; CHECK-NOT: bb1:
>>>> +; CHECK-NOT: bb2:
>>>> bb1: ; preds = %bb0
>>>> %reg107 = load %node_t*, %node_t** %nodelist.upgrd.1
>>>> ; <%node_t*> [#uses=2]
>>>> %cond211 = icmp eq %node_t* %reg107, null ; <i1>
>>>> [#uses=1]
>>>> Index: test/Transforms/ADCE/2002-05-22-PHITest.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-05-22-PHITest.ll
>>>> +++ test/Transforms/ADCE/2002-05-22-PHITest.ll
>>>> @@ -1,6 +1,7 @@
>>>> ; It is illegal to remove BB1 because it will mess up the PHI node!
>>>> ;
>>>> ; RUN: opt < %s -adce -S | grep BB1
>>>> +; RUN: opt < %s -acdce -S | grep BB1
>>>>
>>>> define i32 @test(i1 %C, i32 %A, i32 %B) {
>>>> ; <label>:0
>>>> Index: test/Transforms/ADCE/2002-01-31-UseStuckAround.ll
>>>> ===================================================================
>>>> --- test/Transforms/ADCE/2002-01-31-UseStuckAround.ll
>>>> +++ test/Transforms/ADCE/2002-01-31-UseStuckAround.ll
>>>> @@ -1,4 +1,5 @@
>>>> ; RUN: opt < %s -adce
>>>> +; RUN: opt < %s -acdce
>>>>
>>>> define i32 @"main"(i32 %argc) {
>>>> br label %2
>>>> Index: lib/Transforms/Scalar/Scalar.cpp
>>>> ===================================================================
>>>> --- lib/Transforms/Scalar/Scalar.cpp
>>>> +++ lib/Transforms/Scalar/Scalar.cpp
>>>> @@ -31,6 +31,7 @@
>>>> /// initializeScalarOptsPasses - Initialize all passes linked into the
>>>> /// ScalarOpts library.
>>>> void llvm::initializeScalarOpts(PassRegistry &Registry) {
>>>> + initializeACDCELegacyPassPass(Registry);
>>>> initializeADCELegacyPassPass(Registry);
>>>> initializeBDCEPass(Registry);
>>>> initializeAlignmentFromAssumptionsPass(Registry);
>>>> @@ -96,6 +97,10 @@
>>>> initializeScalarOpts(*unwrap(R));
>>>> }
>>>>
>>>> +void LLVMAddAggressiveControlDCEPass(LLVMPassManagerRef PM) {
>>>> + unwrap(PM)->add(createAggressiveControlDCEPass());
>>>> +}
>>>> +
>>>> void LLVMAddAggressiveDCEPass(LLVMPassManagerRef PM) {
>>>> unwrap(PM)->add(createAggressiveDCEPass());
>>>> }
>>>> Index: lib/Transforms/Scalar/CMakeLists.txt
>>>> ===================================================================
>>>> --- lib/Transforms/Scalar/CMakeLists.txt
>>>> +++ lib/Transforms/Scalar/CMakeLists.txt
>>>> @@ -1,4 +1,5 @@
>>>> add_llvm_library(LLVMScalarOpts
>>>> + ACDCE.cpp
>>>> ADCE.cpp
>>>> AlignmentFromAssumptions.cpp
>>>> BDCE.cpp
>>>> Index: lib/Transforms/Scalar/ACDCE.cpp
>>>> ===================================================================
>>>> --- /dev/null
>>>> +++ lib/Transforms/Scalar/ACDCE.cpp
>>>> @@ -0,0 +1,1090 @@
>>>> +//===- ACDCE.cpp - Code to perform dead code elimination
>>>> +//-------------------===//
>>>> +//
>>>> +// The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open
>>>> Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> +// This file implements the Aggressive Dead Code Elimination pass.
>>>> This pass
>>>> +// optimistically assumes that all instructions are dead until proven
>>>> otherwise,
>>>> +// allowing it to eliminate dead computations that other DCE passes
>>>> do not
>>>> +// catch, particularly involving loop computations.
>>>
>>> I'm guessing you forgot to update this comment after copying it from
>>> ADCE.cpp - it doesn't tell me what the 'C' stands for ;)
>
> Yes.
>
>>>
>>>> +//
>>>> +//
>>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__groups.google.com_f
>>>> orum_-23-21topic_llvm-2Ddev_j2vlIECKkdE&d=CwIFAg&c=5VD0RTtNlTh3ycd41b3MU
>>>> w&r=lFyiPUrFdOHdaobP7i4hoA&m=9JkXH0KSFTIbeSL_jgglMtkxqfMt3c6zp--9Gg9ehIs
>>>> &s=FA-XXrrUJMcYcp3Rzmy2c0rNlOoB1AkYYMNPioPSSMY&e= -- dead loops
>>>> +// discussion
>>>
>>> Maybe this should mention what's relevant about this particular
>>> discussion? A link to a longish thread from 2010 isn't all that great on
>>> its own.
>
> Agreed, missed in cleanup
>
>>>
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +
>>>> +#include "llvm/Transforms/Scalar/ACDCE.h"
>>>> +
>>>> +#include "llvm/ADT/DenseMap.h"
>>>> +#include "llvm/ADT/PostOrderIterator.h"
>>>> +#include "llvm/ADT/SmallPtrSet.h"
>>>> +#include "llvm/ADT/SmallVector.h"
>>>> +#include "llvm/ADT/Statistic.h"
>>>> +#include "llvm/Analysis/CFGPrinter.h"
>>>> +#include "llvm/Analysis/GlobalsModRef.h"
>>>> +#include "llvm/Analysis/IteratedDominanceFrontier.h"
>>>> +#include "llvm/Analysis/PostDominators.h"
>>>> +#include "llvm/IR/BasicBlock.h"
>>>> +#include "llvm/IR/CFG.h"
>>>> +#include "llvm/IR/DebugInfoMetadata.h"
>>>> +#include "llvm/IR/IRBuilder.h"
>>>> +#include "llvm/IR/InstIterator.h"
>>>> +#include "llvm/IR/Instructions.h"
>>>> +#include "llvm/IR/IntrinsicInst.h"
>>>> +#include "llvm/Pass.h"
>>>> +#include "llvm/ProfileData/InstrProf.h"
>>>> +#include "llvm/Support/Debug.h"
>>>> +#include "llvm/Support/FileSystem.h"
>>>> +#include "llvm/Transforms/Scalar.h"
>>>> +
>>>> +using namespace llvm;
>>>> +
>>>> +#define DEBUG_TYPE "acdce"
>>>> +#define DEBUG_MSG(x) DEBUG(dbgs() << x << '\n';)
>>>
>>> This DEBUG_MSG define is pretty unusual - why not just use DEBUG()
>>> directly like everyone else?
>
> There was a fair amount of redundancy in the simple little debug lines I
> used commonly. Although I do notice it seems comment to remove debugging
> (or at least there is not much left).
>
>>>
>>>> +
>>>> +static cl::opt<bool> RemoveLoops("acdce-remove-loops",
>>>> cl::init(false),
>>>> + cl::Hidden);
>>>> +
>>>> +STATISTIC(NumRemoved, "Number of non-branch instructions removed");
>>>> +STATISTIC(NumBranchesRemoved, "Number of branch instructions
>>>> removed");
>>>> +
>>>> +namespace {
>>>> +
>>>> +// helper functions ...
>>>> +static bool isUnconditional(TerminatorInst *term) {
>>>
>>> static functions don't need to be in an anonymous namespace.
>>>
>>> Also, variable names should start with capital letters. There are a few
>>> places in the patch that should be updated.
>
> Yes.
>
>>>
>>>> + auto br = dyn_cast<BranchInst>(term);
>>>> + return br && br->isUnconditional();
>>>> +}
>>>> +
>>>> +// simplified erase pattern
>>>> +template <typename V, typename Pred> void erase(V *vec, Pred p) {
>>>> + vec->erase(std::remove_if(vec->begin(), vec->end(), p), vec->end());
>>>> +}
>>>> +// a composite transform and copy-if which test for non-null
>>>> +template <class InputIterator, class OutputIterator, class
>>>> UnaryOperator>
>>>> +OutputIterator copy_non_null(InputIterator first1, InputIterator
>>>> last1,
>>>> + OutputIterator result, UnaryOperator op)
>>>> {
>>>> + while (first1 != last1) {
>>>> + auto value = op(*first1);
>>>> + if (value) {
>>>> + *result = value;
>>>> + ++result;
>>>> + }
>>>> + ++first1;
>>>> + }
>>>> + return result;
>>>> +}
>>>> +}
>>>> +
>>>> +namespace llvm {
>>>> +
>>>> +// Specialize po_iterator_storage to identify loop bottoms
>>>> +// which we define simply as back edges in a depth first
>>>> +// traversal of the CFG starting at the entry.
>>>> +class PO_WithLoops;
>>>> +
>>>> +template <> class po_iterator_storage<PO_WithLoops, true> {
>>>> + PO_WithLoops &Storage;
>>>> +
>>>> +public:
>>>> + po_iterator_storage(PO_WithLoops &Storage) : Storage(Storage) {}
>>>> + // These functions are defined below.
>>>> + bool insertEdge(BasicBlock *From, BasicBlock *To);
>>>> + void finishPostorder(BasicBlock *BB);
>>>> +};
>>>> +
>>>> +class PO_WithLoops {
>>>> + typedef SmallPtrSet<BasicBlock *, 32> LoopBottomsType;
>>>> + typedef po_iterator<BasicBlock *, PO_WithLoops, true> POTIterator;
>>>> +
>>>> + Function &F;
>>>> + // Visited[BB] is true while the basic block *BB is on
>>>> + // the stack of being visited nodes and false after
>>>> + // all children have been visited
>>>> + DenseMap<BasicBlock *, bool> Visited;
>>>> + LoopBottomsType LoopBottoms;
>>>> +
>>>> +public:
>>>> + PO_WithLoops(Function &F) : F(F) { Visited.grow(2 * F.size()); }
>>>> + POTIterator begin() { return po_ext_begin(&F.getEntryBlock(),
>>>> *this); }
>>>> + POTIterator end() { return po_ext_end(&F.getEntryBlock(), *this); }
>>>> + bool insertEdge(BasicBlock *From, BasicBlock *To) {
>>>> + auto P = Visited.insert(std::make_pair(To, true));
>>>> + if (P.second) {
>>>> + return true;
>>>> + }
>>>> + if (P.first->second) {
>>>> + // back edge to an ancestor in DFS
>>>> + LoopBottoms.insert(From);
>>>> + }
>>>> + return false;
>>>> + }
>>>> +
>>>> + void finishPostorder(BasicBlock *BB) { Visited[BB] = false; }
>>>> + bool reachable(BasicBlock *BB) const {
>>>> + return (Visited.find(BB) != Visited.end());
>>>> + }
>>>> + const LoopBottomsType &getLoopBottoms() { return LoopBottoms; }
>>>> +};
>>>> +
>>>> +bool po_iterator_storage<PO_WithLoops, true>::insertEdge(BasicBlock
>>>> *From,
>>>> + BasicBlock
>>>> *To) {
>>>> + return Storage.insertEdge(From, To);
>>>> +}
>>>> +void po_iterator_storage<PO_WithLoops,
>>>> true>::finishPostorder(BasicBlock *BB) {
>>>> + Storage.finishPostorder(BB);
>>>> +}
>>>> +}
>>>> +
>>>> +namespace {
>>>> +
>>>> +struct BlockInfoType;
>>>> +/// A Dead Region is a set of dead basic blocks with a common
>>>> +/// post-dominating live block
>>>> +struct DeadRegionInfo {
>>>> + /// true when all blocks have unconditional branches
>>>> + bool Trivial = true; // dead blocks are just unconditional branches
>>>> + /// the set of dead blocks in this region
>>>> + SmallVector<BlockInfoType *, 16> DeadBlocks;
>>>> + /// sources of edges from live nodes into dead ones of this region
>>>> + SmallPtrSet<BlockInfoType *, 16> LivePreds;
>>>> +};
>>>> +
>>>> +/// Information about basic blocks relevant to dead code elimination
>>>> +struct BlockInfoType {
>>>> + /// true when this block contains a live instructions
>>>> + bool Live = false;
>>>> + /// this block ends in an unconditional branch
>>>> + bool UnconditionalBranch = false;
>>>> + /// quick access to the Live flag for the terminator
>>>> + bool *TerminatorLive = nullptr; // == & InstInfo[Terminator].Live
>>>
>>> `bool *` is a pretty unusual type. Wouldn't it be easier to follow if
>>> we kept around a pointer to the InstInfo itself to modify?
>
> Ok
>
>>>
>>>> +
>>>> + bool terminatorIsLive() const { return *TerminatorLive; }
>>>> +
>>>> + /// corresponding BasicBlock
>>>> + BasicBlock *BB = nullptr;
>>>> +
>>>> + /// points to this BB when this block is live, otherwise the most
>>>> immediate
>>>> + /// live post-dominator of BB
>>>> + BasicBlock *LivePostDom = nullptr;
>>>> +
>>>> + TerminatorInst *Terminator = nullptr; ///< cache of
>>>> BB->getTerminator()
>>>> +
>>>> + /// block found to not reach a function return point
>>>> + bool isUnreachable() const { return Terminator == nullptr; }
>>>> +
>>>> + /// the collection of dead blocks which have this block as
>>>> + /// the most-immediate live post-dominator
>>>> + DeadRegionInfo DeadRegion;
>>>> +
>>>> + /// used to control exploration of dead connected components
>>>> + unsigned RegionVisited = 0;
>>>> +};
>>>> +
>>>> +/// Information about Instruction's
>>>> +struct InstInfoType {
>>>> +
>>>> + bool Live = false; ///< true if this unstruction is live
>>>> +
>>>> + /// quick access to information for block containing associated
>>>> Instruction
>>>> + BlockInfoType *Block = nullptr;
>>>> +};
>>>> +
>>>> +/// This class implements analysis to determine instructions
>>>> including branching
>>>> +/// which does not effect the output. Such operations are removed as
>>>> are
>>>> +/// unreachable operations for some scenarions. Dead loops are
>>>> optionally
>>>> +/// removed
>>>> +/// or retained.
>>>> +class AggressiveCDCE {
>>>
>>> I think a longer name is in order - the C is easy to miss in
>>> AggressiveCDCE.
>
> -> AggressiveControlDCE
>
>>>
>>>> + Function &F;
>>>> +
>>>> + /// reverse partial order of blocks with a collection of sources of
>>>> backward
>>>> + /// edges referred to as loop bottoms
>>>> + PO_WithLoops PO;
>>>> + PostDominatorTree &PDT;
>>>> + bool GraphWasModified = false;
>>>> +
>>>> + /// function-level statistics
>>>> + unsigned FuncNumBranchesRemoved = 0;
>>>> + unsigned FuncNumInstRemoved = 0;
>>>> +
>>>> + /// one per basic block in the function
>>>> + std::vector<BlockInfoType> BlockInfoVec;
>>>> +
>>>> + /// mapping of blocks to associated information, element in
>>>> BlockInfoVec
>>>> + DenseMap<BasicBlock *, BlockInfoType *> BlockInfo;
>>>> + bool isLive(BasicBlock *BB) { return BlockInfo[BB]->Live; }
>>>> +
>>>> + /// mapping of instructions to associated information
>>>> + DenseMap<Instruction *, InstInfoType> InstInfo;
>>>> + bool isLive(Instruction *I) { return InstInfo[I].Live; }
>>>> +
>>>> + /// initialize maps and BlockInfoVec
>>>> + void initialize();
>>>> +
>>>> + /// live instructions to be processed or dead instructions to be
>>>> deleted
>>>> + SmallVector<Instruction *, 128> Worklist;
>>>> + SmallPtrSet<const Metadata *, 32> AliveScopes;
>>>> +
>>>> + /// Propagate "live-ness" to definitions which reach "live"
>>>> instructions
>>>> + void markLive();
>>>> + /// Mark I and its containing block as live.
>>>> + void markLive(Instruction *I);
>>>> + void collectLiveScopes(const DILocalScope &LS);
>>>> + void collectLiveScopes(const DILocation &DL);
>>>> +
>>>> + /// true for any instructions which is always treated as live
>>>> + bool alwaysLive(Instruction &I) const;
>>>> +
>>>> + /// vector of blocks with not known to be live terminators,
>>>> + SmallPtrSet<BasicBlock *, 16> BlocksWithDeadTerminators;
>>>> +
>>>> + /// The set of blocks which we have determined are live in the
>>>> + /// most recent pass
>>>> + SmallPtrSet<BasicBlock *, 16> NewLiveBlocks;
>>>> +
>>>> + /// Analyze basic blocks to find to loop bottoms to keep live and
>>>> + /// remove unreachable blocks
>>>> + void analyzeBlocks();
>>>> +
>>>> + /// blocks found to be unreachable when searching for back edges
>>>> + SmallVector<BasicBlock *, 16> UnreachableBlocks;
>>>> + void removeUnreachable(BasicBlock *);
>>>> +
>>>> + /// Analyze dead branches to find those whose branches are the
>>>> sources
>>>> + /// of control dependences impacting a live block. Those branches
>>>> are
>>>> + /// marked live.
>>>> + void checkControlDependences();
>>>> +
>>>> + /// look for phi nodes with complex value which force
>>>> + /// source blocks of reaching values to be treated as live.
>>>> + void checkPhiNodes();
>>>> +
>>>> + typedef SmallPtrSet<BasicBlock *, 8> RegionSetType;
>>>> +
>>>> + /// Traverse the connected component associated with BBInfo where
>>>> + /// nodes whose RegionVisited field is greater than FirstVisit are
>>>> considered
>>>> + /// already 'visited' and we stop at tops of live blocks.
>>>> + /// Set RegionVisited for blocks newly visited to CurrentVisit.
>>>> + /// Record live blocks that are successors of DeadBlocks on this
>>>> + /// componente in LivePdoms
>>>> + void visitRegion(BlockInfoType *, unsigned FirstVisit, unsigned
>>>> CurrentVisit,
>>>> + RegionSetType *LivePdoms);
>>>> +
>>>> + /// Incremented for each new traversal of connected components
>>>> + unsigned LastCurrentVisit = 0;
>>>> +
>>>> + /// Verify that all edges from "dead" predecessors into PN
>>>> + /// have the same associated value. To refine the precision, the
>>>> + /// dead blocks are partitioned into connnected components and
>>>> + /// all definitions associated with predecessor blocks in the same
>>>> + /// connected component must be the same
>>>> + void checkPhiNode(PHINode *PN, unsigned FirstVisit);
>>>> +
>>>> + /// find groups of dead blocks with common live post-dominator
>>>> + /// and rewrite the control flow graph
>>>> + void processDeadRegions();
>>>> +
>>>> + /// Rewrite non-trivial dead regions by redirection incoming live
>>>> + /// control flow to the post-dominator and updating phi-nnodes in
>>>> the
>>>> + /// post-dominator
>>>> + void updateDeadRegion(BasicBlock *BB, DeadRegionInfo *Info);
>>>> +
>>>> + /// adjust BB so it has an unconditional branch to Target
>>>> + /// mark that branch live.
>>>> + void makeUnconditional(BasicBlock *BB, BasicBlock *Target);
>>>> +
>>>> + /// the collection of unconditional branch instructions created
>>>> + /// by makeUnconditional
>>>> + SmallVector<Instruction *, 32> NewBranches;
>>>> +
>>>> + /// for trivial regions, we just mark all the branches as live to be
>>>> + /// cleaned up by other phases
>>>> + void cleanTrivialRegion(const DeadRegionInfo &Info);
>>>> +
>>>> + void removeDeadCode();
>>>> +
>>>> +#ifndef NDEBUG
>>>> + /// the set of live blocks with dead predecessors
>>>> + SmallPtrSet<BasicBlock *, 31> BlocksForPhiValidation;
>>>> +
>>>> + /// verify one value for each predecessor after dead blocks are
>>>> removed
>>>> + void validatePhiNodes(BasicBlock *);
>>>> +#endif
>>>> +
>>>> +public:
>>>> + AggressiveCDCE(Function &F, PostDominatorTree &PDT)
>>>> + : F(F), PO(F), PDT(PDT) {}
>>>> + bool doAggressiveCDCE();
>>>> +};
>>>> +}
>>>> +
>>>> +bool AggressiveCDCE::doAggressiveCDCE() {
>>>> +
>>>> + initialize();
>>>> + markLive();
>>>> + processDeadRegions();
>>>> + removeDeadCode();
>>>> +
>>>> + return GraphWasModified;
>>>> +}
>>>> +
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> +//
>>>> +// Initialize of data structures and identification of
>>>> +// loops and unreachable code
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +void AggressiveCDCE::initialize() {
>>>> +
>>>> + DEBUG(PDT.print(dbgs()));
>>>> +
>>>> + auto NumBlocks = F.size();
>>>> + BlockInfoVec.resize(NumBlocks);
>>>> + BlockInfo.grow(2 * NumBlocks);
>>>> + auto InfoP = BlockInfoVec.begin();
>>>> + size_t NumInsts = 0;
>>>> + for (auto &BB : F) {
>>>> + NumInsts += BB.size();
>>>> + auto &Info = *InfoP;
>>>> + BlockInfo[&BB] = &Info;
>>>> + DEBUG_MSG("initializing block " << BB.getName());
>>>> + Info.BB = &BB;
>>>> + Info.Terminator = BB.getTerminator();
>>>> + Info.UnconditionalBranch = isUnconditional(Info.Terminator);
>>>> + ++InfoP;
>>>> + }
>>>> + if (!RemoveLoops) {
>>>> + // remove unreachable code, identify loop bottoms
>>>> + // to be forced live below.
>>>> + analyzeBlocks();
>>>> + }
>>>> + InstInfo.grow(2 * NumInsts);
>>>> + for (auto &BBInfo : BlockInfoVec) {
>>>> + if (BBInfo.isUnreachable()) { // removed unreachable node
>>>> + continue;
>>>> + }
>>>> + for (Instruction &I : *BBInfo.BB) {
>>>> + auto &IInfo = InstInfo[&I];
>>>> + IInfo.Block = &BBInfo;
>>>> + if (alwaysLive(I)) {
>>>> + markLive(&I);
>>>> + }
>>>> + }
>>>> + }
>>>> +
>>>> + // For blocks which do not reach a function return, mark
>>>> + // them live. Also branches where some reach the return
>>>> + // and some done as live.
>>>> + for (auto &BBInfo : BlockInfoVec) {
>>>> + if (!BBInfo.isUnreachable() && !PDT.getNode(BBInfo.BB)) {
>>>> + markLive(BBInfo.Terminator);
>>>> + for (auto Pred : predecessors(BBInfo.BB)) {
>>>> + DEBUG_MSG("no pdom pred live: " << Pred->getName());
>>>> + markLive(Pred->getTerminator());
>>>> + }
>>>> + }
>>>> + }
>>>> +
>>>> + // mark all loop bottom terminators as live so loops are not
>>>> + // deleted (in case they are infinite)
>>>> + for (auto BB : PO.getLoopBottoms()) {
>>>> + DEBUG_MSG("loop bottom " << BB->getName());
>>>> + markLive(BB->getTerminator());
>>>> + }
>>>> +
>>>> + for (auto &BBInfo : BlockInfoVec) {
>>>> + BBInfo.TerminatorLive = &InstInfo[BBInfo.Terminator].Live;
>>>> + if (! *BBInfo.TerminatorLive) {
>>>> + BlocksWithDeadTerminators.insert(BBInfo.BB);
>>>> + }
>>>> + }
>>>> +
>>>> + // Treat the entry block as always live
>>>> + auto BB = &F.getEntryBlock();
>>>> + auto &EntryInfo = *BlockInfo[BB];
>>>> + EntryInfo.Live = true;
>>>> + EntryInfo.LivePostDom = BB;
>>>> + if (EntryInfo.UnconditionalBranch) {
>>>> + *EntryInfo.TerminatorLive = true;
>>>> + BlocksWithDeadTerminators.erase(BB);
>>>> + }
>>>> +}
>>>> +
>>>> +// Find and remove unreachable code and compute the bottoms of loops
>>>> +// which will be forced live so loops are retained.
>>>> +void AggressiveCDCE::analyzeBlocks() {
>>>> +
>>>> + // This loop drives a Post Order traversal of the
>>>> + // control flow graph which will determine the set
>>>> + // of blocks reachable from the entry and also mark
>>>> + // those which are the sources of back edges (loop bottoms)
>>>> + for (auto BB : PO) {
>>>> + (void) BB;
>>>> + }
>>>> +
>>>> + for (auto &BB : F) {
>>>> + if (PO.reachable(&BB)) {
>>>> + continue;
>>>> + }
>>>> + DEBUG_MSG("unreachable " << BB.getName());
>>>> + removeUnreachable(&BB);
>>>> + UnreachableBlocks.push_back(&BB);
>>>> + }
>>>> + if (Worklist.empty()) {
>>>> + return;
>>>> + }
>>>> + GraphWasModified = true;
>>>> + for (auto I : Worklist) {
>>>> + I->eraseFromParent();
>>>> + }
>>>> + Worklist.clear();
>>>> +}
>>>> +
>>>> +// since we go to the trouble of finding unreachable blocks
>>>> +// might as well remove them.
>>>> +void AggressiveCDCE::removeUnreachable(BasicBlock *BB) {
>>>> + auto &Info = *BlockInfo[BB];
>>>> + Info.Live = true;
>>>> + Info.Terminator = nullptr;
>>>> +
>>>> + while (PHINode *PN = dyn_cast<PHINode>(BB->begin())) {
>>>> + PN->replaceAllUsesWith(Constant::getNullValue(PN->getType()));
>>>> + BB->getInstList().pop_front();
>>>> + }
>>>> + for (auto Succ : successors(BB)) {
>>>> + Succ->removePredecessor(BB);
>>>> + }
>>>> + BB->dropAllReferences();
>>>> + for (Instruction &I : *BB) {
>>>> + Worklist.push_back(&I);
>>>> + }
>>>> +}
>>>> +
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> +// Core algorithm to propagate liveness
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +void AggressiveCDCE::markLive() {
>>>> +
>>>> + DEBUG_MSG("propagate live\n");
>>>> +
>>>> + // Propagate liveness backwards to operands.
>>>> + do {
>>>> + while (!Worklist.empty()) {
>>>> + Instruction *Curr = Worklist.pop_back_val();
>>>> + DEBUG(dbgs() << "work live: "; Curr->dump(););
>>>> + for (Use &OI : Curr->operands()) {
>>>> + if (Instruction *Inst = dyn_cast<Instruction>(OI)) {
>>>> + markLive(Inst);
>>>> + }
>>>> + }
>>>> + }
>>>> + checkControlDependences();
>>>> + if (Worklist.empty()) {
>>>> + checkPhiNodes();
>>>> + }
>>>> + } while (!Worklist.empty());
>>>> +
>>>> + // Find blocks with dead terminators which are simply
>>>> + // unconditional branches and mark them live to avoid
>>>> + // trivial edits
>>>> + SmallVector<BasicBlock*, 32> NowLiveBlocks;
>>>> + for (auto BB : BlocksWithDeadTerminators) {
>>>> + auto Info = BlockInfo[BB];
>>>> + if (!Info->Live && Info->UnconditionalBranch &&
>>>> + &Info->BB->front() == Info->Terminator) {
>>>> + if (auto Pred = Info->BB->getSinglePredecessor()) {
>>>> + if (isLive(Pred->getTerminator())) {
>>>> + // this mostly avoids unnecessary work removing trival dead
>>>> regions
>>>> + DEBUG_MSG("unconditional from live pred " <<
>>>> Info->BB->getName());
>>>> + Info->Live = true;
>>>> + *Info->TerminatorLive = true;
>>>> + Info->LivePostDom = BB;
>>>> + NowLiveBlocks.push_back(BB);
>>>> + }
>>>> + }
>>>> + }
>>>> + }
>>>> + for (auto BB : NowLiveBlocks) {
>>>> + BlocksWithDeadTerminators.erase(BB);
>>>> + }
>>>> +}
>>>> +
>>>> +// Check if this instruction is a runtime call for value profiling and
>>>> +// if it's instrumenting a constant.
>>>> +static bool isInstrumentsConstant(Instruction &I) {
>>>> + if (CallInst *CI = dyn_cast<CallInst>(&I))
>>>> + if (Function *Callee = CI->getCalledFunction())
>>>> + if (Callee->getName().equals(getInstrProfValueProfFuncName()))
>>>> + if (isa<Constant>(CI->getArgOperand(0)))
>>>> + return true;
>>>> + return false;
>>>> +}
>>>> +
>>>> +bool AggressiveCDCE::alwaysLive(Instruction &I) const {
>>>> + if (isa<DbgInfoIntrinsic>(I) || I.isEHPad() ||
>>>> I.mayHaveSideEffects()) {
>>>> + if (isInstrumentsConstant(I)) {
>>>> + return false;
>>>> + }
>>>> + return true;
>>>> + }
>>>> + if (!isa<TerminatorInst>(I)) {
>>>> + return false;
>>>> + }
>>>> + if (isa<BranchInst>(I) || isa<SwitchInst>(I)) {
>>>> + return false;
>>>> + }
>>>> + return true;
>>>> +}
>>>> +
>>>> +void AggressiveCDCE::markLive(Instruction *I) {
>>>> + auto &Info = InstInfo[I];
>>>> + if (Info.Live) {
>>>> + return;
>>>> + }
>>>> + DEBUG(dbgs() << "mark live: "; I->dump());
>>>> + Info.Live = true;
>>>> + Worklist.push_back(I);
>>>> +
>>>> + // Collect the live debug info scopes attached to this instruction.
>>>> + if (const DILocation *DL = I->getDebugLoc())
>>>> + collectLiveScopes(*DL);
>>>> +
>>>> + auto &BBInfo = *Info.Block;
>>>> + if (BBInfo.Live) {
>>>> + return;
>>>> + }
>>>> + DEBUG_MSG("mark block live: " << BBInfo.BB->getName());
>>>> + BBInfo.Live = true;
>>>> + NewLiveBlocks.insert(BBInfo.BB);
>>>> +
>>>> + // See comments below...
>>>
>>> Where? I don't see them...
>
> (left over from a previous version)
>
>>>
>>>> + BBInfo.LivePostDom = BBInfo.BB;
>>>> + if (!BBInfo.UnconditionalBranch) {
>>>> + return;
>>>> + }
>>>> + BlocksWithDeadTerminators.erase(BBInfo.BB);
>>>> +
>>>> + if (!BBInfo.TerminatorLive) { // not set in first initialization
>>>> pass
>>>> + InstInfo[BBInfo.Terminator].Live = true;
>>>> + } else {
>>>> + *BBInfo.TerminatorLive = true;
>>>> + }
>>>> +}
>>>> +
>>>> +void AggressiveCDCE::collectLiveScopes(const DILocalScope &LS) {
>>>> + if (!AliveScopes.insert(&LS).second)
>>>> + return;
>>>> +
>>>> + if (isa<DISubprogram>(LS))
>>>> + return;
>>>> +
>>>> + // Tail-recurse through the scope chain.
>>>> + collectLiveScopes(cast<DILocalScope>(*LS.getScope()));
>>>> +}
>>>> +
>>>> +void AggressiveCDCE::collectLiveScopes(const DILocation &DL) {
>>>> + // Even though DILocations are not scopes, shove them into
>>>> AliveScopes so we
>>>> + // don't revisit them.
>>>> + if (!AliveScopes.insert(&DL).second)
>>>> + return;
>>>> +
>>>> + // Collect live scopes from the scope chain.
>>>> + collectLiveScopes(*DL.getScope());
>>>> +
>>>> + // Tail-recurse through the inlined-at chain.
>>>> + if (const DILocation *IA = DL.getInlinedAt())
>>>> + collectLiveScopes(*IA);
>>>> +}
>>>> +
>>>> +
>>>> +
>>>> +// Use the IDFCalculator to find control dependences
>>>> +// strting at newly discovered live blocks but stopping
>>>> +// at blocks with live terminators.
>>>> +void AggressiveCDCE::checkControlDependences() {
>>>> +
>>>> + if (BlocksWithDeadTerminators.empty()) {
>>>> + return ;
>>>> + }
>>>> +
>>>> + DEBUG({
>>>> + dbgs() << "new live blocks:\n";
>>>> + for (auto BB : NewLiveBlocks) {
>>>> + dbgs() << "\t" << BB->getName() << '\n';
>>>> + }
>>>> + dbgs() << "dead terminator blocks:\n";
>>>> + for (auto BB : BlocksWithDeadTerminators) {
>>>> + dbgs() << "\t" << BB->getName() << '\n';
>>>> + }
>>>> + });
>>>> +
>>>> + SmallVector<BasicBlock *, 32> IDFBlocks;
>>>> + ReverseIDFCalculator IDFs(PDT);
>>>> + IDFs.setDefiningBlocks(NewLiveBlocks);
>>>> + IDFs.setLiveInBlocks(BlocksWithDeadTerminators);
>>>> + IDFs.calculate(IDFBlocks);
>>>> + NewLiveBlocks.clear();
>>>> +
>>>> + /* dead terminators which control live blocks become live */
>>>> + for (auto BB : IDFBlocks) {
>>>> + DEBUG_MSG("live control in: " << BB->getName());
>>>> + markLive(BB->getTerminator());
>>>> + BlocksWithDeadTerminators.erase(BB);
>>>> + }
>>>> +}
>>>> +
>>>> +// there are scenarios in which a phi node is really short-hand
>>>> +// for a copy operations on the edge and the semantics of the program
>>>> +// rely on this. We look for situations where there are distinct
>>>> values from
>>>> +// blocks with dead terminators (which we assume
>>>> +// are all replaced with
>>>> +// a single edge) and if we find this case we mark some of those
>>>> terminators
>>>> +// as live.
>>>> +void AggressiveCDCE::checkPhiNodes() {
>>>> + RegionSetType LivePdoms;
>>>> + auto FirstVisit = LastCurrentVisit;
>>>> + for (auto DB : BlocksWithDeadTerminators) {
>>>> + auto DBInfo = BlockInfo[DB];
>>>> + if (DBInfo->RegionVisited > FirstVisit ||
>>>> DBInfo->terminatorIsLive()) {
>>>> + continue;
>>>> + }
>>>> + ++LastCurrentVisit;
>>>> + visitRegion(DBInfo, FirstVisit, LastCurrentVisit, &LivePdoms);
>>>> + }
>>>> + for (auto Succ : LivePdoms) {
>>>> + DEBUG_MSG("checking Phi Nodes " << Succ->getName());
>>>> + for (auto it = Succ->begin(); PHINode *PN =
>>>> dyn_cast<PHINode>(it); ++it) {
>>>> + if (isLive(PN)) {
>>>> + checkPhiNode(PN, FirstVisit);
>>>> + }
>>>> + }
>>>> + }
>>>> +}
>>>> +
>>>> +// Traverse the connected component associated with BBInfo where
>>>> +// nodes whose RegionVisited field is > FirstVisit are considered
>>>> 'visited'
>>>> +// and we stop at tops of live blocks.
>>>> +void AggressiveCDCE::visitRegion(BlockInfoType *BBInfo, unsigned
>>>> FirstVisit,
>>>> + unsigned CurrentVisit,
>>>> + RegionSetType *LivePdoms) {
>>>> + BBInfo->RegionVisited = CurrentVisit;
>>>> + DEBUG_MSG("region visited " << CurrentVisit << " " <<
>>>> BBInfo->BB->getName());
>>>> + if (!BBInfo->Live) {
>>>> + for (auto Pred : predecessors(BBInfo->BB)) {
>>>> + auto PredInfo = BlockInfo[Pred];
>>>> + if (PredInfo->RegionVisited <= FirstVisit) {
>>>> + visitRegion(PredInfo, FirstVisit, CurrentVisit, LivePdoms);
>>>> + }
>>>> + }
>>>> + }
>>>> + for (auto Succ : successors(BBInfo->BB)) {
>>>> + auto SuccInfo = BlockInfo[Succ];
>>>> + if (SuccInfo->Live) {
>>>> + LivePdoms->insert(SuccInfo->BB);
>>>> + continue;
>>>> + }
>>>> + if (SuccInfo->RegionVisited <= FirstVisit) {
>>>> + visitRegion(SuccInfo, FirstVisit, CurrentVisit, LivePdoms);
>>>> + }
>>>> + }
>>>> +}
>>>> +
>>>> +// This code verifies that all edges from "dead" predecessors
>>>> +// have the same associated value. This might not be true
>>>> +// after certain optimizations of eliminated intermediate PHI
>>>> +// nodes
>>>> +void AggressiveCDCE::checkPhiNode(PHINode *PN, unsigned FirstVisit) {
>>>> + DenseMap<unsigned, Value *> DeadValues;
>>>> +
>>>> + auto NumIdx = PN->getNumIncomingValues();
>>>> + // A block P may be a direct predecessor of a block Q and have a
>>>> live
>>>> + // terminator. It may also have a path from dead blocks leading to
>>>> When that
>>>> + // path is removed, there will only be one edge from P to Q and so
>>>> we can
>>>> + // only have one value in that case.
>>>> + for (unsigned Idx = 0; Idx < NumIdx; ++Idx) {
>>>> + auto PredBB = PN->getIncomingBlock(Idx);
>>>> + auto &Info = *BlockInfo[PredBB];
>>>> + if (Info.RegionVisited > FirstVisit && Info.Live &&
>>>> + Info.terminatorIsLive()) {
>>>> + DeadValues[Info.RegionVisited] = PN->getIncomingValue(Idx);
>>>> + DEBUG_MSG("live for region " << Info.RegionVisited << " from "
>>>> + << PredBB->getName());
>>>> + }
>>>> + }
>>>> + for (unsigned Idx = 0; Idx < NumIdx; ++Idx) {
>>>> + auto PredBB = PN->getIncomingBlock(Idx);
>>>> + auto PredInfo = BlockInfo[PredBB];
>>>> + if (PredInfo->terminatorIsLive()) {
>>>> + continue;
>>>> + }
>>>> + DEBUG_MSG("check pred " << PredInfo->RegionVisited << " "
>>>> + << PredBB->getName());
>>>> + auto Value = PN->getIncomingValue(Idx);
>>>> + auto &DeadValue = DeadValues[PredInfo->RegionVisited];
>>>> + if (DeadValue) {
>>>> + if (Value != DeadValue) {
>>>> + DEBUG(dbgs() << "hard phi, region = " <<
>>>> PredInfo->RegionVisited
>>>> + << " pred " << PredBB->getName() << '\n';
>>>> + PN->dump());
>>>> + markLive(PredInfo->Terminator);
>>>> + }
>>>> + } else {
>>>> + DeadValue = Value;
>>>> + }
>>>> + }
>>>> +}
>>>> +
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> +// Routines to update the CFG and SSA information before removing
>>>> dead code
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +// A dead region is the set of dead blocks with a common live
>>>> post-dominator
>>>> +// A trivial region is a region which consists of blocks with
>>>> unconditional
>>>> +// branches. We don't bother removing such blocks and defer to other
>>>> phases
>>>> +void AggressiveCDCE::processDeadRegions() {
>>>> +
>>>> +
>>>> + // Set LivePostDom fields for blocks which dead terminators
>>>> + SmallVector<DomTreeNodeBase<BasicBlock> *, 16> deadPdoms;
>>>> + for (auto & Info : BlockInfoVec) {
>>>> + if( Info.isUnreachable()) {
>>>> + continue;
>>>> + }
>>>> + if(Info.LivePostDom == nullptr) {
>>>> + assert(!Info.Live);
>>>> + auto Node = PDT.getNode(Info.BB)->getIDom();
>>>> + while(!isLive(Node->getBlock())) {
>>>> + deadPdoms.push_back(Node);
>>>> + Node = Node->getIDom();
>>>> + }
>>>> + Info.LivePostDom = Node->getBlock();
>>>> + for (auto DeadNode : deadPdoms) {
>>>> + BlockInfo[DeadNode->getBlock()]->LivePostDom =
>>>> Info.LivePostDom;
>>>> + }
>>>> + deadPdoms.clear();
>>>> + }
>>>> + if (Info.LivePostDom != Info.BB) {
>>>> + DEBUG_MSG("live pdom " << Info.BB->getName() << " "
>>>> + << Info.LivePostDom->getName());
>>>> + }
>>>> + }
>>>> + SmallPtrSet<BlockInfoType *, 32> DeadRegions;
>>>> +
>>>> + // Examine dead blocks and collect them at their
>>>> + // live post-dominator to be processed as a region.
>>>> + for (auto DB : BlocksWithDeadTerminators) {
>>>> + auto Info = BlockInfo[DB];
>>>> + assert(! *Info->TerminatorLive);
>>>> + if (Info->Live) {
>>>> + // Look for live blocks with dead branches which
>>>> + // will need to be converted to unconditional branches
>>>> + for (auto Succ : successors(Info->BB)) {
>>>> + auto &SuccInfo = *BlockInfo[Succ];
>>>> + if (!SuccInfo.Live) {
>>>> + continue;
>>>> + }
>>>> + DEBUG_MSG("dead br in pred " << Info->BB->getName() << "
>>>> reaches "
>>>> + << Succ->getName());
>>>> + SuccInfo.DeadRegion.LivePreds.insert(Info);
>>>> + SuccInfo.DeadRegion.Trivial = false;
>>>> + DeadRegions.insert(&SuccInfo);
>>>> + }
>>>> + continue;
>>>> + }
>>>> + auto LivePdom = Info->LivePostDom;
>>>> + DEBUG_MSG("Dead block: " << Info->BB->getName() << " pdom "
>>>> + << LivePdom->getName());
>>>> + auto &LivePdomInfo = *BlockInfo[LivePdom];
>>>> + DeadRegions.insert(&LivePdomInfo);
>>>> + auto &DeadRegion = LivePdomInfo.DeadRegion;
>>>> + for (auto PredBB : predecessors(Info->BB)) {
>>>> + auto &PredInfo = *BlockInfo[PredBB];
>>>> + if (PredInfo.Live) {
>>>> + DeadRegion.LivePreds.insert(&PredInfo);
>>>> + if (!PredInfo.terminatorIsLive()) {
>>>> + DeadRegion.Trivial = false;
>>>> + }
>>>> + }
>>>> + }
>>>> + if (!Info->UnconditionalBranch) {
>>>> + DeadRegion.Trivial = false;
>>>> + } else if (DeadRegion.Trivial) {
>>>> + DeadRegion.DeadBlocks.push_back(Info);
>>>> + }
>>>> + }
>>>> +
>>>> + for (auto Info : DeadRegions) {
>>>> + if (!Info->DeadRegion.Trivial) {
>>>> + updateDeadRegion(Info->BB, &Info->DeadRegion);
>>>> + } else {
>>>> + cleanTrivialRegion(Info->DeadRegion);
>>>> + }
>>>> + }
>>>> +}
>>>> +
>>>> +void AggressiveCDCE::updateDeadRegion(BasicBlock *BB, DeadRegionInfo
>>>> *Info) {
>>>> +
>>>> + DEBUG({
>>>> + dbgs() << "live edges (unique predecessors) into " <<
>>>> BB->getName() << "\n";
>>>> + for (auto PredInfo : Info->LivePreds) {
>>>> + dbgs() << "\t" << PredInfo->BB->getName() << '\n';
>>>> + }
>>>> + });
>>>> +
>>>> + // update each phi based on the new incoming edges
>>>> + for (auto it = BB->begin(); PHINode *PN = dyn_cast<PHINode>(it);
>>>> ++it) {
>>>> + if (!isLive(PN)) {
>>>> + continue;
>>>> + }
>>>> + DEBUG(dbgs() << "old phi: "; PN->dump());
>>>> + // Note that we have verified in checkPhiNodes that all are
>>>> + // the same from dead predecessors.
>>>> + DenseMap<unsigned, Value *> DeadValues;
>>>> +
>>>> + for (int64_t i = PN->getNumIncomingValues() - 1; i >= 0; --i) {
>>>> + auto PredBB = PN->getIncomingBlock(i);
>>>> + auto PredInfo = BlockInfo[PredBB];
>>>> + if (PredInfo->terminatorIsLive()) {
>>>> + continue;
>>>> + }
>>>> + DEBUG_MSG(" removing " << PredInfo->RegionVisited << " "
>>>> + << PredBB->getName());
>>>> + auto &DeadValue = DeadValues[PredInfo->RegionVisited];
>>>> + assert(!DeadValue || DeadValue == PN->getIncomingValue(i));
>>>> + DeadValue = PN->getIncomingValue(i);
>>>> + PN->removeIncomingValue(i, /*DeletePHIIfEmpty*/ false);
>>>> + }
>>>> + for (auto PredInfo : Info->LivePreds) {
>>>> + auto DeadValue = DeadValues[PredInfo->RegionVisited];
>>>> + assert(DeadValue && "Failed to find value for dead
>>>> predecessor");
>>>> + PN->addIncoming(DeadValue, PredInfo->BB);
>>>> + }
>>>> + DEBUG(dbgs() << "new phi: "; PN->dump());
>>>> + }
>>>> +
>>>> + // update edges
>>>> + for (auto PredInfo : Info->LivePreds) {
>>>> + if (!PredInfo->terminatorIsLive()) {
>>>> + makeUnconditional(PredInfo->BB, BB);
>>>> + } else {
>>>> + auto PredTerm = PredInfo->Terminator;
>>>> + auto NumSucc = PredTerm->getNumSuccessors();
>>>> + for (unsigned Idx = 0; Idx != NumSucc; ++Idx) {
>>>> + auto Succ = PredTerm->getSuccessor(Idx);
>>>> + auto SuccInfo = BlockInfo[Succ];
>>>> + if (SuccInfo->LivePostDom == BB) {
>>>> + PredTerm->setSuccessor(Idx, BB);
>>>> + }
>>>> + }
>>>> + }
>>>> + }
>>>> +#ifndef NDEBUG
>>>> + BlocksForPhiValidation.insert(BB);
>>>> +#endif
>>>> +}
>>>> +void AggressiveCDCE::makeUnconditional(BasicBlock *BB, BasicBlock
>>>> *Target) {
>>>> + auto PredTerm = BB->getTerminator();
>>>> + if (isUnconditional(PredTerm)) {
>>>> + InstInfo[PredTerm].Live = true;
>>>> + return;
>>>> + }
>>>> + DEBUG_MSG("making unconditional " << BB->getName());
>>>> + IRBuilder<> Builder(PredTerm);
>>>> + auto NewTerm = Builder.CreateBr(Target);
>>>> + // don't update InstInfo to protect pointers into it...
>>>> + NewBranches.push_back(NewTerm);
>>>> +}
>>>> +
>>>> +// mark trivial blocks live and their unconditional-branch
>>>> terminators as well.
>>>> +void AggressiveCDCE::cleanTrivialRegion(const DeadRegionInfo &DRInfo)
>>>> {
>>>> + for (auto DBInfo : DRInfo.DeadBlocks) {
>>>> + DEBUG_MSG("Trivial: " << DBInfo->BB->getName());
>>>> + DBInfo->Live = true;
>>>> + *DBInfo->TerminatorLive = true;
>>>> + }
>>>> +}
>>>> +
>>>> +// the actual work of removing dead instructions and blocks
>>>> +void AggressiveCDCE::removeDeadCode() {
>>>> +
>>>> + assert(Worklist.empty() &&
>>>> + "Expected empty work list when removing dead code");
>>>> + // The inverse of the live set is the dead set. These are those
>>>> instructions
>>>> + // which have no side effects and do not influence the control flow
>>>> or return
>>>> + // value of the function, and may therefore be deleted safely.
>>>> + // NOTE: We reuse the Worklist vector here for memory efficiency.
>>>> + unsigned LocalNumBranchesRemoved = std::count_if(
>>>> + BlocksWithDeadTerminators.begin(),
>>>> BlocksWithDeadTerminators.end(),
>>>> + [this](BasicBlock *DB) { return !isLive(DB->getTerminator());
>>>> });
>>>> +
>>>> + // this update invalidates BlockInfoType::TerminatorLive fields
>>>> + for (Instruction *I : NewBranches) {
>>>> + InstInfo[I].Live = true;
>>>> + }
>>>> + for (Instruction &I : instructions(F)) {
>>>> + if (!isLive(&I)) {
>>>> + if (auto *DII = dyn_cast<DbgInfoIntrinsic>(&I)) {
>>>> + // Check if the scope of this variable location is alive.
>>>> + if (AliveScopes.count(DII->getDebugLoc()->getScope()))
>>>> + continue;
>>>> +
>>>> + // Fallthrough and drop the intrinsic.
>>>> + DEBUG({
>>>> + // If intrinsic is pointing at a live SSA value, there may
>>>> be an
>>>> + // earlier optimization bug: if we know the location of the
>>>> variable,
>>>> + // why isn't the scope of the location alive?
>>>> + if (Value *V = DII->getVariableLocation())
>>>> + if (Instruction *II = dyn_cast<Instruction>(V))
>>>> + if (isLive(II))
>>>> + dbgs() << "Dropping debug info for " << *DII << "\n";
>>>> + });
>>>> + }
>>>> +
>>>> + DEBUG(dbgs() << "dead: "; I.dump());
>>>> + Worklist.push_back(&I);
>>>> + I.dropAllReferences();
>>>> + }
>>>> + }
>>>> + for (auto UB : UnreachableBlocks) {
>>>> + DEBUG_MSG("removing unreachble " << UB->getName());
>>>> + UB->eraseFromParent();
>>>> + }
>>>> + if (Worklist.empty()) {
>>>> + return;
>>>> + }
>>>> + GraphWasModified = true;
>>>> + for (Instruction *I : Worklist) {
>>>> + I->eraseFromParent();
>>>> + }
>>>> + for (auto BB : BlocksWithDeadTerminators) {
>>>> + auto DB = BlockInfo[BB];
>>>> + if (!DB->Live) {
>>>> + DEBUG_MSG("deleting block " << DB->BB->getName());
>>>> + DB->BB->eraseFromParent();
>>>> + }
>>>> + }
>>>> + auto LocalNumRemoved = Worklist.size();
>>>> + DEBUG_MSG("Num removed " << LocalNumRemoved << "\n"
>>>> + << "Num branches removed "
>>>> + << LocalNumBranchesRemoved);
>>>> + FuncNumInstRemoved += LocalNumRemoved;
>>>> + FuncNumBranchesRemoved += LocalNumBranchesRemoved;
>>>> + NumBranchesRemoved += FuncNumBranchesRemoved;
>>>> + NumRemoved += FuncNumInstRemoved;
>>>> +}
>>>> +
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> +// Debugging and validation code
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +
>>>> +#ifndef NDEBUG
>>>> +void AggressiveCDCE::validatePhiNodes(BasicBlock *BB) {
>>>> +
>>>> + if (BB->empty())
>>>> + return;
>>>> + PHINode *APN = dyn_cast<PHINode>(&BB->front());
>>>> + if (!APN)
>>>> + return;
>>>> +
>>>> + SmallVector<std::pair<BasicBlock *, Value *>, 16> Preds;
>>>> + for (auto Pred : predecessors(BB)) {
>>>> + Preds.emplace_back(Pred, nullptr);
>>>> + }
>>>> + auto error = [this, BB](PHINode *PN, BasicBlock *Pred, const char
>>>> *Message) {
>>>> + errs() << "Error in function: " << F.getName() << "\n\t" <<
>>>> Message << '\n';
>>>> + errs() << "\tblock " << BB->getName() << '\n';
>>>> + errs() << "\tpred " << Pred->getName() << "\n\t";
>>>> + PN->print(errs());
>>>> + errs() << '\n';
>>>> + };
>>>> +
>>>> + for (auto it = BB->begin(); PHINode *PN = dyn_cast<PHINode>(it);
>>>> ++it) {
>>>> + if (!isLive(PN)) {
>>>> + continue;
>>>> + }
>>>> + auto NumIdx = PN->getNumIncomingValues();
>>>> + for (unsigned Idx = 0; Idx < NumIdx; ++Idx) {
>>>> + auto Value = PN->getIncomingValue(Idx);
>>>> + auto Pred = PN->getIncomingBlock(Idx);
>>>> + bool Found = false;
>>>> + for (auto &P : Preds) {
>>>> + if (P.first == Pred) {
>>>> + if (!P.second) {
>>>> + P.second = Value;
>>>> + Found = true;
>>>> + break;
>>>> + }
>>>> + if (P.second != Value) {
>>>> + error(PN, Pred, "multiple distinct values");
>>>> + }
>>>> + }
>>>> + }
>>>> + if (!Found) {
>>>> + error(PN, Pred, "no predecessor for value");
>>>> + }
>>>> + }
>>>> + for (auto &P : Preds) {
>>>> + if (!P.second) {
>>>> + error(PN, P.first, "no value for predecessor");
>>>> + }
>>>> + P.second = nullptr; // reset for next PHI
>>>> + }
>>>> + }
>>>> +}
>>>> +#endif
>>>> +
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> +// Pass Manager integration code
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +PreservedAnalyses ACDCEPass::run(Function &F,
>>>> AnalysisManager<Function> &AM) {
>>>> + auto &PDT = AM.getResult<PostDominatorTreeAnalysis>(F);
>>>> + if (AggressiveCDCE(F, PDT).doAggressiveCDCE())
>>>> + return PreservedAnalyses::none();
>>>> + return PreservedAnalyses::all();
>>>> +}
>>>> +
>>>> +namespace {
>>>> +struct ACDCELegacyPass : public FunctionPass {
>>>> + static char ID; // Pass identification, replacement for typeid
>>>> + ACDCELegacyPass() : FunctionPass(ID) {
>>>> + initializeACDCELegacyPassPass(*PassRegistry::getPassRegistry());
>>>> + }
>>>> +
>>>> + bool runOnFunction(Function &F) override {
>>>> + if (skipFunction(F))
>>>> + return false;
>>>> + auto &PDT =
>>>> getAnalysis<PostDominatorTreeWrapperPass>().getPostDomTree();
>>>> + return AggressiveCDCE(F, PDT).doAggressiveCDCE();
>>>> + }
>>>> +
>>>> + void getAnalysisUsage(AnalysisUsage &AU) const override {
>>>> + AU.addRequired<PostDominatorTreeWrapperPass>();
>>>> + AU.addPreserved<GlobalsAAWrapperPass>();
>>>> + }
>>>> +};
>>>> +}
>>>> +
>>>> +char ACDCELegacyPass::ID = 0;
>>>> +INITIALIZE_PASS_BEGIN(ACDCELegacyPass, "acdce",
>>>> + "Aggressive Control Dead Code Elimination",
>>>> false, false)
>>>> +INITIALIZE_PASS_DEPENDENCY(PostDominatorTreeWrapperPass)
>>>> +INITIALIZE_PASS_END(ACDCELegacyPass, "acdce",
>>>> + "Aggressive Control Dead Code Elimination",
>>>> false, false)
>>>> +
>>>> +FunctionPass *llvm::createAggressiveControlDCEPass() {
>>>> + return new ACDCELegacyPass();
>>>> +}
>>>> Index: lib/Transforms/IPO/PassManagerBuilder.cpp
>>>> ===================================================================
>>>> --- lib/Transforms/IPO/PassManagerBuilder.cpp
>>>> +++ lib/Transforms/IPO/PassManagerBuilder.cpp
>>>> @@ -316,7 +316,12 @@
>>>> if (LoadCombine)
>>>> MPM.add(createLoadCombinePass());
>>>>
>>>> - MPM.add(createAggressiveDCEPass()); // Delete dead
>>>> instructions
>>>> + if (OptLevel > 2) {
>>>> + MPM.add(createAggressiveControlDCEPass()); // Delete dead
>>>> instructions
>>>> + }
>>>> + else {
>>>> + MPM.add(createAggressiveDCEPass()); // Delete dead
>>>> instructions
>>>> + }
>>>> MPM.add(createCFGSimplificationPass()); // Merge & remove BBs
>>>> // Clean up after everything.
>>>> addInstructionCombiningPass(MPM);
>>>> Index: lib/Passes/PassRegistry.def
>>>> ===================================================================
>>>> --- lib/Passes/PassRegistry.def
>>>> +++ lib/Passes/PassRegistry.def
>>>> @@ -94,6 +94,7 @@
>>>> #ifndef FUNCTION_PASS
>>>> #define FUNCTION_PASS(NAME, CREATE_PASS)
>>>> #endif
>>>> +FUNCTION_PASS("acdce", ACDCEPass())
>>>> FUNCTION_PASS("aa-eval", AAEvaluator())
>>>> FUNCTION_PASS("adce", ADCEPass())
>>>> FUNCTION_PASS("dce", DCEPass())
>>>> Index: lib/Passes/PassBuilder.cpp
>>>> ===================================================================
>>>> --- lib/Passes/PassBuilder.cpp
>>>> +++ lib/Passes/PassBuilder.cpp
>>>> @@ -51,6 +51,7 @@
>>>> #include "llvm/Transforms/IPO/StripDeadPrototypes.h"
>>>> #include "llvm/Transforms/InstCombine/InstCombine.h"
>>>> #include "llvm/Transforms/InstrProfiling.h"
>>>> +#include "llvm/Transforms/Scalar/ACDCE.h"
>>>> #include "llvm/Transforms/Scalar/ADCE.h"
>>>> #include "llvm/Transforms/Scalar/DCE.h"
>>>> #include "llvm/Transforms/Scalar/EarlyCSE.h"
>>>> Index: include/llvm/Transforms/Scalar/ACDCE.h
>>>> ===================================================================
>>>> --- /dev/null
>>>> +++ include/llvm/Transforms/Scalar/ACDCE.h
>>>> @@ -0,0 +1,40 @@
>>>> +//===- ACDCE.h - Aggressive dead code elimination
>>>> +//--------------------------===//
>>>> +//
>>>> +// The LLVM Compiler Infrastructure
>>>> +//
>>>> +// This file is distributed under the University of Illinois Open
>>>> Source
>>>> +// License. See LICENSE.TXT for details.
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> +// This file provides the interface for the Aggressive Control Dead
>>>> Code Elimination
>>>> +// pass. This pass optimistically assumes that all instructions are
>>>> dead until
>>>> +// proven otherwise, allowing it to eliminate dead computations that
>>>> other DCE
>>>> +// passes do not catch, particularly involving loop computations.
>>>> +//
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +
>>>> +#ifndef LLVM_TRANSFORMS_SCALAR_ACDCE_H
>>>> +#define LLVM_TRANSFORMS_SCALAR_ACDCE_H
>>>> +
>>>> +#include "llvm/IR/Function.h"
>>>> +#include "llvm/IR/PassManager.h"
>>>> +
>>>> +namespace llvm {
>>>> +
>>>> +/// A DCE pass that assumes instructions including branches are dead
>>>> until
>>>> +/// proven otherwise.
>>>> +///
>>>> +/// This pass eliminates dead code by optimistically assuming that all
>>>> +/// instructions are dead until proven otherwise. This allows it to
>>>> eliminate
>>>> +/// dead computations that other DCE passes do not catch,
>>>> particularly involving
>>>> +/// loop computations. This pass augments the predecessor "Aggressive
>>>> DCE" by
>>>> +/// not treating all branch operations as automatically live and by
>>>> altering the
>>>> +/// control flow graph remove dead branching.
>>>> +struct ACDCEPass : PassInfoMixin<ACDCEPass> {
>>>> + PreservedAnalyses run(Function &F, AnalysisManager<Function> &AM);
>>>> +};
>>>> +}
>>>> +
>>>> +#endif // LLVM_TRANSFORMS_SCALAR_ACDCE_H
>>>> Index: include/llvm/Transforms/Scalar.h
>>>> ===================================================================
>>>> --- include/llvm/Transforms/Scalar.h
>>>> +++ include/llvm/Transforms/Scalar.h
>>>> @@ -83,6 +83,15 @@
>>>>
>>>>
>>>> //===-------------------------------------------------------------------
>>>> ---===//
>>>> //
>>>> +// AggressiveControlDCE - This pass uses the SSA based Aggressive DCE
>>>> algorithm. This
>>>> +// algorithm assumes instructions are dead until proven otherwise,
>>>> which makes
>>>> +// it more successful at removing non-obviously dead instructions.
>>>> This
>>>> +// variant does not treat branches as automatically live
>>>> +//
>>>> +FunctionPass *createAggressiveControlDCEPass();
>>>> +
>>>>
>>>> +//===------------------------------------------------------------------
>>>> ----===//
>>>> +//
>>>> // BitTrackingDCE - This pass uses a bit-tracking DCE algorithm in
>>>> order to
>>>> // remove computations of dead bits.
>>>> //
>>>> Index: include/llvm/LinkAllPasses.h
>>>> ===================================================================
>>>> --- include/llvm/LinkAllPasses.h
>>>> +++ include/llvm/LinkAllPasses.h
>>>> @@ -60,6 +60,7 @@
>>>> return;
>>>>
>>>> (void) llvm::createAAEvalPass();
>>>> + (void) llvm::createAggressiveControlDCEPass();
>>>> (void) llvm::createAggressiveDCEPass();
>>>> (void) llvm::createBitTrackingDCEPass();
>>>> (void) llvm::createArgumentPromotionPass();
>>>> Index: include/llvm/InitializePasses.h
>>>> ===================================================================
>>>> --- include/llvm/InitializePasses.h
>>>> +++ include/llvm/InitializePasses.h
>>>> @@ -63,6 +63,7 @@
>>>> void initializeTarget(PassRegistry&);
>>>>
>>>> void initializeAAEvalLegacyPassPass(PassRegistry&);
>>>> +void initializeACDCELegacyPassPass(PassRegistry&);
>>>> void initializeAddDiscriminatorsPass(PassRegistry&);
>>>> void initializeADCELegacyPassPass(PassRegistry&);
>>>> void initializeBDCEPass(PassRegistry&);
>
More information about the llvm-commits
mailing list