diff options
Diffstat (limited to 'lib/compiler/src/beam_ssa_opt.erl')
-rw-r--r-- | lib/compiler/src/beam_ssa_opt.erl | 179 |
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) |