aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2016-10-11 08:51:11 +0200
committerBjörn Gustavsson <[email protected]>2016-11-18 11:58:35 +0100
commit9f3c69458c1258c21e44c35d487eceb2394fab74 (patch)
tree0f088111d796f56e4700dae95f044baabb100512
parent506f0982825f032b404425e777010459e974596f (diff)
downloadotp-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.erl22
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) ->