diff options
author | Björn Gustavsson <[email protected]> | 2016-10-11 08:51:11 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2016-11-18 11:58:35 +0100 |
commit | 9f3c69458c1258c21e44c35d487eceb2394fab74 (patch) | |
tree | 0f088111d796f56e4700dae95f044baabb100512 | |
parent | 506f0982825f032b404425e777010459e974596f (diff) | |
download | otp-9f3c69458c1258c21e44c35d487eceb2394fab74.tar.gz otp-9f3c69458c1258c21e44c35d487eceb2394fab74.tar.bz2 otp-9f3c69458c1258c21e44c35d487eceb2394fab74.zip |
beam_dead: Remove redundant 'bif' instructions
A 'bif' or 'gc_bif' instruction is redundant if it has the same
failure label as a 'jump' instruction immediately following it.
There is no need to test for liveness of the destination register,
because the code at the failure label cannot safely assume that
the destination register is initialized. See the comments in the
code for further details.
In practice, this optimization will only apply to contrived guards
that are almost never used in real applications. The only reason we
add this optimization is to help approach the goal of zero tolerance
for 'bif' instructions instead of 'test' instructions in guards.
-rw-r--r-- | lib/compiler/src/beam_dead.erl | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl index 3606af9d75..8ea949425e 100644 --- a/lib/compiler/src/beam_dead.erl +++ b/lib/compiler/src/beam_dead.erl @@ -266,12 +266,30 @@ backward([{jump,{f,To0}},{move,Src,Reg}=Move|Is], D, Acc) -> false -> backward([Move|Is], D, [Jump|Acc]); true -> backward([Jump|Is], D, Acc) end; -backward([{jump,{f,To}}=J|[{bif,Op,_,Ops,Reg}|Is]=Is0], D, Acc) -> +backward([{jump,{f,To}}=J|[{bif,Op,{f,BifFail},Ops,Reg}|Is]=Is0], D, Acc) -> try replace_comp_op(To, Reg, Op, Ops, D) of I -> backward(Is, D, I++Acc) catch - throw:not_possible -> backward(Is0, D, [J|Acc]) + throw:not_possible -> + case To =:= BifFail of + true -> + %% The bif instruction is redundant. See the comment + %% in the next clause for why there is no need to + %% test for liveness of Reg at label To. + backward([J|Is], D, Acc); + false -> + backward(Is0, D, [J|Acc]) + end end; +backward([{jump,{f,To}}=J|[{gc_bif,_,{f,To},_,_,_Dst}|Is]], D, Acc) -> + %% The gc_bif instruction is redundant, since either the gc_bif + %% instruction itself or the jump instruction will transfer control + %% to label To. Note that a gc_bif instruction does not assign its + %% destination register if the failure branch is taken; therefore, + %% the code at label To is not allowed to assume that the destination + %% register is initialized, and it is therefore no need to test + %% for liveness of the destination register at label To. + backward([J|Is], D, Acc); backward([{test,bs_start_match2,F,Live,[R,_]=Args,Ctxt}|Is], D, [{test,bs_match_string,F,[Ctxt,Bs]}, {test,bs_test_tail2,F,[Ctxt,0]}|Acc0]=Acc) -> |