diff options
author | Björn Gustavsson <[email protected]> | 2012-10-10 16:00:04 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2012-10-10 16:00:04 +0200 |
commit | b16c127d4dc2bb070d6e98e5c4cdc38220708a13 (patch) | |
tree | 60e0fe128f9fe6d36354952d70f06463683a112d /lib/compiler/src/beam_bool.erl | |
parent | 55358002ddfa9f19e4142677d1ad4bd0a1760c0a (diff) | |
parent | e1aa422290b09a68bd761cbd0e70bd48442009b3 (diff) | |
download | otp-b16c127d4dc2bb070d6e98e5c4cdc38220708a13.tar.gz otp-b16c127d4dc2bb070d6e98e5c4cdc38220708a13.tar.bz2 otp-b16c127d4dc2bb070d6e98e5c4cdc38220708a13.zip |
Merge branch 'bjorn/compiler/minor-optimization-polishing/OTP-10193'
* bjorn/compiler/minor-optimization-polishing/OTP-10193: (25 commits)
beam_bsm: Handle calls slightly better
Break apart tail-recursive call instructions
Represent the 'send' instruction as a call_ext/2 instruction
Rewrite select_val and select_tuple_arity to a select instruction
Rewrite binary creation instructions to bs_init instructions
Rewrite bs_add, bs_utf*_size to BIF instructions in optimizations
Rewrite bs_put* instructions to a generic bs_put instruction
Refactor removal of unused labels
Introduce the mandatory beam_a and beam_z passes
compile: Fix bug in selection of passes
beam_receive: Optimize receives using refs created by spawn_monitor/{1,3}
compile: Give a friendler error message if a parse transform cannot be found
beam_jump: Don't move a block which can be entered via a fallthrough
beam_jump: Fix broken optimization
v3_kernel: Fix match code for matched out segment size in multiple clauses
Improve binary matching of literals
v3_codegen: Combine adjacent bs_match_string instructions
beam_bool: Recognize more safe optimizations
beam_utils: Correct usage calculations for GC BIFs in blocks
beam_utils:live_opt/1: Correct liveness calculation for 'try'
...
Diffstat (limited to 'lib/compiler/src/beam_bool.erl')
-rw-r--r-- | lib/compiler/src/beam_bool.erl | 41 |
1 files changed, 31 insertions, 10 deletions
diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl index d9ea6f5a70..81be262d6d 100644 --- a/lib/compiler/src/beam_bool.erl +++ b/lib/compiler/src/beam_bool.erl @@ -168,18 +168,18 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) -> end. %% ensure_opt_safe(OriginalCode, OptCode, FollowingCode, Fail, -%% ReversedPreceedingCode, State) -> ok +%% ReversedPrecedingCode, State) -> ok %% Comparing the original code to the optimized code, determine %% whether the optimized code is guaranteed to work in the same %% way as the original code. %% %% Throw an exception if the optimization is not safe. %% -ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) -> +ensure_opt_safe(Bl, NewCode, OldIs, Fail, PrecedingCode, St) -> %% Here are the conditions that must be true for the %% optimization to be safe. %% - %% 1. If a register is INITIALIZED by PreceedingCode, + %% 1. If a register is INITIALIZED by PrecedingCode, %% then if that register assigned a value in the original %% code, but not in the optimized code, it must be UNUSED or KILLED %% in the code that follows. @@ -190,29 +190,50 @@ ensure_opt_safe(Bl, NewCode, OldIs, Fail, PreceedingCode, St) -> %% by the code that follows. %% %% 3. Any register that is assigned a value in the optimized - %% code must be UNUSED or KILLED in the following code - %% (because the register might be assigned the wrong value, - %% and even if the value is right it might no longer be - %% assigned on *all* paths leading to its use). + %% code must be UNUSED or KILLED in the following code, + %% unless we can be sure that it is always assigned the same + %% value. - InitInPreceeding = initialized_regs(PreceedingCode), + InitInPreceding = initialized_regs(PrecedingCode), PrevDst = dst_regs(Bl), NewDst = dst_regs(NewCode), NotSet = ordsets:subtract(PrevDst, NewDst), - MustBeKilled = ordsets:subtract(NotSet, InitInPreceeding), - MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst), MustBeKilled), + MustBeKilled = ordsets:subtract(NotSet, InitInPreceding), case all_killed(MustBeKilled, OldIs, Fail, St) of false -> throw(all_registers_not_killed); true -> ok end, + Same = assigned_same_value(Bl, NewCode), + MustBeUnused = ordsets:subtract(ordsets:union(NotSet, NewDst), + ordsets:union(MustBeKilled, Same)), case none_used(MustBeUnused, OldIs, Fail, St) of false -> throw(registers_used); true -> ok end, ok. +%% assigned_same_value(OldCode, NewCodeReversed) -> [DestinationRegs] +%% Return an ordset with a list of all y registers that are always +%% assigned the same value in the old and new code. Currently, we +%% are very conservative in that we only consider identical move +%% instructions in the same order. +%% +assigned_same_value(Old, New) -> + case reverse(New) of + [{block,Bl}|_] -> + assigned_same_value(Old, Bl, []); + _ -> + ordsets:new() + end. + +assigned_same_value([{set,[{y,_}=D],[S],move}|T1], + [{set,[{y,_}=D],[S],move}|T2], Acc) -> + assigned_same_value(T1, T2, [D|Acc]); +assigned_same_value(_, _, Acc) -> + ordsets:from_list(Acc). + update_fail_label([{set,_,_,move}=I|Is], Fail, Acc) -> update_fail_label(Is, Fail, [I|Acc]); update_fail_label([{set,Ds,As,{bif,N,{f,_}}}|Is], Fail, Acc) -> |