summaryrefslogtreecommitdiff
path: root/lib/compiler/src/beam_ssa_opt.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/compiler/src/beam_ssa_opt.erl')
-rw-r--r--lib/compiler/src/beam_ssa_opt.erl179
1 files changed, 66 insertions, 113 deletions
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl
index 72e320749e..123edb868c 100644
--- a/lib/compiler/src/beam_ssa_opt.erl
+++ b/lib/compiler/src/beam_ssa_opt.erl
@@ -277,7 +277,7 @@ module_passes(Opts) ->
repeated_passes(Opts) ->
Ps = [?PASS(ssa_opt_live),
?PASS(ssa_opt_ne),
- ?PASS(ssa_opt_bs_puts),
+ ?PASS(ssa_opt_bs_create_bin),
?PASS(ssa_opt_dead),
?PASS(ssa_opt_cse),
?PASS(ssa_opt_tail_phis),
@@ -1788,101 +1788,63 @@ bsm_shortcut([], _PosMap) -> [].
%%% If an integer segment or a float segment has a literal size and
%%% a literal value, convert to a binary segment. Coalesce adjacent
%%% literal binary segments. Literal binary segments will be converted
-%%% to bs_put_string instructions in later pass.
+%%% to bs_put_string instructions in a later pass.
%%%
-ssa_opt_bs_puts({#opt_st{ssa=Linear0,cnt=Count0}=St, FuncDb}) ->
- {Linear,Count} = opt_bs_puts(Linear0, Count0, []),
- {St#opt_st{ssa=Linear,cnt=Count}, FuncDb}.
-
-opt_bs_puts([{L,#b_blk{is=Is}=Blk0}|Bs], Count0, Acc0) ->
- case Is of
- [#b_set{op=bs_put},#b_set{op={succeeded,_}}]=Is ->
- case opt_bs_put(L, Is, Blk0, Count0, Acc0) of
- not_possible ->
- opt_bs_puts(Bs, Count0, [{L,Blk0}|Acc0]);
- {Count,Acc1} ->
- Acc = opt_bs_puts_merge(Acc1),
- opt_bs_puts(Bs, Count, Acc)
- end;
- _ ->
- opt_bs_puts(Bs, Count0, [{L,Blk0}|Acc0])
- end;
-opt_bs_puts([], Count, Acc) ->
- {reverse(Acc),Count}.
-
-opt_bs_puts_merge([{L1,#b_blk{is=Is}=Blk0},{L2,#b_blk{is=AccIs}}=BAcc|Acc]) ->
- case {AccIs,Is} of
- {[#b_set{op=bs_put,
- args=[#b_literal{val=binary},
- #b_literal{},
- #b_literal{val=Bin0},
- #b_literal{val=all},
- #b_literal{val=1}]},
- #b_set{op={succeeded,_}}],
- [#b_set{op=bs_put,
- args=[#b_literal{val=binary},
- #b_literal{},
- #b_literal{val=Bin1},
- #b_literal{val=all},
- #b_literal{val=1}]}=I0,
- #b_set{op={succeeded,_}}=Succeeded]} ->
- %% Coalesce the two segments to one.
- Bin = <<Bin0/bitstring,Bin1/bitstring>>,
- I = I0#b_set{args=bs_put_args(binary, Bin, all)},
- Blk = Blk0#b_blk{is=[I,Succeeded]},
- [{L2,Blk}|Acc];
- {_,_} ->
- [{L1,Blk0},BAcc|Acc]
- end.
+ssa_opt_bs_create_bin({#opt_st{ssa=Linear0}=St, FuncDb}) ->
+ Linear = opt_create_bin_fs(Linear0),
+ {St#opt_st{ssa=Linear}, FuncDb}.
-opt_bs_put(L, [I0,Succeeded], #b_blk{last=Br0}=Blk0, Count0, Acc) ->
- case opt_bs_put(I0) of
- [Bin] when is_bitstring(Bin) ->
- Args = bs_put_args(binary, Bin, all),
- I = I0#b_set{args=Args},
- Blk = Blk0#b_blk{is=[I,Succeeded]},
- {Count0,[{L,Blk}|Acc]};
- [{int,Int,Size},Bin] when is_bitstring(Bin) ->
- %% Construct a bs_put_integer instruction following
- %% by a bs_put_binary instruction.
- IntArgs = bs_put_args(integer, Int, Size),
- BinArgs = bs_put_args(binary, Bin, all),
-
- {BinL,BinVarNum,BinBoolNum} = {Count0,Count0+1,Count0+2},
- Count = Count0 + 3,
- BinVar = #b_var{name={'@ssa_bs_put',BinVarNum}},
- BinBool = #b_var{name={'@ssa_bool',BinBoolNum}},
-
- BinI = I0#b_set{dst=BinVar,args=BinArgs},
- BinSucceeded = Succeeded#b_set{dst=BinBool,args=[BinVar]},
- BinBlk = Blk0#b_blk{is=[BinI,BinSucceeded],
- last=Br0#b_br{bool=BinBool}},
-
- IntI = I0#b_set{args=IntArgs},
- IntBlk = Blk0#b_blk{is=[IntI,Succeeded],last=Br0#b_br{succ=BinL}},
-
- {Count,[{BinL,BinBlk},{L,IntBlk}|Acc]};
+opt_create_bin_fs([{L,#b_blk{is=Is0}=Blk0}|Bs]) ->
+ Is = opt_create_bin_is(Is0),
+ Blk = Blk0#b_blk{is=Is},
+ [{L,Blk}|opt_create_bin_fs(Bs)];
+opt_create_bin_fs([]) -> [].
+
+opt_create_bin_is([#b_set{op=bs_create_bin,args=Args0}=I0|Is]) ->
+ Args = opt_create_bin_args(Args0),
+ I = I0#b_set{args=Args},
+ [I|opt_create_bin_is(Is)];
+opt_create_bin_is([I|Is]) ->
+ [I|opt_create_bin_is(Is)];
+opt_create_bin_is([]) -> [].
+
+opt_create_bin_args([#b_literal{val=binary},#b_literal{val=[1|_]},
+ #b_literal{val=Bin0},#b_literal{val=all},
+ #b_literal{val=binary},#b_literal{val=[1|_]},
+ #b_literal{val=Bin1},#b_literal{val=all}|Args0]) ->
+ %% Coalesce two litary binary segments to one.
+ Bin = <<Bin0/bitstring,Bin1/bitstring>>,
+ Args = [#b_literal{val=binary},#b_literal{val=[1]},
+ #b_literal{val=Bin},#b_literal{val=all}|Args0],
+ opt_create_bin_args(Args);
+opt_create_bin_args([#b_literal{val=Type}=Type0,#b_literal{val=UFs}=UFs0,Val,Size|Args0]) ->
+ [Unit|Flags] = UFs,
+ case opt_create_bin_arg(Type, Unit, UFs, Val, Size) of
not_possible ->
- not_possible
- end.
-
-opt_bs_put(#b_set{args=[#b_literal{val=binary},_,#b_literal{val=Val},
- #b_literal{val=all},#b_literal{val=Unit}]})
- when is_bitstring(Val) ->
- if
- bit_size(Val) rem Unit =:= 0 ->
- [Val];
- true ->
- not_possible
- end;
-opt_bs_put(#b_set{args=[#b_literal{val=Type},#b_literal{val=Flags},
- #b_literal{val=Val},#b_literal{val=Size},
- #b_literal{val=Unit}]}=I0) when is_integer(Size) ->
+ [Type0,UFs0,Val,Size|opt_create_bin_args(Args0)];
+ [Bin] when is_bitstring(Bin) ->
+ Args = [#b_literal{val=binary},#b_literal{val=[1]},
+ #b_literal{val=Bin},#b_literal{val=all}|Args0],
+ opt_create_bin_args(Args);
+ [{int,Int,IntSize},Bin] when is_bitstring(Bin) ->
+ Args = [#b_literal{val=integer},#b_literal{val=[1|Flags]},
+ #b_literal{val=Int},#b_literal{val=IntSize},
+ #b_literal{val=binary},#b_literal{val=[1]},
+ #b_literal{val=Bin},#b_literal{val=all}|Args0],
+ opt_create_bin_args(Args)
+ end;
+opt_create_bin_args([]) -> [].
+
+opt_create_bin_arg(binary, Unit, _Flags, #b_literal{val=Val}, #b_literal{val=all})
+ when Unit =/= 1, bit_size(Val) rem Unit =:= 0 ->
+ [Val];
+opt_create_bin_arg(Type, Unit, Flags, #b_literal{val=Val}, #b_literal{val=Size})
+ when is_integer(Size), is_integer(Unit) ->
EffectiveSize = Size * Unit,
if
EffectiveSize > 0 ->
- case {Type,opt_bs_put_endian(Flags)} of
+ case {Type,opt_create_bin_endian(Flags)} of
{integer,big} when is_integer(Val) ->
if
EffectiveSize < 64 ->
@@ -1894,9 +1856,8 @@ opt_bs_put(#b_set{args=[#b_literal{val=Type},#b_literal{val=Flags},
%% To avoid an explosion in code size, we only try
%% to optimize relatively small fields.
<<Int:EffectiveSize>> = <<Val:EffectiveSize/little>>,
- Args = bs_put_args(Type, Int, EffectiveSize),
- I = I0#b_set{args=Args},
- opt_bs_put(I);
+ opt_create_bin_arg(Type, 1, [], #b_literal{val=Int},
+ #b_literal{val=EffectiveSize});
{binary,_} when is_bitstring(Val) ->
case Val of
<<Bitstring:EffectiveSize/bits,_/bits>> ->
@@ -1907,8 +1868,14 @@ opt_bs_put(#b_set{args=[#b_literal{val=Type},#b_literal{val=Flags},
end;
{float,Endian} ->
try
- [opt_bs_put_float(Val, EffectiveSize, Endian)]
- catch error:_ ->
+ case Endian of
+ big ->
+ [<<Val:EffectiveSize/big-float-unit:1>>];
+ little ->
+ [<<Val:EffectiveSize/little-float-unit:1>>]
+ end
+ catch
+ error:_ ->
not_possible
end;
{_,_} ->
@@ -1917,25 +1884,12 @@ opt_bs_put(#b_set{args=[#b_literal{val=Type},#b_literal{val=Flags},
true ->
not_possible
end;
-opt_bs_put(#b_set{}) -> not_possible.
-
-opt_bs_put_float(N, Sz, Endian) ->
- case Endian of
- big -> <<N:Sz/big-float-unit:1>>;
- little -> <<N:Sz/little-float-unit:1>>
- end.
-
-bs_put_args(Type, Val, Size) ->
- [#b_literal{val=Type},
- #b_literal{val=[unsigned,big]},
- #b_literal{val=Val},
- #b_literal{val=Size},
- #b_literal{val=1}].
+opt_create_bin_arg(_, _, _, _, _) -> not_possible.
-opt_bs_put_endian([big=E|_]) -> E;
-opt_bs_put_endian([little=E|_]) -> E;
-opt_bs_put_endian([native=E|_]) -> E;
-opt_bs_put_endian([_|Fs]) -> opt_bs_put_endian(Fs).
+opt_create_bin_endian([little=E|_]) -> E;
+opt_create_bin_endian([native=E|_]) -> E;
+opt_create_bin_endian([_|Fs]) -> opt_create_bin_endian(Fs);
+opt_create_bin_endian([]) -> big.
opt_bs_put_split_int(Int, Size) ->
Pos = opt_bs_put_split_int_1(Int, 0, Size - 1),
@@ -2512,7 +2466,6 @@ unsuitable(Linear, Blocks) ->
unsuitable_1([{L,#b_blk{is=[#b_set{op=Op}=I|_]}}|Bs]) ->
Unsuitable = case Op of
bs_extract -> true;
- bs_put -> true;
{float,_} -> true;
landingpad -> true;
_ -> beam_ssa:is_loop_header(I)