From 1b325a756b0f90bcf2d29706effd65103523d635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Sun, 15 Sep 2019 06:11:00 +0200 Subject: Eliminate the Kernel Erlang records for atomic literals The `v3_kernel` pass still uses the records `#k_atom{}`, `#k_float{}`, `#k_int{}`, and `#k_nil{}` to represent atomic literals. That made sense in ancient times before the introduction of literals. Since both Core Erlang and SSA code use a single type of record for representing all literals (`#c_literal{}` and `#c_kernel{}`, respectively), using `#k_literal{}` to represent all literals in Kernel Erlang will simplify things. --- lib/compiler/src/beam_kernel_to_ssa.erl | 40 +++---- lib/compiler/src/v3_kernel.erl | 193 +++++++++++++------------------- lib/compiler/src/v3_kernel.hrl | 6 +- lib/compiler/src/v3_kernel_pp.erl | 17 ++- 4 files changed, 98 insertions(+), 158 deletions(-) (limited to 'lib') diff --git a/lib/compiler/src/beam_kernel_to_ssa.erl b/lib/compiler/src/beam_kernel_to_ssa.erl index 3753a8925e..cb1b337468 100644 --- a/lib/compiler/src/beam_kernel_to_ssa.erl +++ b/lib/compiler/src/beam_kernel_to_ssa.erl @@ -266,7 +266,7 @@ select_cons(#k_val_clause{val=#k_cons{hd=Hd,tl=Tl},body=B}, {Is,St} = make_cond_branch(is_nonempty_list, [Src], Tf, St2), {Is ++ Eis ++ Bis,St}. -select_nil(#k_val_clause{val=#k_nil{},body=B}, V, Tf, Vf, St0) -> +select_nil(#k_val_clause{val=#k_literal{val=[]},body=B}, V, Tf, Vf, St0) -> {Bis,St1} = match_cg(B, Vf, St0), Src = ssa_arg(V, St1), {Is,St} = make_cond_branch({bif,'=:='}, [Src,#b_literal{val=[]}], Tf, St1), @@ -404,12 +404,12 @@ select_extract_bin(#k_var{name=Hd}, Size0, Unit, Type, Flags, Vf, Size = ssa_arg(Size0, St0), build_bs_instr(Anno, Type, Vf, Ctx, Size, Unit, Flags, Dst, St1). -select_extract_int(#k_var{name=Tl}, 0, #k_int{val=0}, _U, _Fs, _Vf, +select_extract_int(#k_var{name=Tl}, 0, #k_literal{val=0}, _U, _Fs, _Vf, Ctx, St0) -> St = set_ssa_var(Tl, Ctx, St0), {[],St}; -select_extract_int(#k_var{name=Tl}, Val, #k_int{val=Sz}, U, Fs, Vf, - Ctx, St0) -> +select_extract_int(#k_var{name=Tl}, Val, #k_literal{val=Sz}, U, Fs, Vf, + Ctx, St0) when is_integer(Sz) -> {Dst,St1} = new_ssa_var(Tl, St0), Bits = U*Sz, Bin = case member(big, Fs) of @@ -445,13 +445,7 @@ select_val(#k_val_clause{val=#k_tuple{es=Es},body=B}, V, Vf, St0) -> {Eis,St1} = select_extract_tuple(V, Es, St0), {Bis,St2} = match_cg(B, Vf, St1), {length(Es),Eis ++ Bis,St2}; -select_val(#k_val_clause{val=Val0,body=B}, _V, Vf, St0) -> - Val = case Val0 of - #k_atom{val=Lit} -> Lit; - #k_float{val=Lit} -> Lit; - #k_int{val=Lit} -> Lit; - #k_literal{val=Lit} -> Lit - end, +select_val(#k_val_clause{val=#k_literal{val=Val},body=B}, _V, Vf, St0) -> {Bis,St1} = match_cg(B, Vf, St0), {Val,Bis,St1}. @@ -530,7 +524,7 @@ guard_clause_cg(#k_guard_clause{guard=G,body=B}, Fail, St0) -> guard_cg(#k_protected{arg=Ts,ret=Rs,inner=Inner}, Fail, St) -> protected_cg(Ts, Rs, Inner, Fail, St); guard_cg(#k_test{op=Test0,args=As}, Fail, St0) -> - #k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Test}} = Test0, + #k_remote{mod=#k_literal{val=erlang},name=#k_literal{val=Test}} = Test0, test_cg(Test, false, As, Fail, St0); guard_cg(#k_seq{arg=Arg,body=Body}, Fail, St0) -> {ArgIs,St1} = guard_cg(Arg, Fail, St0), @@ -646,8 +640,8 @@ call_cg(Func0, As, [#k_var{name=R}|MoreRs]=Rs, Le, St0) -> %% Inside a guard. The only allowed function call is to %% erlang:error/1,2. We will generate a branch to the %% failure branch. - #k_remote{mod=#k_atom{val=erlang}, - name=#k_atom{val=error}} = Func0, %Assertion. + #k_remote{mod=#k_literal{val=erlang}, + name=#k_literal{val=error}} = Func0, %Assertion. [#k_var{name=DestVar}] = Rs, St = set_ssa_var(DestVar, #b_literal{val=unused}, St0), {[make_uncond_branch(Fail),#cg_unreachable{}],St}; @@ -694,20 +688,18 @@ call_target(Func, As, St) -> bif_cg(#k_bif{op=#k_internal{name=Name},args=As,ret=Rs}, Le, St) -> internal_cg(Name, As, Rs, Le, St); -bif_cg(#k_bif{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Name}}, +bif_cg(#k_bif{op=#k_remote{mod=#k_literal{val=erlang},name=#k_literal{val=Name}}, args=As,ret=Rs}, Le, St) -> bif_cg(Name, As, Rs, Le, St). %% internal_cg(Bif, [Arg], [Ret], Le, State) -> %% {[Ainstr],State}. -internal_cg(make_fun, [Name0,Arity0|As], Rs, _Le, St0) -> - #k_atom{val=Name} = Name0, - #k_int{val=Arity} = Arity0, +internal_cg(make_fun, As, Rs, _Le, St0) -> [#k_var{name=Dst0}] = Rs, {Dst,St} = new_ssa_var(Dst0, St0), - Args = ssa_args(As, St), - Local = #b_local{name=#b_literal{val=Name},arity=Arity}, + [Name,#b_literal{val=Arity}|Args] = ssa_args(As, St), + Local = #b_local{name=Name,arity=Arity}, MakeFun = #b_set{op=make_fun,dst=Dst,args=[Local|Args]}, {[MakeFun],St}; internal_cg(bs_init_writable=I, As, [#k_var{name=Dst0}], _Le, St0) -> @@ -808,7 +800,7 @@ cg_recv_mesg(#k_var{name=R}, Rm, Tl, Le, St0) -> %% cg_recv_wait(Te, Tes, St) -> {[Ainstr],St}. -cg_recv_wait(#k_int{val=0}, Es, St0) -> +cg_recv_wait(#k_literal{val=0}, Es, St0) -> {Tis,St} = cg(Es, St0), {[#b_set{op=timeout}|Tis],St}; cg_recv_wait(Te, Es, St0) -> @@ -1141,11 +1133,7 @@ ssa_args(As, St) -> [ssa_arg(A, St) || A <- As]. ssa_arg(#k_var{name=V}, #cg{vars=Vars}) -> maps:get(V, Vars); -ssa_arg(#k_literal{val=V}, _) -> #b_literal{val=V}; -ssa_arg(#k_atom{val=V}, _) -> #b_literal{val=V}; -ssa_arg(#k_float{val=V}, _) -> #b_literal{val=V}; -ssa_arg(#k_int{val=V}, _) -> #b_literal{val=V}; -ssa_arg(#k_nil{}, _) -> #b_literal{val=[]}. +ssa_arg(#k_literal{val=V}, _) -> #b_literal{val=V}. new_ssa_vars(Vs, St) -> mapfoldl(fun(#k_var{name=V}, S) -> diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl index 42e36c188c..bab19c219b 100644 --- a/lib/compiler/src/v3_kernel.erl +++ b/lib/compiler/src/v3_kernel.erl @@ -219,8 +219,9 @@ wrap_guard(Core, St0) -> %% Must enter try blocks and isets and find the last Kexpr in them. %% This must end in a recognised BEAM test! -gexpr_test(#k_bif{anno=A,op=#k_remote{mod=#k_atom{val=erlang}, - name=#k_atom{val=F},arity=Ar}=Op, +gexpr_test(#k_bif{anno=A, + op=#k_remote{mod=#k_literal{val=erlang}, + name=#k_literal{val=F},arity=Ar}=Op, args=Kargs}=Ke, St) -> %% Either convert to test if ok, or add test. %% At this stage, erlang:float/1 is not a type test. (It should @@ -231,7 +232,7 @@ gexpr_test(#k_bif{anno=A,op=#k_remote{mod=#k_atom{val=erlang}, false -> gexpr_test_add(Ke, St) %Add equality test end; gexpr_test(#k_try{arg=B0,vars=[#k_var{name=X}],body=#k_var{name=X}, - handler=#k_atom{val=false}}=Try, St0) -> + handler=#k_literal{val=false}}=Try, St0) -> {B,St} = gexpr_test(B0, St0), %%ok = io:fwrite("~w: ~p~n", [?LINE,{B0,B}]), {Try#k_try{arg=B},St}; @@ -241,12 +242,12 @@ gexpr_test(#iset{body=B0}=Iset, St0) -> gexpr_test(Ke, St) -> gexpr_test_add(Ke, St). %Add equality test gexpr_test_add(Ke, St0) -> - Test = #k_remote{mod=#k_atom{val='erlang'}, - name=#k_atom{val='=:='}, + Test = #k_remote{mod=#k_literal{val='erlang'}, + name=#k_literal{val='=:='}, arity=2}, {Ae,Ap,St1} = force_atomic(Ke, St0), {pre_seq(Ap, #k_test{anno=get_kanno(Ke), - op=Test,args=[Ae,#k_atom{val='true'}]}),St1}. + op=Test,args=[Ae,#k_literal{val='true'}]}),St1}. %% expr(Cexpr, Sub, State) -> {Kexpr,[PreKexpr],State}. %% Convert a Core expression, flattening it at the same time. @@ -275,19 +276,7 @@ expr(#c_var{anno=A0,name={Name,Arity}}=Fname, Sub, St) -> expr(#c_var{anno=A,name=V}, Sub, St) -> {#k_var{anno=A,name=get_vsub(V, Sub)},[],St}; expr(#c_literal{anno=A,val=V}, _Sub, St) -> - Klit = case V of - [] -> - #k_nil{anno=A}; - V when is_integer(V) -> - #k_int{anno=A,val=V}; - V when is_float(V) -> - #k_float{anno=A,val=V}; - V when is_atom(V) -> - #k_atom{anno=A,val=V}; - _ -> - #k_literal{anno=A,val=V} - end, - {Klit,[],St}; + {#k_literal{anno=A,val=V},[],St}; expr(#c_cons{anno=A,hd=Ch,tl=Ct}, Sub, St0) -> %% Do cons in two steps, first the expressions left to right, then %% any remaining literals right to left. @@ -398,10 +387,12 @@ expr(#c_apply{anno=A,op=Cop,args=Cargs}, Sub, St) -> expr(#c_call{anno=A,module=#c_literal{val=erlang},name=#c_literal{val=is_record}, args=[_,Tag,Sz]=Args0}, Sub, St0) -> {Args,Ap,St} = atomic_list(Args0, Sub, St0), - Remote = #k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=is_record},arity=3}, + Remote = #k_remote{mod=#k_literal{val=erlang}, + name=#k_literal{val=is_record}, + arity=3}, case {Tag,Sz} of {#c_literal{val=Atom},#c_literal{val=Int}} - when is_atom(Atom), is_integer(Int) -> + when is_atom(Atom), is_integer(Int) -> %% Tag and size are literals. Make it a BIF, which will actually %% be expanded out in a later pass. {#k_bif{anno=A,op=Remote,args=Args},Ap,St}; @@ -446,8 +437,8 @@ expr(#c_primop{anno=A,name=#c_literal{val=match_fail},args=Cargs0}, Sub, St0) -> Cargs = translate_match_fail(Cargs0, Sub, A, St0), {Kargs,Ap,St} = atomic_list(Cargs, Sub, St0), Ar = length(Cargs), - Call = #k_call{anno=A,op=#k_remote{mod=#k_atom{val=erlang}, - name=#k_atom{val=error}, + Call = #k_call{anno=A,op=#k_remote{mod=#k_literal{val=erlang}, + name=#k_literal{val=error}, arity=Ar},args=Kargs}, {Call,Ap,St}; expr(#c_primop{anno=A,name=#c_literal{val=N},args=Cargs}, Sub, St0) -> @@ -597,14 +588,9 @@ map_remove_dup_keys([{exact,K0,V}|Es0],Used0) -> map_remove_dup_keys(Es0, Used1); map_remove_dup_keys([], Used) -> Used. -%% Be explicit instead of using set_kanno(K, []). +%% Clean a map key from annotations. map_key_clean(#k_var{name=V}) -> {var,V}; -map_key_clean(#k_literal{val=V}) -> {lit,V}; -map_key_clean(#k_int{val=V}) -> {lit,V}; -map_key_clean(#k_float{val=V}) -> {lit,V}; -map_key_clean(#k_atom{val=V}) -> {lit,V}; -map_key_clean(#k_nil{}) -> {lit,[]}. - +map_key_clean(#k_literal{val=V}) -> {lit,V}. %% call_type(Module, Function, Arity) -> call | bif | apply | error. %% Classify the call. @@ -694,10 +680,13 @@ atomic_bin([#c_bitstr{anno=A,val=E0,size=S0,unit=U0,type=T,flags=Fs0}|Es0], atomic_bin([], _Sub, St) -> {#k_bin_end{},[],St}. validate_bin_element_size(#k_var{}) -> ok; -validate_bin_element_size(#k_int{val=V}) when V >= 0 -> ok; -validate_bin_element_size(#k_atom{val=all}) -> ok; -validate_bin_element_size(#k_atom{val=undefined}) -> ok; -validate_bin_element_size(_) -> throw(bad_element_size). +validate_bin_element_size(#k_literal{val=Val}) -> + case Val of + all -> ok; + undefined -> ok; + _ when is_integer(Val), Val >= 0 -> ok; + _ -> throw(bad_element_size) + end. %% atomic_list([Cexpr], Sub, State) -> {[Kexpr],[PreKexpr],State}. @@ -708,15 +697,11 @@ atomic_list(Ces, Sub, St) -> end, {[],[],St}, Ces). %% is_atomic(Kexpr) -> boolean(). -%% Is a Kexpr atomic? Strings are NOT considered atomic! +%% Is a Kexpr atomic? is_atomic(#k_literal{}) -> true; -is_atomic(#k_int{}) -> true; -is_atomic(#k_float{}) -> true; -is_atomic(#k_atom{}) -> true; -%%is_atomic(#k_char{}) -> true; %No characters -is_atomic(#k_nil{}) -> true; is_atomic(#k_var{}) -> true; +%%is_atomic(#k_char{}) -> true; %No characters is_atomic(_) -> false. %% variable(Cexpr, Sub, State) -> {Kvar,[PreKexpr],State}. @@ -804,15 +789,14 @@ pattern_bin_1([#c_bitstr{anno=A,val=E0,size=S0,unit=U,type=T,flags=Fs}|Es0], Isub0, Osub0, St0) -> {S1,[],St1} = expr(S0, Isub0, St0), S = case S1 of - #k_int{} -> S1; #k_var{} -> S1; - #k_atom{} -> S1; + #k_literal{val=Val} when is_integer(Val); is_atom(Val) -> S1; _ -> %% Bad size (coming from an optimization or Core Erlang %% source code) - replace it with a known atom because %% a literal or bit syntax construction can cause further %% problems. - #k_atom{val=bad_size} + #k_literal{val=bad_size} end, U0 = cerl:concrete(U), Fs0 = cerl:concrete(Fs), @@ -835,7 +819,8 @@ pattern_bin_1([], Isub, Osub, St) -> {#k_bin_end{},{Isub,Osub},St}. %% more literals and group more clauses. Those integers may be "squeezed" %% later into the largest integer possible. %% -build_bin_seg(A, #k_int{val=Bits} = Sz, U, integer=Type, [unsigned,big]=Flags, #k_literal{val=Int}=Seg, Next) -> +build_bin_seg(A, #k_literal{val=Bits} = Sz, U, integer=Type, + [unsigned,big]=Flags, #k_literal{val=Int}=Seg, Next) -> Size = Bits * U, case integer_fits_and_is_expandable(Int, Size) of true -> build_bin_seg_integer_recur(A, Size, Int, Next); @@ -859,7 +844,7 @@ build_bin_seg_integer_recur(A, Bits, Val, Next) -> build_bin_seg_integer(A, Bits, Val, Next). build_bin_seg_integer(A, Bits, Val, Next) -> - Sz = #k_int{anno=A,val=Bits}, + Sz = #k_literal{anno=A,val=Bits}, Seg = #k_literal{anno=A,val=Val}, #k_bin_seg{anno=A,size=Sz,unit=1,type=integer,flags=[unsigned,big],seg=Seg,next=Next}. @@ -1052,11 +1037,6 @@ foldr2(_, Acc, [], []) -> Acc. kmatch(Us, Ccs, Sub, St0) -> {Cs,St1} = match_pre(Ccs, Sub, St0), %Convert clauses Def = fail, -%% Def = #k_call{anno=[compiler_generated], -%% op=#k_remote{mod=#k_atom{val=erlang}, -%% name=#k_atom{val=exit}, -%% arity=1}, -%% args=[#k_atom{val=kernel_match_error}]}, match(Us, Cs, Def, St1). %Do the match. %% match_pre([Cclause], Sub, State) -> {[Clause],State}. @@ -1246,31 +1226,27 @@ expand_pat_lit_clause(#iclause{pats=[#k_literal{anno=A,val=Val}|Ps]}=C) -> expand_pat_lit_clause(C) -> C. expand_pat_lit([H|T], A) -> - #k_cons{anno=A,hd=literal(H, A),tl=literal(T, A)}; + #k_cons{anno=A,hd=#k_literal{anno=A,val=H},tl=#k_literal{anno=A,val=T}}; expand_pat_lit(Tuple, A) when is_tuple(Tuple) -> - #k_tuple{anno=A,es=[literal(E, A) || E <- tuple_to_list(Tuple)]}; + #k_tuple{anno=A,es=[#k_literal{anno=A,val=E} || E <- tuple_to_list(Tuple)]}; expand_pat_lit(Lit, A) -> - literal(Lit, A). - -literal([], A) -> - #k_nil{anno=A}; -literal(Val, A) when is_integer(Val) -> - #k_int{anno=A,val=Val}; -literal(Val, A) when is_float(Val) -> - #k_float{anno=A,val=Val}; -literal(Val, A) when is_atom(Val) -> - #k_atom{anno=A,val=Val}; -literal(Val, A) when is_list(Val); is_tuple(Val) -> - #k_literal{anno=A,val=Val}. + #k_literal{anno=A,val=Lit}. %% opt_singled_valued([{Type,Clauses}]) -> [{Type,Clauses}]. -%% If a type only has one clause and if the pattern is literal, -%% the matching can be done more efficiently by directly comparing -%% with the literal (that is especially true for binaries). +%% If a type only has one clause and if the pattern is a complex +%% literal, the matching can be done more efficiently by directly +%% comparing with the literal (that is especially true for binaries). +%% +%% It is important not to do this transformation for atomic literals +%% (such as `[]`), since that would cause the test for an emtpy list +%% to be executed before the test for a nonempty list. opt_single_valued(Ttcs) -> opt_single_valued(Ttcs, [], []). +opt_single_valued([{_,[#iclause{pats=[#k_literal{}|_]}]}=Ttc|Ttcs], TtcAcc, LitAcc) -> + %% This is an atomic literal. + opt_single_valued(Ttcs, [Ttc|TtcAcc], LitAcc); opt_single_valued([{_,[#iclause{pats=[P0|Ps]}=Tc]}=Ttc|Ttcs], TtcAcc, LitAcc) -> try combine_lit_pat(P0) of P -> @@ -1300,26 +1276,13 @@ opt_single_valued([], TtcAcc, LitAcc) -> combine_lit_pat(#ialias{pat=Pat0}=Alias) -> Pat = combine_lit_pat(Pat0), Alias#ialias{pat=Pat}; +combine_lit_pat(#k_literal{}) -> + %% This is an atomic literal. Rewriting would be a pessimization, + %% especially for `[]`. + throw(not_possible); combine_lit_pat(Pat) -> - case do_combine_lit_pat(Pat) of - #k_literal{val=Val} when is_atom(Val) -> - throw(not_possible); - #k_literal{val=Val} when is_number(Val) -> - throw(not_possible); - #k_literal{val=[]} -> - throw(not_possible); - #k_literal{}=Lit -> - Lit - end. + do_combine_lit_pat(Pat). -do_combine_lit_pat(#k_atom{anno=A,val=Val}) -> - #k_literal{anno=A,val=Val}; -do_combine_lit_pat(#k_float{anno=A,val=Val}) -> - #k_literal{anno=A,val=Val}; -do_combine_lit_pat(#k_int{anno=A,val=Val}) -> - #k_literal{anno=A,val=Val}; -do_combine_lit_pat(#k_nil{anno=A}) -> - #k_literal{anno=A,val=[]}; do_combine_lit_pat(#k_binary{anno=A,segs=Segs}) -> Bin = combine_bin_segs(Segs), #k_literal{anno=A,val=Bin}; @@ -1338,7 +1301,7 @@ do_combine_lit_pat(#k_tuple{anno=A,es=Es0}) -> do_combine_lit_pat(_) -> throw(not_possible). -combine_bin_segs(#k_bin_seg{size=#k_int{val=8},unit=1,type=integer, +combine_bin_segs(#k_bin_seg{size=#k_literal{val=8},unit=1,type=integer, flags=[unsigned,big],seg=#k_literal{val=Int},next=Next}) when is_integer(Int), 0 =< Int, Int =< 255 -> <>; @@ -1409,9 +1372,9 @@ handle_bin_con_not_possible([]) -> []. %% exception is thrown. select_bin_int([#iclause{pats=[#k_bin_seg{anno=A,type=integer, - size=#k_int{val=Bits0}=Sz,unit=U, - flags=Fl,seg=#k_literal{val=Val}, - next=N}|Ps]}=C|Cs0]) -> + size=#k_literal{val=Bits0}=Sz,unit=U, + flags=Fl,seg=#k_literal{val=Val}, + next=N}|Ps]}=C|Cs0]) when is_integer(Bits0) -> Bits = U * Bits0, if Bits > ?EXPAND_MAX_SIZE_SEGMENT -> throw(not_possible); %Expands the code too much. @@ -1428,7 +1391,7 @@ select_bin_int([#iclause{pats=[#k_bin_seg{anno=A,type=integer, select_bin_int(_) -> throw(not_possible). select_bin_int_1([#iclause{pats=[#k_bin_seg{anno=A,type=integer, - size=#k_int{val=Bits0}=Sz, + size=#k_literal{val=Bits0}=Sz, unit=U, flags=Fl,seg=#k_literal{val=Val}, next=N}|Ps]}=C|Cs], @@ -1599,7 +1562,7 @@ get_match(#k_cons{}, St0) -> get_match(#k_binary{}, St0) -> {[V]=Mes,St1} = new_vars(1, St0), {#k_binary{segs=V},Mes,St1}; -get_match(#k_bin_seg{size=#k_atom{val=all},next={k_bin_end,[]}}=Seg, St0) -> +get_match(#k_bin_seg{size=#k_literal{val=all},next={k_bin_end,[]}}=Seg, St0) -> {[S,N0],St1} = new_vars(2, St0), N = set_kanno(N0, [no_usage]), {Seg#k_bin_seg{seg=S,next=N},[S],St1}; @@ -1630,7 +1593,7 @@ new_clauses(Cs0, U, St) -> #k_cons{hd=H,tl=T} -> [H,T|As]; #k_tuple{es=Es} -> Es ++ As; #k_binary{segs=E} -> [E|As]; - #k_bin_seg{size=#k_atom{val=all}, + #k_bin_seg{size=#k_literal{val=all}, seg=S,next={k_bin_end,[]}} -> [S|As]; #k_bin_seg{seg=S,next=N} -> @@ -1705,15 +1668,17 @@ squeeze_clauses_by_bin_integer_count([Clause | Clauses], N, Count, GroupAcc, Acc clause_count_bin_integer_segments(#iclause{pats=[#k_bin_seg{seg=#k_literal{}} = BinSeg | _]}) -> count_bin_integer_segments(BinSeg, 0); -clause_count_bin_integer_segments(#iclause{pats=[#k_bin_seg{size=#k_int{val=Size},unit=Unit, - type=integer,flags=[unsigned,big], seg=#k_var{}} | _]}) - when ((Size * Unit) rem 8) =:= 0 -> +clause_count_bin_integer_segments(#iclause{pats=[#k_bin_seg{size=#k_literal{val=Size},unit=Unit, + type=integer,flags=[unsigned,big], + seg=#k_var{}} | _]}) + when ((Size * Unit) rem 8) =:= 0 -> {variadic, (Size * Unit) div 8}; clause_count_bin_integer_segments(_) -> error. -count_bin_integer_segments(#k_bin_seg{size=#k_int{val=8},unit=1,type=integer,flags=[unsigned,big], - seg=#k_literal{val=Int},next=Next}, Count) when is_integer(Int), 0 =< Int, Int =< 255 -> +count_bin_integer_segments(#k_bin_seg{size=#k_literal{val=8},unit=1,type=integer,flags=[unsigned,big], + seg=#k_literal{val=Int},next=Next}, Count) + when is_integer(Int), 0 =< Int, Int =< 255 -> count_bin_integer_segments(Next, Count + 1); count_bin_integer_segments(_, Count) when Count > 0 -> {literal, Count}; @@ -1740,7 +1705,7 @@ squeeze_clauses([], _Size) -> []. squeeze_segments(#k_bin_seg{size=Sz, seg=#k_literal{val=Val}=Lit} = BinSeg, Acc, Size, 1) -> - BinSeg#k_bin_seg{size=Sz#k_int{val=Size + 8}, seg=Lit#k_literal{val=(Acc bsl 8) bor Val}}; + BinSeg#k_bin_seg{size=Sz#k_literal{val=Size + 8}, seg=Lit#k_literal{val=(Acc bsl 8) bor Val}}; squeeze_segments(#k_bin_seg{seg=#k_literal{val=Val},next=Next}, Acc, Size, Count) -> squeeze_segments(Next, (Acc bsl 8) bor Val, Size + 8, Count - 1). @@ -1805,26 +1770,26 @@ arg_alias(_Con) -> []. arg_con(Arg) -> case arg_arg(Arg) of - #k_literal{} -> k_literal; - #k_int{} -> k_int; - #k_float{} -> k_float; - #k_atom{} -> k_atom; - #k_nil{} -> k_nil; - #k_cons{} -> k_cons; + #k_cons{} -> k_cons; #k_tuple{} -> k_tuple; #k_map{} -> k_map; #k_binary{} -> k_binary; #k_bin_end{} -> k_bin_end; #k_bin_seg{} -> k_bin_seg; - #k_var{} -> k_var + #k_var{} -> k_var; + #k_literal{val=[]} -> k_nil; + #k_literal{val=Val} -> + if + is_atom(Val) -> k_atom; + is_integer(Val) -> k_int; + is_float(Val) -> k_float; + true -> k_literal + end end. arg_val(Arg, C) -> case arg_arg(Arg) of #k_literal{val=Lit} -> Lit; - #k_int{val=I} -> I; - #k_float{val=F} -> F; - #k_atom{val=A} -> A; #k_tuple{es=Es} -> length(Es); #k_bin_seg{size=S,unit=U,type=T,flags=Fs} -> case S of @@ -2005,7 +1970,7 @@ uexpr(#k_try{anno=A,arg=A0,vars=Vs,body=B0,evars=Evs,handler=H0}, case is_in_guard(St0) of true -> {[#k_var{name=X}],#k_var{name=X}} = {Vs,B0}, %Assertion. - #k_atom{val=false} = H0, %Assertion. + #k_literal{val=false} = H0, %Assertion. {Avs,St1} = new_vars(length(Rs0), St0), {A1,Bu,St} = uexpr(A0, {break,Avs}, St1), {#k_protected{anno=A,arg=A1,ret=Rs0,inner=Avs},Bu,St}; @@ -2053,7 +2018,7 @@ uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) -> Fun = make_fdef(A, Fname, Arity, Vs++Fvs, B1), {#k_bif{anno=A, op=#k_internal{name=make_fun,arity=length(Free)+2}, - args=[#k_atom{val=Fname},#k_int{val=Arity}|Fvs], + args=[#k_literal{val=Fname},#k_literal{val=Arity}|Fvs], ret=Rs}, Free,add_local_function(Fun, St)}; uexpr(Lit, {break,Rs0}, St0) -> @@ -2188,11 +2153,7 @@ op_vars(Atomic) -> lit_vars(Atomic). %% Return the variables in a literal. lit_vars(#k_var{name=N}) -> [N]; -lit_vars(#k_int{}) -> []; -lit_vars(#k_float{}) -> []; -lit_vars(#k_atom{}) -> []; %%lit_vars(#k_char{}) -> []; -lit_vars(#k_nil{}) -> []; lit_vars(#k_cons{hd=H,tl=T}) -> union(lit_vars(H), lit_vars(T)); lit_vars(#k_map{var=Var,es=Es}) -> @@ -2218,10 +2179,6 @@ lit_list_vars(Ps) -> pat_vars(#k_var{name=N}) -> {[],[N]}; %%pat_vars(#k_char{}) -> {[],[]}; pat_vars(#k_literal{}) -> {[],[]}; -pat_vars(#k_int{}) -> {[],[]}; -pat_vars(#k_float{}) -> {[],[]}; -pat_vars(#k_atom{}) -> {[],[]}; -pat_vars(#k_nil{}) -> {[],[]}; pat_vars(#k_cons{hd=H,tl=T}) -> pat_list_vars([H,T]); pat_vars(#k_binary{segs=V}) -> diff --git a/lib/compiler/src/v3_kernel.hrl b/lib/compiler/src/v3_kernel.hrl index b68cd61b19..f2d90d0c99 100644 --- a/lib/compiler/src/v3_kernel.hrl +++ b/lib/compiler/src/v3_kernel.hrl @@ -27,11 +27,7 @@ %% Literals %% NO CHARACTERS YET. %%-record(k_char, {anno=[],val}). --record(k_literal, {anno=[],val}). %Only used for complex literals. --record(k_int, {anno=[],val}). --record(k_float, {anno=[],val}). --record(k_atom, {anno=[],val}). --record(k_nil, {anno=[]}). +-record(k_literal, {anno=[],val}). -record(k_tuple, {anno=[],es}). -record(k_map, {anno=[],var=#k_literal{val=#{}},op,es}). diff --git a/lib/compiler/src/v3_kernel_pp.erl b/lib/compiler/src/v3_kernel_pp.erl index d99502f571..571d51a59d 100644 --- a/lib/compiler/src/v3_kernel_pp.erl +++ b/lib/compiler/src/v3_kernel_pp.erl @@ -81,11 +81,7 @@ format_anno(Anno, Ctxt0, ObjFun) -> %% format_1(Kexpr, Context) -> string(). -format_1(#k_atom{val=A}, _Ctxt) -> core_atom(A); %%format_1(#k_char{val=C}, _Ctxt) -> io_lib:write_char(C); -format_1(#k_float{val=F}, _Ctxt) -> float_to_list(F); -format_1(#k_int{val=I}, _Ctxt) -> integer_to_list(I); -format_1(#k_nil{}, _Ctxt) -> "[]"; format_1(#k_var{name=V}, _Ctxt) -> if is_atom(V) -> case atom_to_list(V) of @@ -133,10 +129,13 @@ format_1(#k_bin_seg{next=Next}=S, Ctxt) -> [format_bin_seg_1(S, Ctxt), format_bin_seg(Next, ctxt_bump_indent(Ctxt, 2))]; format_1(#k_bin_int{size=Sz,unit=U,flags=Fs,val=Val,next=Next}, Ctxt) -> - S = #k_bin_seg{size=Sz,unit=U,type=integer,flags=Fs,seg=#k_int{val=Val},next=Next}, + S = #k_bin_seg{size=Sz,unit=U,type=integer,flags=Fs, + seg=#k_literal{val=Val},next=Next}, [format_bin_seg_1(S, Ctxt), format_bin_seg(Next, ctxt_bump_indent(Ctxt, 2))]; format_1(#k_bin_end{}, _Ctxt) -> "#<>#"; +format_1(#k_literal{val=A}, _Ctxt) when is_atom(A) -> + core_atom(A); format_1(#k_literal{val=Term}, _Ctxt) -> io_lib:format("~p", [Term]); format_1(#k_local{name=N,arity=A}, Ctxt) -> @@ -325,7 +324,7 @@ format_1(#k_fdef{func=F,arity=A,vars=Vs,body=B}, Ctxt) -> ]; format_1(#k_mdef{name=N,exports=Es,attributes=As,body=B}, Ctxt) -> ["module ", - format(#k_atom{val=N}, ctxt_bump_indent(Ctxt, 7)), + format(#k_literal{val=N}, ctxt_bump_indent(Ctxt, 7)), nl_indent(Ctxt), "export [", format_vseq(Es, @@ -415,17 +414,17 @@ format_fa_pair({F,A}, _Ctxt) -> [core_atom(F),$/,integer_to_list(A)]. %% format_attribute({Name,Val}, Context) -> Txt. format_attribute({Name,Val}, Ctxt) when is_list(Val) -> - Txt = format(#k_atom{val=Name}, Ctxt), + Txt = format(#k_literal{val=Name}, Ctxt), Ctxt1 = ctxt_bump_indent(Ctxt, width(Txt,Ctxt)+4), [Txt," = ", $[,format_vseq(Val, "", ",", Ctxt1, fun (A, _C) -> io_lib:write(A) end),$] ]; format_attribute({Name,Val}, Ctxt) -> - Txt = format(#k_atom{val=Name}, Ctxt), + Txt = format(#k_literal{val=Name}, Ctxt), [Txt," = ",io_lib:write(Val)]. -format_list_tail(#k_nil{anno=[]}, _Ctxt) -> "]"; +format_list_tail(#k_literal{anno=[],val=[]}, _Ctxt) -> "]"; format_list_tail(#k_cons{anno=[],hd=H,tl=T}, Ctxt) -> Txt = [$,|format(H, Ctxt)], Ctxt1 = ctxt_bump_indent(Ctxt, width(Txt, Ctxt)), -- cgit v1.2.1