aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2011-09-23 10:29:47 +0200
committerBjörn Gustavsson <[email protected]>2012-10-09 15:24:39 +0200
commitb17da0957f6441e41579d2bad40a8977c4098c0f (patch)
treea4d9137c78385af380bd27721795aed50d40e1f9
parent562cf135b9518985d172d291665eb32f891032fb (diff)
downloadotp-b17da0957f6441e41579d2bad40a8977c4098c0f.tar.gz
otp-b17da0957f6441e41579d2bad40a8977c4098c0f.tar.bz2
otp-b17da0957f6441e41579d2bad40a8977c4098c0f.zip
beam_jump: Fix broken optimization
A test instruction with the same target label as jump immediately followed it was supposed to be removed, but it was kept anyway. Fix that optimization, but also make sure that the test instruction is kept if the test instruction may have side effects (such as a bit syntax matching instruction). While at it, make the code cleaner by breaking it up into two clauses and don't remove the jump instruction if it is redudant (removal of redundant jump instructions is already handled in another place).
-rw-r--r--lib/compiler/src/beam_jump.erl58
1 files changed, 28 insertions, 30 deletions
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index db67d24514..79cdc8e179 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -260,38 +260,36 @@ find_fixpoint(OptFun, Is0) ->
Is -> find_fixpoint(OptFun, Is)
end.
-opt([{test,Test0,{f,Lnum}=Lbl,Ops}=I|Is0], Acc, St) ->
- case Is0 of
- [{jump,{f,Lnum}}|Is] ->
- %% We have
- %% Test Label Ops
- %% jump Label
- %% The test instruction is definitely not needed.
- %% The jump instruction is not needed if there is
- %% a definition of Label following the jump instruction.
- case is_label_defined(Is, Lnum) of
- false ->
- %% The jump instruction is still needed.
- opt(Is0, [I|Acc], label_used(Lbl, St));
- true ->
- %% Neither the test nor the jump are needed.
- opt(Is, Acc, St)
- end;
- [{jump,To}|Is] ->
- case is_label_defined(Is, Lnum) of
- false ->
+opt([{test,_,{f,L}=Lbl,_}=I|[{jump,{f,L}}|_]=Is], Acc, St) ->
+ %% We have
+ %% Test Label Ops
+ %% jump Label
+ %% The test instruction is not needed if the test is pure
+ %% (it modifies neither registers nor bit syntax state).
+ case beam_utils:is_pure_test(I) of
+ false ->
+ %% Test is not pure; we must keep it.
+ opt(Is, [I|Acc], label_used(Lbl, St));
+ true ->
+ %% The test is pure and its failure label is the same
+ %% as in the jump that follows -- thus it is not needed.
+ opt(Is, Acc, St)
+ end;
+opt([{test,Test0,{f,L}=Lbl,Ops}=I|[{jump,To}|Is]=Is0], Acc, St) ->
+ case is_label_defined(Is, L) of
+ false ->
+ opt(Is0, [I|Acc], label_used(Lbl, St));
+ true ->
+ case invert_test(Test0) of
+ not_possible ->
opt(Is0, [I|Acc], label_used(Lbl, St));
- true ->
- case invert_test(Test0) of
- not_possible ->
- opt(Is0, [I|Acc], label_used(Lbl, St));
- Test ->
- opt([{test,Test,To,Ops}|Is], Acc, St)
- end
- end;
- _Other ->
- opt(Is0, [I|Acc], label_used(Lbl, St))
+ Test ->
+ %% Invert the test and remove the jump.
+ opt([{test,Test,To,Ops}|Is], Acc, St)
+ end
end;
+opt([{test,_,{f,_}=Lbl,_}=I|Is], Acc, St) ->
+ opt(Is, [I|Acc], label_used(Lbl, St));
opt([{test,_,{f,_}=Lbl,_,_,_}=I|Is], Acc, St) ->
opt(Is, [I|Acc], label_used(Lbl, St));
opt([{select_val,_R,Fail,{list,Vls}}=I|Is], Acc, St) ->