diff options
Diffstat (limited to 'lib/compiler/src/beam_kernel_to_ssa.erl')
-rw-r--r-- | lib/compiler/src/beam_kernel_to_ssa.erl | 197 |
1 files changed, 42 insertions, 155 deletions
diff --git a/lib/compiler/src/beam_kernel_to_ssa.erl b/lib/compiler/src/beam_kernel_to_ssa.erl index aa66d4c418..7270be7066 100644 --- a/lib/compiler/src/beam_kernel_to_ssa.erl +++ b/lib/compiler/src/beam_kernel_to_ssa.erl @@ -25,8 +25,8 @@ -export([module/2]). -import(lists, [all/2,append/1,flatmap/2,foldl/3, - keysort/2,mapfoldl/3,map/2,member/2, - reverse/1,reverse/2,sort/1]). + keysort/2,mapfoldl/3,member/2, + reverse/1,sort/1]). -include("v3_kernel.hrl"). -include("beam_ssa.hrl"). @@ -1048,167 +1048,54 @@ put_cg_map(LineAnno, Op, SrcMap, Dst, List, St0) -> %%% cg_binary(Dst, Segs0, FailCtx, Le, St0) -> - {PutCode0,SzCalc0,St1} = cg_bin_put(Segs0, FailCtx, St0), + Segs1 = cg_bin_segments(Segs0, St0), + Segs = case Segs1 of + [#b_literal{val=binary},UnitFlags,Val,#b_literal{val=all}|Segs2] -> + Op = case member(single_use, Le) of + true -> private_append; + false -> append + end, + [#b_literal{val=Op},UnitFlags,Val,#b_literal{val=all}|Segs2]; + _ -> + Segs1 + end, LineAnno = line_anno(Le), - Anno = Le, - case PutCode0 of - [#b_set{op=bs_put,dst=Bin,args=[_,_,Src,#b_literal{val=all}|_]}, - #b_set{op={succeeded,_},dst=Bool,args=[Bin]}, - #b_br{bool=Bool}, - {label,_}|_] -> - #k_bin_seg{unit=Unit0,next=Segs} = Segs0, - Unit = #b_literal{val=Unit0}, - {PutCode,SzCalc1,St2} = cg_bin_put(Segs, FailCtx, St1), - {_,SzVar,SzCode0,St3} = cg_size_calc(1, SzCalc1, FailCtx, St2), - SzCode = cg_bin_anno(SzCode0, LineAnno), - Args = case member(single_use, Anno) of - true -> - [#b_literal{val=private_append},Src,SzVar,Unit]; - false -> - [#b_literal{val=append},Src,SzVar,Unit] - end, - BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args}, - {TestIs,St} = make_succeeded(Dst, FailCtx, St3), - {SzCode ++ [BsInit] ++ TestIs ++ PutCode,St}; - [#b_set{op=bs_put}|_] -> - {Unit,SzVar,SzCode0,St2} = cg_size_calc(8, SzCalc0, FailCtx, St1), - SzCode = cg_bin_anno(SzCode0, LineAnno), - Args = [#b_literal{val=new},SzVar,Unit], - BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args}, - {TestIs,St} = make_succeeded(Dst, FailCtx, St2), - {SzCode ++ [BsInit] ++ TestIs ++ PutCode0,St} - end. - -cg_bin_anno([Set|Sets], Anno) -> - [Set#b_set{anno=Anno}|Sets]; -cg_bin_anno([], _) -> []. - -%% cg_size_calc(PreferredUnit, SzCalc, FailCtx, St0) -> -%% {ActualUnit,SizeVariable,SizeCode,St}. -%% Generate size calculation code. - -cg_size_calc(Unit, error, _FailCtx, St) -> - {#b_literal{val=Unit},#b_literal{val=badarg},[],St}; -cg_size_calc(8, [{1,_}|_]=SzCalc, FailCtx, St) -> - cg_size_calc(1, SzCalc, FailCtx, St); -cg_size_calc(8, SzCalc, FailCtx, St0) -> - {Var,Pre,St} = cg_size_calc_1(SzCalc, FailCtx, St0), - {#b_literal{val=8},Var,Pre,St}; -cg_size_calc(1, SzCalc0, FailCtx, St0) -> - SzCalc = map(fun({8,#b_literal{val=Size}}) -> - {1,#b_literal{val=8*Size}}; - ({8,{{bif,byte_size},Src}}) -> - {1,{{bif,bit_size},Src}}; - ({8,{_,_}=UtfCalc}) -> - {1,{'*',#b_literal{val=8},UtfCalc}}; - ({_,_}=Pair) -> - Pair - end, SzCalc0), - {Var,Pre,St} = cg_size_calc_1(SzCalc, FailCtx, St0), - {#b_literal{val=1},Var,Pre,St}. - -cg_size_calc_1(SzCalc, FailCtx, St0) -> - cg_size_calc_2(SzCalc, #b_literal{val=0}, FailCtx, St0). - -cg_size_calc_2([{_,{'*',Unit,{_,_}=Bif}}|T], Sum0, FailCtx, St0) -> - {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0), - {BifDst,Pre1,St2} = cg_size_bif(Bif, FailCtx, St1), - {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, Unit, FailCtx, St2), - {Sum,Pre0++Pre1++Pre2,St}; -cg_size_calc_2([{_,#b_literal{}=Sz}|T], Sum0, FailCtx, St0) -> - {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0), - {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, FailCtx, St1), - {Sum,Pre0++Pre,St}; -cg_size_calc_2([{_,#b_var{}=Sz}|T], Sum0, FailCtx, St0) -> - {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0), - {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, FailCtx, St1), - {Sum,Pre0++Pre,St}; -cg_size_calc_2([{_,{_,_}=Bif}|T], Sum0, FailCtx, St0) -> - {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0), - {BifDst,Pre1,St2} = cg_size_bif(Bif, FailCtx, St1), - {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, #b_literal{val=1}, FailCtx, St2), - {Sum,Pre0++Pre1++Pre2,St}; -cg_size_calc_2([], Sum, _FailCtx, St) -> - {Sum,[],St}. - -cg_size_bif(#b_var{}=Var, _FailCtx, St) -> - {Var,[],St}; -cg_size_bif({Name,Src}, FailCtx, St0) -> - {Dst,St1} = new_ssa_var('@ssa_bif', St0), - Bif = #b_set{op=Name,dst=Dst,args=[Src]}, - {TestIs,St} = make_succeeded(Dst, FailCtx, St1), - {Dst,[Bif|TestIs],St}. - -cg_size_add(#b_literal{val=0}, Val, #b_literal{val=1}, _FailCtx, St) -> - {Val,[],St}; -cg_size_add(#b_literal{val=A}, #b_literal{val=B}, #b_literal{val=U}, _FailCtx, St) -> - {#b_literal{val=A+B*U},[],St}; -cg_size_add(A, B, Unit, FailCtx, St0) -> - {Dst,St1} = new_ssa_var('@ssa_sum', St0), - {TestIs,St} = make_succeeded(Dst, FailCtx, St1), - BsAdd = #b_set{op=bs_add,dst=Dst,args=[A,B,Unit]}, - {Dst,[BsAdd|TestIs],St}. - -cg_bin_put(Seg, FailCtx, St) -> - cg_bin_put_1(Seg, FailCtx, [], [], St). - -cg_bin_put_1(#k_bin_seg{size=Size0,unit=U,type=T,flags=Fs,seg=Src0,next=Next}, - FailCtx, Acc, SzCalcAcc, St0) -> - [Src,Size] = ssa_args([Src0,Size0], St0), - NeedSize = bs_need_size(T), - TypeArg = #b_literal{val=T}, - Flags = #b_literal{val=Fs}, - Unit = #b_literal{val=U}, - Args = case NeedSize of - true -> [TypeArg,Flags,Src,Size,Unit]; - false -> [TypeArg,Flags,Src] + Build = #b_set{anno=LineAnno,op=bs_create_bin,args=Segs,dst=Dst}, + {TestIs,St} = make_succeeded(Dst, FailCtx, St0), + {[Build|TestIs],St}. + +cg_bin_segments(#k_bin_seg{anno=Anno,type=Type,flags=Flags0,seg=Src0,size=Size0,unit=U,next=Next}, St) -> + Seg = case lists:keyfind(segment, 1,Anno) of + false -> []; + {segment,_}=Seg0 -> [Seg0] + end, + [Src,Size] = ssa_args([Src0,Size0], St), + TypeArg = #b_literal{val=Type}, + Unit = case U of + undefined -> 0; + _ -> U end, - {Dst,St1} = new_ssa_var('@ssa_bs_put', St0), - {TestIs,St} = make_succeeded(Dst, FailCtx, St1), - Is = [#b_set{op=bs_put,dst=Dst,args=Args}|TestIs], - SzCalc = bin_size_calc(T, Src, Size, U), - cg_bin_put_1(Next, FailCtx, reverse(Is, Acc), [SzCalc|SzCalcAcc], St); -cg_bin_put_1(#k_bin_end{}, _, Acc, SzCalcAcc, St) -> - SzCalc = fold_size_calc(SzCalcAcc, 0, []), - {reverse(Acc),SzCalc,St}. + Flags = strip_bs_construct_flags(Flags0), + UnitFlags = #b_literal{val=[Unit|Flags++Seg]}, + [TypeArg,UnitFlags,Src,Size|cg_bin_segments(Next, St)]; +cg_bin_segments(#k_bin_end{}, _St) -> []. bs_need_size(utf8) -> false; bs_need_size(utf16) -> false; bs_need_size(utf32) -> false; bs_need_size(_) -> true. -bin_size_calc(utf8, Src, _Size, _Unit) -> - {8,{bs_utf8_size,Src}}; -bin_size_calc(utf16, Src, _Size, _Unit) -> - {8,{bs_utf16_size,Src}}; -bin_size_calc(utf32, _Src, _Size, _Unit) -> - {8,#b_literal{val=4}}; -bin_size_calc(binary, Src, #b_literal{val=all}, Unit) -> - case Unit rem 8 of - 0 -> {8,{{bif,byte_size},Src}}; - _ -> {1,{{bif,bit_size},Src}} - end; -bin_size_calc(_Type, _Src, Size, Unit) -> - {Unit,Size}. - -fold_size_calc([{Unit,#b_literal{val=Size}}|T], Bits, Acc) -> - if - is_integer(Size) -> - fold_size_calc(T, Bits + Unit*Size, Acc); - true -> - error - end; -fold_size_calc([{U,#b_var{}}=H|T], Bits, Acc) when U =:= 1; U =:= 8 -> - fold_size_calc(T, Bits, [H|Acc]); -fold_size_calc([{U,#b_var{}=Var}|T], Bits, Acc) -> - fold_size_calc(T, Bits, [{1,{'*',#b_literal{val=U},Var}}|Acc]); -fold_size_calc([{_,_}=H|T], Bits, Acc) -> - fold_size_calc(T, Bits, [H|Acc]); -fold_size_calc([], Bits, Acc) -> - Bytes = Bits div 8, - RemBits = Bits rem 8, - Sizes = sort([{1,#b_literal{val=RemBits}},{8,#b_literal{val=Bytes}}|Acc]), - [Pair || {_,Sz}=Pair <- Sizes, Sz =/= #b_literal{val=0}]. +%% Only keep the flags that have a meaning for binary construction and +%% are distinct from the default value. +strip_bs_construct_flags(Flags) -> + [Flag || Flag <- Flags, + case Flag of + little -> true; + native -> true; + big -> false; + signed -> false; + unsigned -> false + end]. %%% %%% Utilities for creating the SSA types. |