diff options
author | Björn Gustavsson <[email protected]> | 2019-05-14 10:11:31 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2019-05-22 10:47:22 +0200 |
commit | 18dc9a8099d1ad8f52b9db7bd251bcbfd632ce5e (patch) | |
tree | cb7d2a6d3620c53cc098a2cb863bd3adf9427d0c /lib/compiler/src/beam_block.erl | |
parent | fe2b1323a3866ed0a9712e9d12e1f8f84793ec47 (diff) | |
download | otp-18dc9a8099d1ad8f52b9db7bd251bcbfd632ce5e.tar.gz otp-18dc9a8099d1ad8f52b9db7bd251bcbfd632ce5e.tar.bz2 otp-18dc9a8099d1ad8f52b9db7bd251bcbfd632ce5e.zip |
Make the swap instruction known to the compiler
BEAM has had a `swap` instruction for several releases, but it was not
known to the compiler. The loader would translate a sequence of three
`move` instructions to the `swap` instructions, but only when it was
possible to determine that it would be safe.
By making `swap` known to the compiler, it can be applied in more
situations since it is easier for the compiler than for the loader
to ensure that the usage is safe, and the loader shenanigans can be
eliminated.
Diffstat (limited to 'lib/compiler/src/beam_block.erl')
-rw-r--r-- | lib/compiler/src/beam_block.erl | 39 |
1 files changed, 37 insertions, 2 deletions
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl index 707974b2c1..a734ca3a10 100644 --- a/lib/compiler/src/beam_block.erl +++ b/lib/compiler/src/beam_block.erl @@ -33,8 +33,9 @@ module({Mod,Exp,Attr,Fs0,Lc}, _Opts) -> function({function,Name,Arity,CLabel,Is0}) -> try - Is1 = blockify(Is0), - Is = embed_lines(Is1), + Is1 = swap_opt(Is0), + Is2 = blockify(Is1), + Is = embed_lines(Is2), {function,Name,Arity,CLabel,Is} catch Class:Error:Stack -> @@ -42,6 +43,40 @@ function({function,Name,Arity,CLabel,Is0}) -> erlang:raise(Class, Error, Stack) end. +%%% +%%% Try to use a `swap` instruction instead of a sequence of moves. +%%% +%%% Note that beam_ssa_codegen generates `swap` instructions only for +%%% the moves within a single SSA instruction (such as `call`), not +%%% for the moves generated by a sequence of SSA instructions. +%%% Therefore, this optimization is needed. +%%% + +swap_opt([{move,Reg1,{x,X}=Temp}=Move1, + {move,Reg2,Reg1}=Move2, + {move,Temp,Reg2}=Move3|Is]) when Reg1 =/= Temp -> + case is_unused(X, Is) of + true -> + [{swap,Reg1,Reg2}|swap_opt(Is)]; + false -> + [Move1|swap_opt([Move2,Move3|Is])] + end; +swap_opt([I|Is]) -> + [I|swap_opt(Is)]; +swap_opt([]) -> []. + +is_unused(X, [{call,A,_}|_]) when A =< X -> true; +is_unused(X, [{call_ext,A,_}|_]) when A =< X -> true; +is_unused(X, [{make_fun2,_,_,_,A}|_]) when A =< X -> true; +is_unused(X, [{move,Src,Dst}|Is]) -> + case {Src,Dst} of + {{x,X},_} -> false; + {_,{x,X}} -> true; + {_,_} -> is_unused(X, Is) + end; +is_unused(X, [{line,_}|Is]) -> is_unused(X, Is); +is_unused(_, _) -> false. + %% blockify(Instructions0) -> Instructions %% Collect sequences of instructions to basic blocks. %% Also do some simple optimations on instructions outside the blocks. |