[PATCH] D18762: Add Aggressive Control Dead Code Elimination
David Callahan via llvm-commits
llvm-commits at lists.llvm.org
Mon Apr 25 16:30:14 PDT 2016
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?
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