1%% ``Licensed under the Apache License, Version 2.0 (the "License"); 2%% you may not use this file except in compliance with the License. 3%% You may obtain a copy of the License at 4%% 5%% http://www.apache.org/licenses/LICENSE-2.0 6%% 7%% Unless required by applicable law or agreed to in writing, software 8%% distributed under the License is distributed on an "AS IS" BASIS, 9%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10%% See the License for the specific language governing permissions and 11%% limitations under the License. 12%% 13%% The Initial Developer of the Original Code is Ericsson Utvecklings AB. 14%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings 15%% AB. All Rights Reserved.'' 16%% 17%% $Id: v3_codegen.erl,v 1.1 2008/12/17 09:53:42 mikpe Exp $ 18%% Purpose : Code generator for Beam. 19 20%% The following assumptions have been made: 21%% 22%% 1. Matches, i.e. things with {match,M,Ret} wrappers, only return 23%% values; no variables are exported. If the match would have returned 24%% extra variables then these have been transformed to multiple return 25%% values. 26%% 27%% 2. All BIF's called in guards are gc-safe so there is no need to 28%% put thing on the stack in the guard. While this would in principle 29%% work it would be difficult to keep track of the stack depth when 30%% trimming. 31%% 32%% The code generation uses variable lifetime information added by 33%% the v3_life module to save variables, allocate registers and 34%% move registers to the stack when necessary. 35%% 36%% We try to use a consistent variable name scheme throughout. The 37%% StackReg record is always called Bef,Int<n>,Aft. 38 39-module(v3_codegen). 40 41%% The main interface. 42-export([module/2]). 43 44-import(lists, [member/2,keymember/3,keysort/2,keysearch/3,append/1, 45 map/2,flatmap/2,foldl/3,foldr/3,mapfoldl/3, 46 sort/1,reverse/1,reverse/2]). 47-import(v3_life, [vdb_find/2]). 48 49%%-compile([export_all]). 50 51-include("v3_life.hrl"). 52 53%% Main codegen structure. 54-record(cg, {lcount=1, %Label counter 55 mod, %Current module 56 func, %Current function 57 finfo, %Function info label 58 fcode, %Function code label 59 btype, %Type of bif used. 60 bfail, %Fail label of bif 61 break, %Break label 62 recv, %Receive label 63 is_top_block, %Boolean: top block or not 64 functable = [], %Table of local functions: 65 %[{{Name, Arity}, Label}...] 66 in_catch=false, %Inside a catch or not. 67 need_frame, %Need a stack frame. 68 new_funs=true}). %Generate new fun instructions. 69 70%% Stack/register state record. 71-record(sr, {reg=[], %Register table 72 stk=[], %Stack table 73 res=[]}). %Reserved regs: [{reserved,I,V}] 74 75module({Mod,Exp,Attr,Forms}, Options) -> 76 NewFunsFlag = not member(no_new_funs, Options), 77 {Fs,St} = functions(Forms, #cg{mod=Mod,new_funs=NewFunsFlag}), 78 {ok,{Mod,Exp,Attr,Fs,St#cg.lcount}}. 79 80functions(Forms, St0) -> 81 mapfoldl(fun (F, St) -> function(F, St) end, St0#cg{lcount=1}, Forms). 82 83function({function,Name,Arity,As0,Vb,Vdb}, St0) -> 84 %%ok = io:fwrite("cg ~w:~p~n", [?LINE,{Name,Arity}]), 85 St1 = St0#cg{func={Name,Arity}}, 86 {Fun,St2} = cg_fun(Vb, As0, Vdb, St1), 87 Func0 = {function,Name,Arity,St2#cg.fcode,Fun}, 88 Func = bs_function(Func0), 89 {Func,St2}. 90 91%% cg_fun([Lkexpr], [HeadVar], Vdb, State) -> {[Ainstr],State} 92 93cg_fun(Les, Hvs, Vdb, St0) -> 94 {Name,Arity} = St0#cg.func, 95 {Fi,St1} = new_label(St0), %FuncInfo label 96 {Fl,St2} = local_func_label(Name, Arity, St1), 97 %% Create initial stack/register state, clear unused arguments. 98 Bef = clear_dead(#sr{reg=foldl(fun ({var,V}, Reg) -> 99 put_reg(V, Reg) 100 end, [], Hvs), 101 stk=[]}, 0, Vdb), 102 {B2,_Aft,St3} = cg_list(Les, 0, Vdb, Bef, St2#cg{btype=exit, 103 bfail=Fi, 104 finfo=Fi, 105 fcode=Fl, 106 is_top_block=true}), 107 A = [{label,Fi},{func_info,{atom,St3#cg.mod},{atom,Name},Arity}, 108 {label,Fl}|B2], 109 {A,St3}. 110 111%% cg(Lkexpr, Vdb, StackReg, State) -> {[Ainstr],StackReg,State}. 112%% Generate code for a kexpr. 113%% Split function into two steps for clarity, not efficiency. 114 115cg(Le, Vdb, Bef, St) -> 116 cg(Le#l.ke, Le, Vdb, Bef, St). 117 118cg({block,Es}, Le, Vdb, Bef, St) -> 119 block_cg(Es, Le, Vdb, Bef, St); 120cg({match,M,Rs}, Le, Vdb, Bef, St) -> 121 match_cg(M, Rs, Le, Vdb, Bef, St); 122cg({match_fail,F}, Le, Vdb, Bef, St) -> 123 match_fail_cg(F, Le, Vdb, Bef, St); 124cg({call,Func,As,Rs}, Le, Vdb, Bef, St) -> 125 call_cg(Func, As, Rs, Le, Vdb, Bef, St); 126cg({enter,Func,As}, Le, Vdb, Bef, St) -> 127 enter_cg(Func, As, Le, Vdb, Bef, St); 128cg({bif,Bif,As,Rs}, Le, Vdb, Bef, St) -> 129 bif_cg(Bif, As, Rs, Le, Vdb, Bef, St); 130cg({receive_loop,Te,Rvar,Rm,Tes,Rs}, Le, Vdb, Bef, St) -> 131 recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St); 132cg(receive_next, Le, Vdb, Bef, St) -> 133 recv_next_cg(Le, Vdb, Bef, St); 134cg(receive_accept, _Le, _Vdb, Bef, St) -> {[remove_message],Bef,St}; 135cg({'try',Ta,Vs,Tb,Evs,Th,Rs}, Le, Vdb, Bef, St) -> 136 try_cg(Ta, Vs, Tb, Evs, Th, Rs, Le, Vdb, Bef, St); 137cg({'catch',Cb,R}, Le, Vdb, Bef, St) -> 138 catch_cg(Cb, R, Le, Vdb, Bef, St); 139cg({set,Var,Con}, Le, Vdb, Bef, St) -> set_cg(Var, Con, Le, Vdb, Bef, St); 140cg({return,Rs}, Le, Vdb, Bef, St) -> return_cg(Rs, Le, Vdb, Bef, St); 141cg({break,Bs}, Le, Vdb, Bef, St) -> break_cg(Bs, Le, Vdb, Bef, St); 142cg({need_heap,0}, _Le, _Vdb, Bef, St) -> 143 {[],Bef,St}; 144cg({need_heap,H}, _Le, _Vdb, Bef, St) -> 145 {[{test_heap,H,max_reg(Bef#sr.reg)}],Bef,St}. 146 147%% cg_list([Kexpr], FirstI, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}. 148 149cg_list(Kes, I, Vdb, Bef, St0) -> 150 {Keis,{Aft,St1}} = 151 flatmapfoldl(fun (Ke, {Inta,Sta}) -> 152% ok = io:fwrite(" %% ~p\n", [Inta]), 153% ok = io:fwrite("cgl:~p\n", [Ke]), 154 {Keis,Intb,Stb} = cg(Ke, Vdb, Inta, Sta), 155% ok = io:fwrite(" ~p\n", [Keis]), 156% ok = io:fwrite(" %% ~p\n", [Intb]), 157 {comment(Inta) ++ Keis,{Intb,Stb}} 158 end, {Bef,St0}, need_heap(Kes, I)), 159 {Keis,Aft,St1}. 160 161%% need_heap([Lkexpr], I, BifType) -> [Lkexpr]. 162%% Insert need_heap instructions in Kexpr list. Try to be smart and 163%% collect them together as much as possible. 164 165need_heap(Kes0, I) -> 166 {Kes1,{H,F}} = flatmapfoldr(fun (Ke, {H0,F0}) -> 167 {Ns,H1,F1} = need_heap_1(Ke, H0, F0), 168 {[Ke|Ns],{H1,F1}} 169 end, {0,false}, Kes0), 170 %% Prepend need_heap if necessary. 171 Kes2 = need_heap_need(I, H, F) ++ Kes1, 172% ok = io:fwrite("need_heap: ~p~n", 173% [{{H,F}, 174% map(fun (#l{ke={match,M,Rs}}) -> match; 175% (Lke) -> Lke#l.ke end, Kes2)}]), 176 Kes2. 177 178need_heap_1(#l{ke={set,_,{binary,_}},i=I}, H, F) -> 179 {need_heap_need(I, H, F),0,false}; 180need_heap_1(#l{ke={set,_,Val}}, H, F) -> 181 %% Just pass through adding to needed heap. 182 {[],H + case Val of 183 {cons,_} -> 2; 184 {tuple,Es} -> 1 + length(Es); 185 {string,S} -> 2 * length(S); 186 _Other -> 0 187 end,F}; 188need_heap_1(#l{ke={call,_Func,_As,_Rs},i=I}, H, F) -> 189 %% Calls generate a need if necessary and also force one. 190 {need_heap_need(I, H, F),0,true}; 191need_heap_1(#l{ke={bif,dsetelement,_As,_Rs},i=I}, H, F) -> 192 {need_heap_need(I, H, F),0,true}; 193need_heap_1(#l{ke={bif,{make_fun,_,_,_,_},_As,_Rs},i=I}, H, F) -> 194 {need_heap_need(I, H, F),0,true}; 195need_heap_1(#l{ke={bif,_Bif,_As,_Rs}}, H, F) -> 196 {[],H,F}; 197need_heap_1(#l{i=I}, H, F) -> 198 %% Others kexprs generate a need if necessary but don't force. 199 {need_heap_need(I, H, F),0,false}. 200 201need_heap_need(_I, 0, false) -> []; 202need_heap_need(I, H, _F) -> [#l{ke={need_heap,H},i=I}]. 203 204 205%% match_cg(Match, [Ret], Le, Vdb, StackReg, State) -> 206%% {[Ainstr],StackReg,State}. 207%% Generate code for a match. First save all variables on the stack 208%% that are to survive after the match. We leave saved variables in 209%% their registers as they might actually be in the right place. 210%% Should test this. 211 212match_cg(M, Rs, Le, Vdb, Bef, St0) -> 213 I = Le#l.i, 214 {Sis,Int0} = adjust_stack(Bef, I, I+1, Vdb), 215 {B,St1} = new_label(St0), 216 {Mis,Int1,St2} = match_cg(M, none, Int0, St1#cg{break=B}), 217 %% Put return values in registers. 218 Reg = load_vars(Rs, Int1#sr.reg), 219 {Sis ++ Mis ++ [{label,B}], 220 clear_dead(Int1#sr{reg=Reg}, I, Vdb), 221 St2#cg{break=St1#cg.break}}. 222 223%% match_cg(Match, Fail, StackReg, State) -> {[Ainstr],StackReg,State}. 224%% Generate code for a match tree. N.B. there is no need pass Vdb 225%% down as each level which uses this takes its own internal Vdb not 226%% the outer one. 227 228match_cg(Le, Fail, Bef, St) -> 229 match_cg(Le#l.ke, Le, Fail, Bef, St). 230 231match_cg({alt,F,S}, _Le, Fail, Bef, St0) -> 232 {Tf,St1} = new_label(St0), 233 {Fis,Faft,St2} = match_cg(F, Tf, Bef, St1), 234 {Sis,Saft,St3} = match_cg(S, Fail, Bef, St2), 235 Aft = sr_merge(Faft, Saft), 236 {Fis ++ [{label,Tf}] ++ Sis,Aft,St3}; 237match_cg({select,V,Scs}, _Va, Fail, Bef, St) -> 238 match_fmf(fun (S, F, Sta) -> 239 select_cg(S, V, F, Fail, Bef, Sta) end, 240 Fail, St, Scs); 241match_cg({guard,Gcs}, _Le, Fail, Bef, St) -> 242 match_fmf(fun (G, F, Sta) -> guard_clause_cg(G, F, Bef, Sta) end, 243 Fail, St, Gcs); 244match_cg({block,Es}, Le, _Fail, Bef, St) -> 245 %% Must clear registers and stack of dead variables. 246 Int = clear_dead(Bef, Le#l.i, Le#l.vdb), 247 block_cg(Es, Le, Int, St). 248 249%% match_fail_cg(FailReason, Le, Vdb, StackReg, State) -> 250%% {[Ainstr],StackReg,State}. 251%% Generate code for the match_fail "call". N.B. there is no generic 252%% case for when the fail value has been created elsewhere. 253 254match_fail_cg({function_clause,As}, Le, Vdb, Bef, St) -> 255 %% Must have the args in {x,0}, {x,1},... 256 {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb), 257 {Sis ++ [{jump,{f,St#cg.finfo}}], 258 Int#sr{reg=clear_regs(Int#sr.reg)},St}; 259match_fail_cg({badmatch,Term}, Le, Vdb, Bef, St) -> 260 R = cg_reg_arg(Term, Bef), 261 Int0 = clear_dead(Bef, Le#l.i, Vdb), 262 {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), 263 {Sis ++ [{badmatch,R}], 264 Int#sr{reg=clear_regs(Int0#sr.reg)},St}; 265match_fail_cg({case_clause,Reason}, Le, Vdb, Bef, St) -> 266 R = cg_reg_arg(Reason, Bef), 267 Int0 = clear_dead(Bef, Le#l.i, Vdb), 268 {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), 269 {Sis++[{case_end,R}], 270 Int#sr{reg=clear_regs(Bef#sr.reg)},St}; 271match_fail_cg(if_clause, Le, Vdb, Bef, St) -> 272 Int0 = clear_dead(Bef, Le#l.i, Vdb), 273 {Sis,Int1} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), 274 {Sis++[if_end],Int1#sr{reg=clear_regs(Int1#sr.reg)},St}; 275match_fail_cg({try_clause,Reason}, Le, Vdb, Bef, St) -> 276 R = cg_reg_arg(Reason, Bef), 277 Int0 = clear_dead(Bef, Le#l.i, Vdb), 278 {Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb), 279 {Sis ++ [{try_case_end,R}], 280 Int#sr{reg=clear_regs(Int0#sr.reg)},St}. 281 282 283%% block_cg([Kexpr], Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}. 284%% block_cg([Kexpr], Le, StackReg, St) -> {[Ainstr],StackReg,St}. 285 286block_cg(Es, Le, _Vdb, Bef, St) -> 287 block_cg(Es, Le, Bef, St). 288 289block_cg(Es, Le, Bef, St0) -> 290 case St0#cg.is_top_block of 291 false -> 292 cg_block(Es, Le#l.i, Le#l.vdb, Bef, St0); 293 true -> 294 {Keis,Aft,St1} = cg_block(Es, Le#l.i, Le#l.vdb, Bef, 295 St0#cg{is_top_block=false, 296 need_frame=false}), 297 top_level_block(Keis, Aft, max_reg(Bef#sr.reg), St1) 298 end. 299 300cg_block([], _I, _Vdb, Bef, St0) -> 301 {[],Bef,St0}; 302cg_block(Kes0, I, Vdb, Bef, St0) -> 303 {Kes2,Int1,St1} = 304 case basic_block(Kes0) of 305 {Kes1,LastI,Args,Rest} -> 306 Ke = hd(Kes1), 307 Fb = Ke#l.i, 308 cg_basic_block(Kes1, Fb, LastI, Args, Vdb, Bef, St0); 309 {Kes1,Rest} -> 310 cg_list(Kes1, I, Vdb, Bef, St0) 311 end, 312 {Kes3,Int2,St2} = cg_block(Rest, I, Vdb, Int1, St1), 313 {Kes2 ++ Kes3,Int2,St2}. 314 315basic_block(Kes) -> basic_block(Kes, []). 316 317basic_block([], Acc) -> {reverse(Acc),[]}; 318basic_block([Le|Les], Acc) -> 319 case collect_block(Le#l.ke) of 320 include -> basic_block(Les, [Le|Acc]); 321 {block_end,As} -> {reverse(Acc, [Le]),Le#l.i,As,Les}; 322 no_block -> {reverse(Acc, [Le]),Les} 323 end. 324 325collect_block({set,_,{binary,_}}) -> no_block; 326collect_block({set,_,_}) -> include; 327collect_block({call,{var,_}=Var,As,_Rs}) -> {block_end,As++[Var]}; 328collect_block({call,Func,As,_Rs}) -> {block_end,As++func_vars(Func)}; 329collect_block({enter,{var,_}=Var,As})-> {block_end,As++[Var]}; 330collect_block({enter,Func,As}) -> {block_end,As++func_vars(Func)}; 331collect_block({return,Rs}) -> {block_end,Rs}; 332collect_block({break,Bs}) -> {block_end,Bs}; 333collect_block({bif,_Bif,_As,_Rs}) -> include; 334collect_block(_) -> no_block. 335 336func_vars({remote,M,F}) when element(1, M) == var; 337 element(1, F) == var -> 338 [M,F]; 339func_vars(_) -> []. 340 341%% cg_basic_block([Kexpr], FirstI, LastI, As, Vdb, StackReg, State) -> 342%% {[Ainstr],StackReg,State}. 343 344cg_basic_block(Kes, Fb, Lf, As, Vdb, Bef, St0) -> 345 Res = make_reservation(As, 0), 346 Regs0 = reserve(Res, Bef#sr.reg, Bef#sr.stk), 347 Stk = extend_stack(Bef, Lf, Lf+1, Vdb), 348 Int0 = Bef#sr{reg=Regs0,stk=Stk,res=Res}, 349 X0_v0 = x0_vars(As, Fb, Lf, Vdb), 350 {Keis,{Aft,_,St1}} = 351 flatmapfoldl(fun(Ke, St) -> cg_basic_block(Ke, St, Lf, Vdb) end, 352 {Int0,X0_v0,St0}, need_heap(Kes, Fb)), 353 {Keis,Aft,St1}. 354 355cg_basic_block(Ke, {Inta,X0v,Sta}, _Lf, Vdb) when element(1, Ke#l.ke) =:= need_heap -> 356 {Keis,Intb,Stb} = cg(Ke, Vdb, Inta, Sta), 357 {comment(Inta) ++ Keis, {Intb,X0v,Stb}}; 358cg_basic_block(Ke, {Inta,X0_v1,Sta}, Lf, Vdb) -> 359 {Sis,Intb} = save_carefully(Inta, Ke#l.i, Lf+1, Vdb), 360 {X0_v2,Intc} = allocate_x0(X0_v1, Ke#l.i, Intb), 361 Intd = reserve(Intc), 362 {Keis,Inte,Stb} = cg(Ke, Vdb, Intd, Sta), 363 {comment(Inta) ++ Sis ++ Keis, {Inte,X0_v2,Stb}}. 364 365make_reservation([], _) -> []; 366make_reservation([{var,V}|As], I) -> [{I,V}|make_reservation(As, I+1)]; 367make_reservation([A|As], I) -> [{I,A}|make_reservation(As, I+1)]. 368 369reserve(Sr) -> Sr#sr{reg=reserve(Sr#sr.res, Sr#sr.reg, Sr#sr.stk)}. 370 371reserve([{I,V}|Rs], [free|Regs], Stk) -> [{reserved,I,V}|reserve(Rs, Regs, Stk)]; 372reserve([{I,V}|Rs], [{I,V}|Regs], Stk) -> [{I,V}|reserve(Rs, Regs, Stk)]; 373reserve([{I,V}|Rs], [{I,Var}|Regs], Stk) -> 374 case on_stack(Var, Stk) of 375 true -> [{reserved,I,V}|reserve(Rs, Regs, Stk)]; 376 false -> [{I,Var}|reserve(Rs, Regs, Stk)] 377 end; 378reserve([{I,V}|Rs], [{reserved,I,_}|Regs], Stk) -> 379 [{reserved,I,V}|reserve(Rs, Regs, Stk)]; 380%reserve([{I,V}|Rs], [Other|Regs], Stk) -> [Other|reserve(Rs, Regs, Stk)]; 381reserve([{I,V}|Rs], [], Stk) -> [{reserved,I,V}|reserve(Rs, [], Stk)]; 382reserve([], Regs, _) -> Regs. 383 384extend_stack(Bef, Fb, Lf, Vdb) -> 385 Stk0 = clear_dead_stk(Bef#sr.stk, Fb, Vdb), 386 Saves = [V || {V,F,L} <- Vdb, 387 F < Fb, 388 L >= Lf, 389 not on_stack(V, Stk0)], 390 Stk1 = foldl(fun (V, Stk) -> put_stack(V, Stk) end, Stk0, Saves), 391 Bef#sr.stk ++ lists:duplicate(length(Stk1) - length(Bef#sr.stk), free). 392 393save_carefully(Bef, Fb, Lf, Vdb) -> 394 Stk = Bef#sr.stk, 395 %% New variables that are in use but not on stack. 396 New = [ {V,F,L} || {V,F,L} <- Vdb, 397 F < Fb, 398 L >= Lf, 399 not on_stack(V, Stk) ], 400 Saves = [ V || {V,_,_} <- keysort(2, New) ], 401 save_carefully(Saves, Bef, []). 402 403save_carefully([], Bef, Acc) -> {reverse(Acc),Bef}; 404save_carefully([V|Vs], Bef, Acc) -> 405 case put_stack_carefully(V, Bef#sr.stk) of 406 error -> {reverse(Acc),Bef}; 407 Stk1 -> 408 SrcReg = fetch_reg(V, Bef#sr.reg), 409 Move = {move,SrcReg,fetch_stack(V, Stk1)}, 410 {x,_} = SrcReg, %Assertion - must be X register. 411 save_carefully(Vs, Bef#sr{stk=Stk1}, [Move|Acc]) 412 end. 413 414x0_vars([], _Fb, _Lf, _Vdb) -> []; 415x0_vars([{var,V}|_], Fb, _Lf, Vdb) -> 416 {V,F,_L} = VFL = vdb_find(V, Vdb), 417 x0_vars1([VFL], Fb, F, Vdb); 418x0_vars([X0|_], Fb, Lf, Vdb) -> 419 x0_vars1([{X0,Lf,Lf}], Fb, Lf, Vdb). 420 421x0_vars1(X0, Fb, Xf, Vdb) -> 422 Vs0 = [VFL || {_V,F,L}=VFL <- Vdb, 423 F >= Fb, 424 L < Xf], 425 Vs1 = keysort(3, Vs0), 426 keysort(2, X0++Vs1). 427 428allocate_x0([], _, Bef) -> {[],Bef#sr{res=[]}}; 429allocate_x0([{_,_,L}|Vs], I, Bef) when L =< I -> 430 allocate_x0(Vs, I, Bef); 431allocate_x0([{V,_F,_L}=VFL|Vs], _, Bef) -> 432 {[VFL|Vs],Bef#sr{res=reserve_x0(V, Bef#sr.res)}}. 433 434reserve_x0(V, [_|Res]) -> [{0,V}|Res]; 435reserve_x0(V, []) -> [{0,V}]. 436 437top_level_block(Keis, Bef, _MaxRegs, St0) when St0#cg.need_frame =:= false, 438 length(Bef#sr.stk) =:= 0 -> 439 %% This block need no stack frame. However, we still need to turn the 440 %% stack frame upside down. 441 MaxY = length(Bef#sr.stk)-1, 442 Keis1 = flatmap(fun (Tuple) when tuple(Tuple) -> 443 [turn_yregs(size(Tuple), Tuple, MaxY)]; 444 (Other) -> 445 [Other] 446 end, Keis), 447 {Keis1, Bef, St0#cg{is_top_block=true}}; 448top_level_block(Keis, Bef, MaxRegs, St0) -> 449 %% This top block needs an allocate instruction before it, and a 450 %% deallocate instruction before each return. 451 FrameSz = length(Bef#sr.stk), 452 MaxY = FrameSz-1, 453 Keis1 = flatmap(fun ({call_only,Arity,Func}) -> 454 [{call_last,Arity,Func,FrameSz}]; 455 ({call_ext_only,Arity,Func}) -> 456 [{call_ext_last,Arity,Func,FrameSz}]; 457 ({apply_only,Arity}) -> 458 [{apply_last,Arity,FrameSz}]; 459 (return) -> 460 [{deallocate,FrameSz}, return]; 461 (Tuple) when tuple(Tuple) -> 462 [turn_yregs(size(Tuple), Tuple, MaxY)]; 463 (Other) -> 464 [Other] 465 end, Keis), 466 {[{allocate_zero,FrameSz,MaxRegs}|Keis1], Bef, St0#cg{is_top_block=true}}. 467 468%% turn_yregs(Size, Tuple, MaxY) -> Tuple' 469%% Renumber y register so that {y, 0} becomes {y, FrameSize-1}, 470%% {y, FrameSize-1} becomes {y, 0} and so on. This is to make nested 471%% catches work. The code generation algorithm gives a lower register 472%% number to the outer catch, which is wrong. 473 474turn_yregs(0, Tp, _) -> Tp; 475turn_yregs(El, Tp, MaxY) when element(1, element(El, Tp)) == yy -> 476 turn_yregs(El-1, setelement(El, Tp, {y,MaxY-element(2, element(El, Tp))}), MaxY); 477turn_yregs(El, Tp, MaxY) when list(element(El, Tp)) -> 478 New = map(fun ({yy,YY}) -> {y,MaxY-YY}; 479 (Other) -> Other end, element(El, Tp)), 480 turn_yregs(El-1, setelement(El, Tp, New), MaxY); 481turn_yregs(El, Tp, MaxY) -> 482 turn_yregs(El-1, Tp, MaxY). 483 484%% select_cg(Sclause, V, TypeFail, ValueFail, StackReg, State) -> 485%% {Is,StackReg,State}. 486%% Selecting type and value needs two failure labels, TypeFail is the 487%% label to jump to of the next type test when this type fails, and 488%% ValueFail is the label when this type is correct but the value is 489%% wrong. These are different as in the second case there is no need 490%% to try the next type, it will always fail. 491 492select_cg(#l{ke={type_clause,cons,[S]}}, {var,V}, Tf, Vf, Bef, St) -> 493 select_cons(S, V, Tf, Vf, Bef, St); 494select_cg(#l{ke={type_clause,nil,[S]}}, {var,V}, Tf, Vf, Bef, St) -> 495 select_nil(S, V, Tf, Vf, Bef, St); 496select_cg(#l{ke={type_clause,binary,[S]}}, {var,V}, Tf, Vf, Bef, St) -> 497 select_binary(S, V, Tf, Vf, Bef, St); 498select_cg(#l{ke={type_clause,bin_seg,S}}, {var,V}, Tf, Vf, Bef, St) -> 499 select_bin_segs(S, V, Tf, Vf, Bef, St); 500select_cg(#l{ke={type_clause,bin_end,[S]}}, {var,V}, Tf, Vf, Bef, St) -> 501 select_bin_end(S, V, Tf, Vf, Bef, St); 502select_cg(#l{ke={type_clause,Type,Scs}}, {var,V}, Tf, Vf, Bef, St0) -> 503 {Vis,{Aft,St1}} = 504 mapfoldl(fun (S, {Int,Sta}) -> 505 {Val,Is,Inta,Stb} = select_val(S, V, Vf, Bef, Sta), 506 {{Is,[Val]},{sr_merge(Int, Inta),Stb}} 507 end, {void,St0}, Scs), 508 OptVls = combine(lists:sort(combine(Vis))), 509 {Vls,Sis,St2} = select_labels(OptVls, St1, [], []), 510 {select_val_cg(Type, fetch_var(V, Bef), Vls, Tf, Vf, Sis), Aft, St2}. 511 512select_val_cg(tuple, R, [Arity,{f,Lbl}], Tf, Vf, [{label,Lbl}|Sis]) -> 513 [{test,is_tuple,{f,Tf},[R]},{test,test_arity,{f,Vf},[R,Arity]}|Sis]; 514select_val_cg(tuple, R, Vls, Tf, Vf, Sis) -> 515 [{test,is_tuple,{f,Tf},[R]},{select_tuple_arity,R,{f,Vf},{list,Vls}}|Sis]; 516select_val_cg(Type, R, [Val, {f,Lbl}], Fail, Fail, [{label,Lbl}|Sis]) -> 517 [{test,is_eq_exact,{f,Fail},[R,{Type,Val}]}|Sis]; 518select_val_cg(Type, R, [Val, {f,Lbl}], Tf, Vf, [{label,Lbl}|Sis]) -> 519 [{test,select_type_test(Type),{f,Tf},[R]}, 520 {test,is_eq_exact,{f,Vf},[R,{Type,Val}]}|Sis]; 521select_val_cg(Type, R, Vls0, Tf, Vf, Sis) -> 522 Vls1 = map(fun ({f,Lbl}) -> {f,Lbl}; 523 (Value) -> {Type,Value} 524 end, Vls0), 525 [{test,select_type_test(Type),{f,Tf},[R]}, {select_val,R,{f,Vf},{list,Vls1}}|Sis]. 526 527select_type_test(tuple) -> is_tuple; 528select_type_test(integer) -> is_integer; 529select_type_test(atom) -> is_atom; 530select_type_test(float) -> is_float. 531 532combine([{Is,Vs1}, {Is,Vs2}|Vis]) -> combine([{Is,Vs1 ++ Vs2}|Vis]); 533combine([V|Vis]) -> [V|combine(Vis)]; 534combine([]) -> []. 535 536select_labels([{Is,Vs}|Vis], St0, Vls, Sis) -> 537 {Lbl,St1} = new_label(St0), 538 select_labels(Vis, St1, add_vls(Vs, Lbl, Vls), [[{label,Lbl}|Is]|Sis]); 539select_labels([], St, Vls, Sis) -> 540 {Vls,append(Sis),St}. 541 542add_vls([V|Vs], Lbl, Acc) -> 543 add_vls(Vs, Lbl, [V, {f,Lbl}|Acc]); 544add_vls([], _, Acc) -> Acc. 545 546select_cons(#l{ke={val_clause,{cons,Es},B},i=I,vdb=Vdb}, V, Tf, Vf, Bef, St0) -> 547 {Eis,Int,St1} = select_extract_cons(V, Es, I, Vdb, Bef, St0), 548 {Bis,Aft,St2} = match_cg(B, Vf, Int, St1), 549 {[{test,is_nonempty_list,{f,Tf},[fetch_var(V, Bef)]}] ++ Eis ++ Bis,Aft,St2}. 550 551select_nil(#l{ke={val_clause,nil,B}}, V, Tf, Vf, Bef, St0) -> 552 {Bis,Aft,St1} = match_cg(B, Vf, Bef, St0), 553 {[{test,is_nil,{f,Tf},[fetch_var(V, Bef)]}] ++ Bis,Aft,St1}. 554 555select_binary(#l{ke={val_clause,{old_binary,Var},B}}=L, 556 V, Tf, Vf, Bef, St) -> 557 %% Currently handled in the same way as new binaries. 558 select_binary(L#l{ke={val_clause,{binary,Var},B}}, V, Tf, Vf, Bef, St); 559select_binary(#l{ke={val_clause,{binary,{var,Ivar}},B},i=I,vdb=Vdb}, 560 V, Tf, Vf, Bef, St0) -> 561 Int0 = clear_dead(Bef, I, Vdb), 562 {Bis,Aft,St1} = match_cg(B, Vf, Int0, St0), 563 {[{test,bs_start_match,{f,Tf},[fetch_var(V, Bef)]},{bs_save,Ivar}|Bis], 564 Aft,St1}. 565 566select_bin_segs(Scs, Ivar, Tf, _Vf, Bef, St) -> 567 match_fmf(fun(S, Fail, Sta) -> 568 select_bin_seg(S, Ivar, Fail, Bef, Sta) end, 569 Tf, St, Scs). 570 571select_bin_seg(#l{ke={val_clause,{bin_seg,Size,U,T,Fs,Es},B},i=I,vdb=Vdb}, 572 Ivar, Fail, Bef, St0) -> 573 {Mis,Int,St1} = select_extract_bin(Es, Size, U, T, Fs, Fail, 574 I, Vdb, Bef, St0), 575 {Bis,Aft,St2} = match_cg(B, Fail, Int, St1), 576 {[{bs_restore,Ivar}|Mis] ++ Bis,Aft,St2}. 577 578select_extract_bin([{var,Hd},{var,Tl}], Size0, Unit, Type, Flags, Vf, 579 I, Vdb, Bef, St) -> 580 SizeReg = get_bin_size_reg(Size0, Bef), 581 {Es,Aft} = 582 case vdb_find(Hd, Vdb) of 583 {_,_,Lhd} when Lhd =< I -> 584 {[{test,bs_skip_bits,{f,Vf},[SizeReg,Unit,{field_flags,Flags}]}, 585 {bs_save,Tl}],Bef}; 586 {_,_,_} -> 587 Reg0 = put_reg(Hd, Bef#sr.reg), 588 Int1 = Bef#sr{reg=Reg0}, 589 Rhd = fetch_reg(Hd, Reg0), 590 Name = get_bits_instr(Type), 591 {[{test,Name,{f,Vf},[SizeReg,Unit,{field_flags,Flags},Rhd]}, 592 {bs_save,Tl}],Int1} 593 end, 594 {Es,clear_dead(Aft, I, Vdb),St}. 595 596get_bin_size_reg({var,V}, Bef) -> 597 fetch_var(V, Bef); 598get_bin_size_reg(Literal, _Bef) -> 599 Literal. 600 601select_bin_end(#l{ke={val_clause,bin_end,B}}, 602 Ivar, Tf, Vf, Bef, St0) -> 603 {Bis,Aft,St2} = match_cg(B, Vf, Bef, St0), 604 {[{bs_restore,Ivar},{test,bs_test_tail,{f,Tf},[0]}|Bis],Aft,St2}. 605 606get_bits_instr(integer) -> bs_get_integer; 607get_bits_instr(float) -> bs_get_float; 608get_bits_instr(binary) -> bs_get_binary. 609 610select_val(#l{ke={val_clause,{tuple,Es},B},i=I,vdb=Vdb}, V, Vf, Bef, St0) -> 611 {Eis,Int,St1} = select_extract_tuple(V, Es, I, Vdb, Bef, St0), 612 {Bis,Aft,St2} = match_cg(B, Vf, Int, St1), 613 {length(Es),Eis ++ Bis,Aft,St2}; 614select_val(#l{ke={val_clause,{_,Val},B}}, _V, Vf, Bef, St0) -> 615 {Bis,Aft,St1} = match_cg(B, Vf, Bef, St0), 616 {Val,Bis,Aft,St1}. 617 618%% select_extract_tuple(Src, [V], I, Vdb, StackReg, State) -> 619%% {[E],StackReg,State}. 620%% Extract tuple elements, but only if they do not immediately die. 621 622select_extract_tuple(Src, Vs, I, Vdb, Bef, St) -> 623 F = fun ({var,V}, {Int0,Elem}) -> 624 case vdb_find(V, Vdb) of 625 {V,_,L} when L =< I -> {[], {Int0,Elem+1}}; 626 _Other -> 627 Reg1 = put_reg(V, Int0#sr.reg), 628 Int1 = Int0#sr{reg=Reg1}, 629 Rsrc = fetch_var(Src, Int1), 630 {[{get_tuple_element,Rsrc,Elem,fetch_reg(V, Reg1)}], 631 {Int1,Elem+1}} 632 end 633 end, 634 {Es,{Aft,_}} = flatmapfoldl(F, {Bef,0}, Vs), 635 {Es,Aft,St}. 636 637select_extract_cons(Src, [{var,Hd}, {var,Tl}], I, Vdb, Bef, St) -> 638 {Es,Aft} = case {vdb_find(Hd, Vdb), vdb_find(Tl, Vdb)} of 639 {{_,_,Lhd}, {_,_,Ltl}} when Lhd =< I, Ltl =< I -> 640 %% Both head and tail are dead. No need to generate 641 %% any instruction. 642 {[], Bef}; 643 _ -> 644 %% At least one of head and tail will be used, 645 %% but we must always fetch both. We will call 646 %% clear_dead/2 to allow reuse of the register 647 %% in case only of them is used. 648 649 Reg0 = put_reg(Tl, put_reg(Hd, Bef#sr.reg)), 650 Int0 = Bef#sr{reg=Reg0}, 651 Rsrc = fetch_var(Src, Int0), 652 Rhd = fetch_reg(Hd, Reg0), 653 Rtl = fetch_reg(Tl, Reg0), 654 Int1 = clear_dead(Int0, I, Vdb), 655 {[{get_list,Rsrc,Rhd,Rtl}], Int1} 656 end, 657 {Es,Aft,St}. 658 659 660guard_clause_cg(#l{ke={guard_clause,G,B},vdb=Vdb}, Fail, Bef, St0) -> 661 {Gis,Int,St1} = guard_cg(G, Fail, Vdb, Bef, St0), 662 {Bis,Aft,St2} = match_cg(B, Fail, Int, St1), 663 {Gis ++ Bis,Aft,St2}. 664 665%% guard_cg(Guard, Fail, Vdb, StackReg, State) -> 666%% {[Ainstr],StackReg,State}. 667%% A guard is a boolean expression of tests. Tests return true or 668%% false. A fault in a test causes the test to return false. Tests 669%% never return the boolean, instead we generate jump code to go to 670%% the correct exit point. Primops and tests all go to the next 671%% instruction on success or jump to a failure label. 672 673guard_cg(#l{ke={protected,Ts,Rs},i=I,vdb=Pdb}, Fail, _Vdb, Bef, St) -> 674 protected_cg(Ts, Rs, Fail, I, Pdb, Bef, St); 675guard_cg(#l{ke={block,Ts},i=I,vdb=Bdb}, Fail, _Vdb, Bef, St) -> 676 guard_cg_list(Ts, Fail, I, Bdb, Bef, St); 677guard_cg(#l{ke={test,Test,As},i=I,vdb=_Tdb}, Fail, Vdb, Bef, St) -> 678 test_cg(Test, As, Fail, I, Vdb, Bef, St); 679guard_cg(G, _Fail, Vdb, Bef, St) -> 680 %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{G,Fail,Vdb,Bef}]), 681 {Gis,Aft,St1} = cg(G, Vdb, Bef, St), 682 %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{Aft}]), 683 {Gis,Aft,St1}. 684 685%% protected_cg([Kexpr], [Ret], Fail, I, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 686%% Do a protected. Protecteds without return values are just done 687%% for effect, the return value is not checked, success passes on to 688%% the next instruction and failure jumps to Fail. If there are 689%% return values then these must be set to 'false' on failure, 690%% control always passes to the next instruction. 691 692protected_cg(Ts, [], Fail, I, Vdb, Bef, St0) -> 693 %% Protect these calls, revert when done. 694 {Tis,Aft,St1} = guard_cg_list(Ts, Fail, I, Vdb, Bef, 695 St0#cg{btype=fail,bfail=Fail}), 696 {Tis,Aft,St1#cg{btype=St0#cg.btype,bfail=St0#cg.bfail}}; 697protected_cg(Ts, Rs, _Fail, I, Vdb, Bef, St0) -> 698 {Pfail,St1} = new_label(St0), 699 {Psucc,St2} = new_label(St1), 700 {Tis,Aft,St3} = guard_cg_list(Ts, Pfail, I, Vdb, Bef, 701 St2#cg{btype=fail,bfail=Pfail}), 702 %%ok = io:fwrite("cg ~w: ~p~n", [?LINE,{Rs,I,Vdb,Aft}]), 703 %% Set return values to false. 704 Mis = map(fun ({var,V}) -> {move,{atom,false},fetch_var(V, Aft)} end, Rs), 705 Live = {'%live',max_reg(Aft#sr.reg)}, 706 {Tis ++ [Live,{jump,{f,Psucc}}, 707 {label,Pfail}] ++ Mis ++ [Live,{label,Psucc}], 708 Aft,St3#cg{btype=St0#cg.btype,bfail=St0#cg.bfail}}. 709 710%% test_cg(TestName, Args, Fail, I, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 711%% Generate test instruction. Use explicit fail label here. 712 713test_cg(Test, As, Fail, I, Vdb, Bef, St) -> 714 case test_type(Test, length(As)) of 715 {cond_op,Op} -> 716 Ars = cg_reg_args(As, Bef), 717 Int = clear_dead(Bef, I, Vdb), 718 {[{test,Op,{f,Fail},Ars}], 719 clear_dead(Int, I, Vdb), 720 St}; 721 {rev_cond_op,Op} -> 722 [S1,S2] = cg_reg_args(As, Bef), 723 Int = clear_dead(Bef, I, Vdb), 724 {[{test,Op,{f,Fail},[S2,S1]}], 725 clear_dead(Int, I, Vdb), 726 St} 727 end. 728 729test_type(is_atom, 1) -> {cond_op,is_atom}; 730test_type(is_boolean, 1) -> {cond_op,is_boolean}; 731test_type(is_binary, 1) -> {cond_op,is_binary}; 732test_type(is_constant, 1) -> {cond_op,is_constant}; 733test_type(is_float, 1) -> {cond_op,is_float}; 734test_type(is_function, 1) -> {cond_op,is_function}; 735test_type(is_integer, 1) -> {cond_op,is_integer}; 736test_type(is_list, 1) -> {cond_op,is_list}; 737test_type(is_number, 1) -> {cond_op,is_number}; 738test_type(is_pid, 1) -> {cond_op,is_pid}; 739test_type(is_port, 1) -> {cond_op,is_port}; 740test_type(is_reference, 1) -> {cond_op,is_reference}; 741test_type(is_tuple, 1) -> {cond_op,is_tuple}; 742test_type('=<', 2) -> {rev_cond_op,is_ge}; 743test_type('>', 2) -> {rev_cond_op,is_lt}; 744test_type('<', 2) -> {cond_op,is_lt}; 745test_type('>=', 2) -> {cond_op,is_ge}; 746test_type('==', 2) -> {cond_op,is_eq}; 747test_type('/=', 2) -> {cond_op,is_ne}; 748test_type('=:=', 2) -> {cond_op,is_eq_exact}; 749test_type('=/=', 2) -> {cond_op,is_ne_exact}; 750test_type(internal_is_record, 3) -> {cond_op,internal_is_record}. 751 752%% guard_cg_list([Kexpr], Fail, I, Vdb, StackReg, St) -> 753%% {[Ainstr],StackReg,St}. 754 755guard_cg_list(Kes, Fail, I, Vdb, Bef, St0) -> 756 {Keis,{Aft,St1}} = 757 flatmapfoldl(fun (Ke, {Inta,Sta}) -> 758 {Keis,Intb,Stb} = 759 guard_cg(Ke, Fail, Vdb, Inta, Sta), 760 {comment(Inta) ++ Keis,{Intb,Stb}} 761 end, {Bef,St0}, need_heap(Kes, I)), 762 {Keis,Aft,St1}. 763 764%% match_fmf(Fun, LastFail, State, [Clause]) -> {Is,Aft,State}. 765%% This is a special flatmapfoldl for match code gen where we 766%% generate a "failure" label for each clause. The last clause uses 767%% an externally generated failure label, LastFail. N.B. We do not 768%% know or care how the failure labels are used. 769 770match_fmf(F, LastFail, St, [H]) -> 771 F(H, LastFail, St); 772match_fmf(F, LastFail, St0, [H|T]) -> 773 {Fail,St1} = new_label(St0), 774 {R,Aft1,St2} = F(H, Fail, St1), 775 {Rs,Aft2,St3} = match_fmf(F, LastFail, St2, T), 776 {R ++ [{label,Fail}] ++ Rs,sr_merge(Aft1, Aft2),St3}; 777match_fmf(_, _, St, []) -> {[],void,St}. 778 779%% call_cg(Func, [Arg], [Ret], Le, Vdb, StackReg, State) -> 780%% {[Ainstr],StackReg,State}. 781%% enter_cg(Func, [Arg], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 782%% Call and enter first put the arguments into registers and save any 783%% other registers, then clean up and compress the stack and set the 784%% frame size. Finally the actual call is made. Call then needs the 785%% return values filled in. 786 787call_cg({var,V}, As, Rs, Le, Vdb, Bef, St0) -> 788 {Sis,Int} = cg_setup_call(As++[{var,V}], Bef, Le#l.i, Vdb), 789 %% Put return values in registers. 790 Reg = load_vars(Rs, clear_regs(Int#sr.reg)), 791 %% Build complete code and final stack/register state. 792 Arity = length(As), 793 {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)), 794 {comment({call_fun,{var,V},As}) ++ Sis ++ Frees ++ [{call_fun,Arity}], 795 Aft,need_stack_frame(St0)}; 796call_cg({remote,Mod,Name}, As, Rs, Le, Vdb, Bef, St0) 797 when element(1, Mod) == var; 798 element(1, Name) == var -> 799 {Sis,Int} = cg_setup_call(As++[Mod,Name], Bef, Le#l.i, Vdb), 800 %% Put return values in registers. 801 Reg = load_vars(Rs, clear_regs(Int#sr.reg)), 802 %% Build complete code and final stack/register state. 803 Arity = length(As), 804 Call = {apply,Arity}, 805 St = need_stack_frame(St0), 806 %%{Call,St1} = build_call(Func, Arity, St0), 807 {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)), 808 {Sis ++ Frees ++ [Call],Aft,St}; 809call_cg(Func, As, Rs, Le, Vdb, Bef, St0) -> 810 {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb), 811 %% Put return values in registers. 812 Reg = load_vars(Rs, clear_regs(Int#sr.reg)), 813 %% Build complete code and final stack/register state. 814 Arity = length(As), 815 {Call,St1} = build_call(Func, Arity, St0), 816 {Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)), 817 {comment({call,Func,As}) ++ Sis ++ Frees ++ Call,Aft,St1}. 818 819build_call({remote,{atom,erlang},{atom,'!'}}, 2, St0) -> 820 {[send],need_stack_frame(St0)}; 821build_call({remote,{atom,Mod},{atom,Name}}, Arity, St0) -> 822 {[{call_ext,Arity,{extfunc,Mod,Name,Arity}}],need_stack_frame(St0)}; 823build_call(Name, Arity, St0) when atom(Name) -> 824 {Lbl,St1} = local_func_label(Name, Arity, need_stack_frame(St0)), 825 {[{call,Arity,{f,Lbl}}],St1}. 826 827free_dead(#sr{stk=Stk0}=Aft) -> 828 {Instr,Stk} = free_dead(Stk0, 0, [], []), 829 {Instr,Aft#sr{stk=Stk}}. 830 831free_dead([dead|Stk], Y, Instr, StkAcc) -> 832 %% Note: kill/1 is equivalent to init/1 (translated by beam_asm). 833 %% We use kill/1 to help further optimisation passes. 834 free_dead(Stk, Y+1, [{kill,{yy,Y}}|Instr], [free|StkAcc]); 835free_dead([Any|Stk], Y, Instr, StkAcc) -> 836 free_dead(Stk, Y+1, Instr, [Any|StkAcc]); 837free_dead([], _, Instr, StkAcc) -> {Instr,reverse(StkAcc)}. 838 839enter_cg({var,V}, As, Le, Vdb, Bef, St0) -> 840 {Sis,Int} = cg_setup_call(As++[{var,V}], Bef, Le#l.i, Vdb), 841 %% Build complete code and final stack/register state. 842 Arity = length(As), 843 {comment({call_fun,{var,V},As}) ++ Sis ++ [{call_fun,Arity},return], 844 clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb), 845 need_stack_frame(St0)}; 846enter_cg({remote,Mod,Name}=Func, As, Le, Vdb, Bef, St0) 847 when element(1, Mod) == var; 848 element(1, Name) == var -> 849 {Sis,Int} = cg_setup_call(As++[Mod,Name], Bef, Le#l.i, Vdb), 850 %% Build complete code and final stack/register state. 851 Arity = length(As), 852 Call = {apply_only,Arity}, 853 St = need_stack_frame(St0), 854 {comment({enter,Func,As}) ++ Sis ++ [Call], 855 clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb), 856 St}; 857enter_cg(Func, As, Le, Vdb, Bef, St0) -> 858 {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb), 859 %% Build complete code and final stack/register state. 860 Arity = length(As), 861 {Call,St1} = build_enter(Func, Arity, St0), 862 {comment({enter,Func,As}) ++ Sis ++ Call, 863 clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb), 864 St1}. 865 866build_enter({remote,{atom,erlang},{atom,'!'}}, 2, St0) -> 867 {[send,return],need_stack_frame(St0)}; 868build_enter({remote,{atom,Mod},{atom,Name}}, Arity, St0) -> 869 St1 = case trap_bif(Mod, Name, Arity) of 870 true -> need_stack_frame(St0); 871 false -> St0 872 end, 873 {[{call_ext_only,Arity,{extfunc,Mod,Name,Arity}}],St1}; 874build_enter(Name, Arity, St0) when is_atom(Name) -> 875 {Lbl,St1} = local_func_label(Name, Arity, St0), 876 {[{call_only,Arity,{f,Lbl}}],St1}. 877 878%% local_func_label(Name, Arity, State) -> {Label,State'} 879%% Get the function entry label for a local function. 880 881local_func_label(Name, Arity, St0) -> 882 Key = {Name,Arity}, 883 case keysearch(Key, 1, St0#cg.functable) of 884 {value,{Key,Label}} -> 885 {Label,St0}; 886 false -> 887 {Label,St1} = new_label(St0), 888 {Label,St1#cg{functable=[{Key,Label}|St1#cg.functable]}} 889 end. 890 891%% need_stack_frame(State) -> State' 892%% Make a note in the state that this function will need a stack frame. 893 894need_stack_frame(#cg{need_frame=true}=St) -> St; 895need_stack_frame(St) -> St#cg{need_frame=true}. 896 897%% trap_bif(Mod, Name, Arity) -> true|false 898%% Trap bifs that need a stack frame. 899 900trap_bif(erlang, '!', 2) -> true; 901trap_bif(erlang, link, 1) -> true; 902trap_bif(erlang, unlink, 1) -> true; 903trap_bif(erlang, monitor_node, 2) -> true; 904trap_bif(erlang, group_leader, 2) -> true; 905trap_bif(erlang, exit, 2) -> true; 906trap_bif(_, _, _) -> false. 907 908%% bif_cg(Bif, [Arg], [Ret], Le, Vdb, StackReg, State) -> 909%% {[Ainstr],StackReg,State}. 910 911bif_cg(dsetelement, [Index0,Tuple0,New0], _Rs, Le, Vdb, Bef, St0) -> 912 [New,Tuple,{integer,Index1}] = cg_reg_args([New0,Tuple0,Index0], Bef), 913 Index = Index1-1, 914 {[{set_tuple_element,New,Tuple,Index}], 915 clear_dead(Bef, Le#l.i, Vdb), St0}; 916bif_cg({make_fun,Func,Arity,Index,Uniq}, As, Rs, Le, Vdb, Bef, St0) -> 917 %% This behaves more like a function call. 918 {Sis,Int} = cg_setup_call(As, Bef, Le#l.i, Vdb), 919 Reg = load_vars(Rs, clear_regs(Int#sr.reg)), 920 {FuncLbl,St1} = local_func_label(Func, Arity, St0), 921 MakeFun = case St0#cg.new_funs of 922 true -> {make_fun2,{f,FuncLbl},Index,Uniq,length(As)}; 923 false -> {make_fun,{f,FuncLbl},Uniq,length(As)} 924 end, 925 {comment({make_fun,{Func,Arity,Uniq},As}) ++ Sis ++ 926 [MakeFun], 927 clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb), 928 St1}; 929bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) -> 930 Ars = cg_reg_args(As, Bef), 931 932 %% If we are inside a catch, we must save everything that will 933 %% be alive after the catch (because the BIF might fail and there 934 %% will be a jump to the code after the catch). 935 %% Currently, we are somewhat pessimistic in 936 %% that we save any variable that will be live after this BIF call. 937 938 {Sis,Int0} = 939 case St0#cg.in_catch of 940 true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb); 941 false -> {[],Bef} 942 end, 943 944 Int1 = clear_dead(Int0, Le#l.i, Vdb), 945 Reg = put_reg(V, Int1#sr.reg), 946 Int = Int1#sr{reg=Reg}, 947 Dst = fetch_reg(V, Reg), 948 {Sis ++ [{bif,Bif,bif_fail(St0#cg.btype, St0#cg.bfail, length(Ars)),Ars,Dst}], 949 clear_dead(Int, Le#l.i, Vdb), St0}. 950 951bif_fail(_, _, 0) -> nofail; 952bif_fail(exit, _, _) -> {f,0}; 953bif_fail(fail, Fail, _) -> {f,Fail}. 954 955%% recv_loop_cg(TimeOut, ReceiveVar, ReceiveMatch, TimeOutExprs, 956%% [Ret], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 957 958recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St0) -> 959 {Sis,Int0} = adjust_stack(Bef, Le#l.i, Le#l.i, Vdb), 960 Int1 = Int0#sr{reg=clear_regs(Int0#sr.reg)}, 961 %% Get labels. 962 {Rl,St1} = new_label(St0), 963 {Tl,St2} = new_label(St1), 964 {Bl,St3} = new_label(St2), 965 St4 = St3#cg{break=Bl,recv=Rl}, %Set correct receive labels 966 {Ris,Raft,St5} = cg_recv_mesg(Rvar, Rm, Tl, Int1, St4), 967 {Wis,Taft,St6} = cg_recv_wait(Te, Tes, Le#l.i, Int1, St5), 968 Int2 = sr_merge(Raft, Taft), %Merge stack/registers 969 Reg = load_vars(Rs, Int2#sr.reg), 970 {Sis ++ Ris ++ [{label,Tl}] ++ Wis ++ [{label,Bl}], 971 clear_dead(Int2#sr{reg=Reg}, Le#l.i, Vdb), 972 St6#cg{break=St0#cg.break,recv=St0#cg.recv}}. 973 974%% cg_recv_mesg( ) -> {[Ainstr],Aft,St}. 975 976cg_recv_mesg({var,R}, Rm, Tl, Bef, St0) -> 977 Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)}, 978 Ret = fetch_reg(R, Int0#sr.reg), 979 %% Int1 = clear_dead(Int0, I, Rm#l.vdb), 980 Int1 = Int0, 981 {Mis,Int2,St1} = match_cg(Rm, none, Int1, St0), 982 {[{'%live',0},{label,St1#cg.recv},{loop_rec,{f,Tl},Ret}|Mis],Int2,St1}. 983 984%% cg_recv_wait(Te, Tes, I, Vdb, Int2, St3) -> {[Ainstr],Aft,St}. 985 986cg_recv_wait({atom,infinity}, Tes, I, Bef, St0) -> 987 %% We know that the 'after' body will never be executed. 988 %% But to keep the stack and register information up to date, 989 %% we will generate the code for the 'after' body, and then discard it. 990 Int1 = clear_dead(Bef, I, Tes#l.vdb), 991 {_,Int2,St1} = cg_block(Tes#l.ke, Tes#l.i, Tes#l.vdb, 992 Int1#sr{reg=clear_regs(Int1#sr.reg)}, St0), 993 {[{wait,{f,St1#cg.recv}}],Int2,St1}; 994cg_recv_wait({integer,0}, Tes, _I, Bef, St0) -> 995 {Tis,Int,St1} = cg_block(Tes#l.ke, Tes#l.i, Tes#l.vdb, Bef, St0), 996 {[timeout|Tis],Int,St1}; 997cg_recv_wait(Te, Tes, I, Bef, St0) -> 998 Reg = cg_reg_arg(Te, Bef), 999 %% Must have empty registers here! Bug if anything in registers. 1000 Int0 = clear_dead(Bef, I, Tes#l.vdb), 1001 {Tis,Int,St1} = cg_block(Tes#l.ke, Tes#l.i, Tes#l.vdb, 1002 Int0#sr{reg=clear_regs(Int0#sr.reg)}, St0), 1003 {[{wait_timeout,{f,St1#cg.recv},Reg},timeout] ++ Tis,Int,St1}. 1004 1005%% recv_next_cg(Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}. 1006%% Use adjust stack to clear stack, but only need it for Aft. 1007 1008recv_next_cg(Le, Vdb, Bef, St) -> 1009 {Sis,Aft} = adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb), 1010 {[{loop_rec_end,{f,St#cg.recv}}] ++ Sis,Aft,St}. %Joke 1011 1012%% try_cg(TryBlock, [BodyVar], TryBody, [ExcpVar], TryHandler, [Ret], 1013%% Le, Vdb, StackReg, St) -> {[Ainstr],StackReg,St}. 1014 1015try_cg(Ta, Vs, Tb, Evs, Th, Rs, Le, Vdb, Bef, St0) -> 1016 {B,St1} = new_label(St0), %Body label 1017 {H,St2} = new_label(St1), %Handler label 1018 {E,St3} = new_label(St2), %End label 1019 TryTag = Ta#l.i, 1020 Int1 = Bef#sr{stk=put_catch(TryTag, Bef#sr.stk)}, 1021 TryReg = fetch_stack({catch_tag,TryTag}, Int1#sr.stk), 1022 {Ais,Int2,St4} = cg(Ta, Vdb, Int1, St3#cg{break=B,in_catch=true}), 1023 Int3 = Int2#sr{stk=drop_catch(TryTag, Int2#sr.stk)}, 1024 St5 = St4#cg{break=E,in_catch=St3#cg.in_catch}, 1025 {Bis,Baft,St6} = cg(Tb, Vdb, Int3#sr{reg=load_vars(Vs, Int3#sr.reg)}, St5), 1026 {His,Haft,St7} = cg(Th, Vdb, Int3#sr{reg=load_vars(Evs, Int3#sr.reg)}, St6), 1027 Int4 = sr_merge(Baft, Haft), %Merge stack/registers 1028 Aft = Int4#sr{reg=load_vars(Rs, Int4#sr.reg)}, 1029 {[{'try',TryReg,{f,H}}] ++ Ais ++ 1030 [{label,B},{try_end,TryReg}] ++ Bis ++ 1031 [{label,H},{try_case,TryReg}] ++ His ++ 1032 [{label,E}], 1033 clear_dead(Aft, Le#l.i, Vdb), 1034 St7#cg{break=St0#cg.break}}. 1035 1036%% catch_cg(CatchBlock, Ret, Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 1037 1038catch_cg(C, {var,R}, Le, Vdb, Bef, St0) -> 1039 {B,St1} = new_label(St0), 1040 CatchTag = Le#l.i, 1041 Int1 = Bef#sr{stk=put_catch(CatchTag, Bef#sr.stk)}, 1042 CatchReg = fetch_stack({catch_tag,CatchTag}, Int1#sr.stk), 1043 {Cis,Int2,St2} = cg_block(C, Le#l.i, Le#l.vdb, Int1, 1044 St1#cg{break=B,in_catch=true}), 1045 Aft = Int2#sr{reg=load_reg(R, 0, Int2#sr.reg), 1046 stk=drop_catch(CatchTag, Int2#sr.stk)}, 1047 {[{'catch',CatchReg,{f,B}}] ++ Cis ++ 1048 [{label,B},{catch_end,CatchReg}], 1049 clear_dead(Aft, Le#l.i, Vdb), 1050 St2#cg{break=St1#cg.break,in_catch=St1#cg.in_catch}}. 1051 1052%% set_cg([Var], Constr, Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 1053%% We have to be careful how a 'set' works. First the structure is 1054%% built, then it is filled and finally things can be cleared. The 1055%% annotation must reflect this and make sure that the return 1056%% variable is allocated first. 1057%% 1058%% put_list for constructing a cons is an atomic instruction 1059%% which can safely resuse one of the source registers as target. 1060%% Also binaries can reuse a source register as target. 1061 1062set_cg([{var,R}], {cons,Es}, Le, Vdb, Bef, St) -> 1063 [S1,S2] = map(fun ({var,V}) -> fetch_var(V, Bef); 1064 (Other) -> Other 1065 end, Es), 1066 Int0 = clear_dead(Bef, Le#l.i, Vdb), 1067 Int1 = Int0#sr{reg=put_reg(R, Int0#sr.reg)}, 1068 Ret = fetch_reg(R, Int1#sr.reg), 1069 {[{put_list,S1,S2,Ret}], Int1, St}; 1070set_cg([{var,R}], {old_binary,Segs}, Le, Vdb, Bef, St) -> 1071 Fail = bif_fail(St#cg.btype, St#cg.bfail, 42), 1072 PutCode = cg_bin_put(Segs, Fail, Bef), 1073 Code = cg_binary_old(PutCode), 1074 Int0 = clear_dead(Bef, Le#l.i, Vdb), 1075 Aft = Int0#sr{reg=put_reg(R, Int0#sr.reg)}, 1076 Ret = fetch_reg(R, Aft#sr.reg), 1077 {Code ++ [{bs_final,Fail,Ret}],Aft,St}; 1078set_cg([{var,R}], {binary,Segs}, Le, Vdb, Bef, #cg{in_catch=InCatch}=St) -> 1079 Int0 = Bef#sr{reg=put_reg(R, Bef#sr.reg)}, 1080 Target = fetch_reg(R, Int0#sr.reg), 1081 Fail = bif_fail(St#cg.btype, St#cg.bfail, 42), 1082 Temp = find_scratch_reg(Int0#sr.reg), 1083 PutCode = cg_bin_put(Segs, Fail, Bef), 1084 {Sis,Int1} = 1085 case InCatch of 1086 true -> adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb); 1087 false -> {[],Int0} 1088 end, 1089 Aft = clear_dead(Int1, Le#l.i, Vdb), 1090 Code = cg_binary(PutCode, Target, Temp, Fail, Aft), 1091 {Sis++Code,Aft,St}; 1092set_cg([{var,R}], Con, Le, Vdb, Bef, St) -> 1093 %% Find a place for the return register first. 1094 Int = Bef#sr{reg=put_reg(R, Bef#sr.reg)}, 1095 Ret = fetch_reg(R, Int#sr.reg), 1096 Ais = case Con of 1097 {tuple,Es} -> 1098 [{put_tuple,length(Es),Ret}] ++ cg_build_args(Es, Bef); 1099 {var,V} -> % Normally removed by kernel optimizer. 1100 [{move,fetch_var(V, Int),Ret}]; 1101 {string,Str} -> 1102 [{put_string,length(Str),{string,Str},Ret}]; 1103 Other -> 1104 [{move,Other,Ret}] 1105 end, 1106 {Ais,clear_dead(Int, Le#l.i, Vdb),St}; 1107set_cg([], {binary,Segs}, Le, Vdb, Bef, St) -> 1108 Fail = bif_fail(St#cg.btype, St#cg.bfail, 42), 1109 Target = find_scratch_reg(Bef#sr.reg), 1110 Temp = find_scratch_reg(put_reg(Target, Bef#sr.reg)), 1111 PutCode = cg_bin_put(Segs, Fail, Bef), 1112 Code = cg_binary(PutCode, Target, Temp, Fail, Bef), 1113 Aft = clear_dead(Bef, Le#l.i, Vdb), 1114 {Code,Aft,St}; 1115set_cg([], {old_binary,Segs}, Le, Vdb, Bef, St) -> 1116 Fail = bif_fail(St#cg.btype, St#cg.bfail, 42), 1117 PutCode = cg_bin_put(Segs, Fail, Bef), 1118 Ais0 = cg_binary_old(PutCode), 1119 Ret = find_scratch_reg(Bef#sr.reg), 1120 Ais = Ais0 ++ [{bs_final,Fail,Ret}], 1121 {Ais,clear_dead(Bef, Le#l.i, Vdb),St}; 1122set_cg([], _, Le, Vdb, Bef, St) -> 1123 %% This should have been stripped by compiler, just cleanup. 1124 {[],clear_dead(Bef, Le#l.i, Vdb), St}. 1125 1126 1127%%% 1128%%% Code generation for constructing binaries. 1129%%% 1130 1131cg_binary(PutCode, Target, Temp, Fail, Bef) -> 1132 SzCode = cg_binary_size(PutCode, Target, Temp, Fail), 1133 MaxRegs = max_reg(Bef#sr.reg), 1134 Code = SzCode ++ [{bs_init2,Fail,Target,MaxRegs,{field_flags,[]},Target}|PutCode], 1135 cg_bin_opt(Code). 1136 1137cg_binary_size(PutCode, Target, Temp, Fail) -> 1138 Szs = cg_binary_size_1(PutCode, 0, []), 1139 cg_binary_size_expr(Szs, Target, Temp, Fail). 1140 1141cg_binary_size_1([{_Put,_Fail,S,U,_Flags,Src}|T], Bits, Acc) -> 1142 cg_binary_size_2(S, U, Src, T, Bits, Acc); 1143cg_binary_size_1([], Bits, Acc) -> 1144 Bytes = Bits div 8, 1145 RemBits = Bits rem 8, 1146 Res = sort([{1,{integer,RemBits}},{8,{integer,Bytes}}|Acc]), 1147 cg_binary_size_3(Res). 1148 1149cg_binary_size_2({integer,N}, U, _, Next, Bits, Acc) -> 1150 cg_binary_size_1(Next, Bits+N*U, Acc); 1151cg_binary_size_2({atom,all}, 8, E, Next, Bits, Acc) -> 1152 cg_binary_size_1(Next, Bits, [{8,{size,E}}|Acc]); 1153cg_binary_size_2(Reg, 1, _, Next, Bits, Acc) -> 1154 cg_binary_size_1(Next, Bits, [{1,Reg}|Acc]); 1155cg_binary_size_2(Reg, 8, _, Next, Bits, Acc) -> 1156 cg_binary_size_1(Next, Bits, [{8,Reg}|Acc]); 1157cg_binary_size_2(Reg, U, _, Next, Bits, Acc) -> 1158 cg_binary_size_1(Next, Bits, [{1,{'*',Reg,U}}|Acc]). 1159 1160cg_binary_size_3([{_,{integer,0}}|T]) -> 1161 cg_binary_size_3(T); 1162cg_binary_size_3([{U,S1},{U,S2}|T]) -> 1163 {L0,Rest} = cg_binary_size_4(T, U, []), 1164 L = [S1,S2|L0], 1165 [{U,L}|cg_binary_size_3(Rest)]; 1166cg_binary_size_3([{U,S}|T]) -> 1167 [{U,[S]}|cg_binary_size_3(T)]; 1168cg_binary_size_3([]) -> []. 1169 1170cg_binary_size_4([{U,S}|T], U, Acc) -> 1171 cg_binary_size_4(T, U, [S|Acc]); 1172cg_binary_size_4(T, _, Acc) -> 1173 {Acc,T}. 1174 1175%% cg_binary_size_expr/4 1176%% Generate code for calculating the resulting size of a binary. 1177cg_binary_size_expr(Sizes, Target, Temp, Fail) -> 1178 cg_binary_size_expr_1(Sizes, Target, Temp, Fail, 1179 [{move,{integer,0},Target}]). 1180 1181cg_binary_size_expr_1([{1,E0}|T], Target, Temp, Fail, Acc) -> 1182 E1 = cg_gen_binsize(E0, Target, Temp, Fail, Acc), 1183 E = [{bs_bits_to_bytes,Fail,Target,Target}|E1], 1184 cg_binary_size_expr_1(T, Target, Temp, Fail, E); 1185cg_binary_size_expr_1([{8,E0}], Target, Temp, Fail, Acc) -> 1186 E = cg_gen_binsize(E0, Target, Temp, Fail, Acc), 1187 reverse(E); 1188cg_binary_size_expr_1([], _, _, _, Acc) -> reverse(Acc). 1189 1190cg_gen_binsize([{'*',A,B}|T], Target, Temp, Fail, Acc) -> 1191 cg_gen_binsize(T, Target, Temp, Fail, 1192 [{bs_add,Fail,[Target,A,B],Target}|Acc]); 1193cg_gen_binsize([{size,B}|T], Target, Temp, Fail, Acc) -> 1194 cg_gen_binsize([Temp|T], Target, Temp, Fail, 1195 [{bif,size,Fail,[B],Temp}|Acc]); 1196cg_gen_binsize([E0|T], Target, Temp, Fail, Acc) -> 1197 cg_gen_binsize(T, Target, Temp, Fail, 1198 [{bs_add,Fail,[Target,E0,1],Target}|Acc]); 1199cg_gen_binsize([], _, _, _, Acc) -> Acc. 1200 1201%% cg_bin_opt(Code0) -> Code 1202%% Optimize the size calculations for binary construction. 1203 1204cg_bin_opt([{move,{integer,0},D},{bs_add,_,[D,{integer,_}=S,1],Dst}|Is]) -> 1205 cg_bin_opt([{move,S,Dst}|Is]); 1206cg_bin_opt([{move,{integer,0},D},{bs_add,Fail,[D,S,U],Dst}|Is]) -> 1207 cg_bin_opt([{bs_add,Fail,[{integer,0},S,U],Dst}|Is]); 1208cg_bin_opt([{move,{integer,Bytes},D},{bs_init2,Fail,D,Regs0,Flags,D}|Is]) -> 1209 Regs = cg_bo_newregs(Regs0, D), 1210 cg_bin_opt([{bs_init2,Fail,Bytes,Regs,Flags,D}|Is]); 1211cg_bin_opt([{move,Src,D},{bs_init2,Fail,D,Regs0,Flags,D}|Is]) -> 1212 Regs = cg_bo_newregs(Regs0, D), 1213 cg_bin_opt([{bs_init2,Fail,Src,Regs,Flags,D}|Is]); 1214cg_bin_opt([{move,Src,Dst},{bs_bits_to_bytes,Fail,Dst,Dst}|Is]) -> 1215 cg_bin_opt([{bs_bits_to_bytes,Fail,Src,Dst}|Is]); 1216cg_bin_opt([{move,Src1,Dst},{bs_add,Fail,[Dst,Src2,U],Dst}|Is]) -> 1217 cg_bin_opt([{bs_add,Fail,[Src1,Src2,U],Dst}|Is]); 1218cg_bin_opt([{bs_bits_to_bytes,Fail,{integer,N},_}|Is0]) when N rem 8 =/= 0 -> 1219 case Fail of 1220 {f,0} -> 1221 Is = [{move,{atom,badarg},{x,0}}, 1222 {call_ext_only,1,{extfunc,erlang,error,1}}|Is0], 1223 cg_bin_opt(Is); 1224 _ -> 1225 cg_bin_opt([{jump,Fail}|Is0]) 1226 end; 1227cg_bin_opt([I|Is]) -> 1228 [I|cg_bin_opt(Is)]; 1229cg_bin_opt([]) -> []. 1230 1231cg_bo_newregs(R, {x,X}) when R-1 =:= X -> R-1; 1232cg_bo_newregs(R, _) -> R. 1233 1234%% Common for new and old binary code generation. 1235 1236cg_bin_put({bin_seg,S0,U,T,Fs,[E0,Next]}, Fail, Bef) -> 1237 S1 = case S0 of 1238 {var,Sv} -> fetch_var(Sv, Bef); 1239 _ -> S0 1240 end, 1241 E1 = case E0 of 1242 {var,V} -> fetch_var(V, Bef); 1243 Other -> Other 1244 end, 1245 Op = case T of 1246 integer -> bs_put_integer; 1247 binary -> bs_put_binary; 1248 float -> bs_put_float 1249 end, 1250 [{Op,Fail,S1,U,{field_flags,Fs},E1}|cg_bin_put(Next, Fail, Bef)]; 1251cg_bin_put(bin_end, _, _) -> []. 1252 1253%% Old style. 1254 1255cg_binary_old(PutCode) -> 1256 [cg_bs_init(PutCode)] ++ need_bin_buf(PutCode). 1257 1258cg_bs_init(Code) -> 1259 {Size,Fs} = foldl(fun ({_,_,{integer,N},U,_,_}, {S,Fs}) -> 1260 {S + N*U,Fs}; 1261 (_, {S,_}) -> 1262 {S,[]} 1263 end, {0,[exact]}, Code), 1264 {bs_init,(Size+7) div 8,{field_flags,Fs}}. 1265 1266need_bin_buf(Code0) -> 1267 {Code1,F,H} = foldr(fun ({_,_,{integer,N},U,_,_}=Bs, {Code,F,H}) -> 1268 {[Bs|Code],F,H + N*U}; 1269 ({_,_,_,_,_,_}=Bs, {Code,F,H}) -> 1270 {[Bs|need_bin_buf_need(H, F, Code)],true,0} 1271 end, {[],false,0}, Code0), 1272 need_bin_buf_need(H, F, Code1). 1273 1274need_bin_buf_need(0, false, Rest) -> Rest; 1275need_bin_buf_need(H, _, Rest) -> [{bs_need_buf,H}|Rest]. 1276 1277cg_build_args(As, Bef) -> 1278 map(fun ({var,V}) -> {put,fetch_var(V, Bef)}; 1279 (Other) -> {put,Other} 1280 end, As). 1281 1282%% return_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 1283%% break_cg([Val], Le, Vdb, Bef, St) -> {[Ainstr],Aft,St}. 1284%% These are very simple, just put return/break values in registers 1285%% from 0, then return/break. Use the call setup to clean up stack, 1286%% but must clear registers to ensure sr_merge works correctly. 1287 1288return_cg(Rs, Le, Vdb, Bef, St) -> 1289 {Ms,Int} = cg_setup_call(Rs, Bef, Le#l.i, Vdb), 1290 {comment({return,Rs}) ++ Ms ++ [return], 1291 Int#sr{reg=clear_regs(Int#sr.reg)},St}. 1292 1293break_cg(Bs, Le, Vdb, Bef, St) -> 1294 {Ms,Int} = cg_setup_call(Bs, Bef, Le#l.i, Vdb), 1295 {comment({break,Bs}) ++ Ms ++ [{jump,{f,St#cg.break}}], 1296 Int#sr{reg=clear_regs(Int#sr.reg)},St}. 1297 1298%% cg_reg_arg(Arg0, Info) -> Arg 1299%% cg_reg_args([Arg0], Info) -> [Arg] 1300%% Convert argument[s] into registers. Literal values are returned unchanged. 1301 1302cg_reg_args(As, Bef) -> [cg_reg_arg(A, Bef) || A <- As]. 1303 1304cg_reg_arg({var,V}, Bef) -> fetch_var(V, Bef); 1305cg_reg_arg(Literal, _) -> Literal. 1306 1307%% cg_setup_call([Arg], Bef, Cur, Vdb) -> {[Instr],Aft}. 1308%% Do the complete setup for a call/enter. 1309 1310cg_setup_call(As, Bef, I, Vdb) -> 1311 {Ms,Int0} = cg_call_args(As, Bef, I, Vdb), 1312 %% Have set up arguments, can now clean up, compress and save to stack. 1313 Int1 = Int0#sr{stk=clear_dead_stk(Int0#sr.stk, I, Vdb),res=[]}, 1314 {Sis,Int2} = adjust_stack(Int1, I, I+1, Vdb), 1315 {Ms ++ Sis ++ [{'%live',length(As)}],Int2}. 1316 1317%% cg_call_args([Arg], SrState) -> {[Instr],SrState}. 1318%% Setup the arguments to a call/enter/bif. Put the arguments into 1319%% consecutive registers starting at {x,0} moving any data which 1320%% needs to be saved. Return a modified SrState structure with the 1321%% new register contents. N.B. the resultant register info will 1322%% contain non-variable values when there are non-variable values. 1323%% 1324%% This routine is complicated by unsaved values in x registers. 1325%% We'll move away any unsaved values that are in the registers 1326%% to be overwritten by the arguments. 1327 1328cg_call_args(As, Bef, I, Vdb) -> 1329 Regs0 = load_arg_regs(Bef#sr.reg, As), 1330 Unsaved = unsaved_registers(Regs0, Bef#sr.stk, I, I+1, Vdb), 1331 {UnsavedMoves,Regs} = move_unsaved(Unsaved, Bef#sr.reg, Regs0), 1332 Moves0 = gen_moves(As, Bef), 1333 Moves = order_moves(Moves0, find_scratch_reg(Regs)), 1334 {UnsavedMoves ++ Moves,Bef#sr{reg=Regs}}. 1335 1336%% load_arg_regs([Reg], Arguments) -> [Reg] 1337%% Update the register descriptor to include the arguments (from {x,0} 1338%% and upwards). Values in argument register are overwritten. 1339%% Values in x registers above the arguments are preserved. 1340 1341load_arg_regs(Regs, As) -> load_arg_regs(Regs, As, 0). 1342 1343load_arg_regs([_|Rs], [{var,V}|As], I) -> [{I,V}|load_arg_regs(Rs, As, I+1)]; 1344load_arg_regs([_|Rs], [A|As], I) -> [{I,A}|load_arg_regs(Rs, As, I+1)]; 1345load_arg_regs([], [{var,V}|As], I) -> [{I,V}|load_arg_regs([], As, I+1)]; 1346load_arg_regs([], [A|As], I) -> [{I,A}|load_arg_regs([], As, I+1)]; 1347load_arg_regs(Rs, [], _) -> Rs. 1348 1349%% Returns the variables must be saved and are currently in the 1350%% x registers that are about to be overwritten by the arguments. 1351 1352unsaved_registers(Regs, Stk, Fb, Lf, Vdb) -> 1353 [V || {V,F,L} <- Vdb, 1354 F < Fb, 1355 L >= Lf, 1356 not on_stack(V, Stk), 1357 not in_reg(V, Regs)]. 1358 1359in_reg(V, Regs) -> keymember(V, 2, Regs). 1360 1361%% Move away unsaved variables from the registers that are to be 1362%% overwritten by the arguments. 1363move_unsaved(Vs, OrigRegs, NewRegs) -> 1364 move_unsaved(Vs, OrigRegs, NewRegs, []). 1365 1366move_unsaved([V|Vs], OrigRegs, NewRegs0, Acc) -> 1367 NewRegs = put_reg(V, NewRegs0), 1368 Src = fetch_reg(V, OrigRegs), 1369 Dst = fetch_reg(V, NewRegs), 1370 move_unsaved(Vs, OrigRegs, NewRegs, [{move,Src,Dst}|Acc]); 1371move_unsaved([], _, Regs, Acc) -> {Acc,Regs}. 1372 1373%% gen_moves(As, Sr) 1374%% Generate the basic move instruction to move the arguments 1375%% to their proper registers. The list will be sorted on 1376%% destinations. (I.e. the move to {x,0} will be first -- 1377%% see the comment to order_moves/2.) 1378 1379gen_moves(As, Sr) -> gen_moves(As, Sr, 0, []). 1380 1381gen_moves([{var,V}|As], Sr, I, Acc) -> 1382 case fetch_var(V, Sr) of 1383 {x,I} -> gen_moves(As, Sr, I+1, Acc); 1384 Reg -> gen_moves(As, Sr, I+1, [{move,Reg,{x,I}}|Acc]) 1385 end; 1386gen_moves([A|As], Sr, I, Acc) -> 1387 gen_moves(As, Sr, I+1, [{move,A,{x,I}}|Acc]); 1388gen_moves([], _, _, Acc) -> lists:keysort(3, Acc). 1389 1390%% order_moves([Move], ScratchReg) -> [Move] 1391%% Orders move instruction so that source registers are not 1392%% destroyed before they are used. If there are cycles 1393%% (such as {move,{x,0},{x,1}}, {move,{x,1},{x,1}}), 1394%% the scratch register is used to break up the cycle. 1395%% If possible, the first move of the input list is placed 1396%% last in the result list (to make the move to {x,0} occur 1397%% just before the call to allow the Beam loader to coalesce 1398%% the instructions). 1399 1400order_moves(Ms, Scr) -> order_moves(Ms, Scr, []). 1401 1402order_moves([{move,_,_}=M|Ms0], ScrReg, Acc0) -> 1403 {Chain,Ms} = collect_chain(Ms0, [M], ScrReg), 1404 Acc = reverse(Chain, Acc0), 1405 order_moves(Ms, ScrReg, Acc); 1406order_moves([], _, Acc) -> Acc. 1407 1408collect_chain(Ms, Path, ScrReg) -> 1409 collect_chain(Ms, Path, [], ScrReg). 1410 1411collect_chain([{move,Src,Same}=M|Ms0], [{move,Same,_}|_]=Path, Others, ScrReg) -> 1412 case keysearch(Src, 3, Path) of 1413 {value,_} -> %We have a cycle. 1414 {break_up_cycle(M, Path, ScrReg),reverse(Others, Ms0)}; 1415 false -> 1416 collect_chain(reverse(Others, Ms0), [M|Path], [], ScrReg) 1417 end; 1418collect_chain([M|Ms], Path, Others, ScrReg) -> 1419 collect_chain(Ms, Path, [M|Others], ScrReg); 1420collect_chain([], Path, Others, _) -> 1421 {Path,Others}. 1422 1423break_up_cycle({move,Src,_}=M, Path, ScrReg) -> 1424 [{move,ScrReg,Src},M|break_up_cycle1(Src, Path, ScrReg)]. 1425 1426break_up_cycle1(Dst, [{move,Src,Dst}|Path], ScrReg) -> 1427 [{move,Src,ScrReg}|Path]; 1428break_up_cycle1(Dst, [M|Path], LastMove) -> 1429 [M|break_up_cycle1(Dst, Path, LastMove)]. 1430 1431%% clear_dead(Sr, Until, Vdb) -> Aft. 1432%% Remove all variables in Sr which have died AT ALL so far. 1433 1434clear_dead(Sr, Until, Vdb) -> 1435 Sr#sr{reg=clear_dead_reg(Sr, Until, Vdb), 1436 stk=clear_dead_stk(Sr#sr.stk, Until, Vdb)}. 1437 1438clear_dead_reg(Sr, Until, Vdb) -> 1439 Reg = map(fun ({I,V}) -> 1440 case vdb_find(V, Vdb) of 1441 {V,_,L} when L > Until -> {I,V}; 1442 _ -> free %Remove anything else 1443 end; 1444 ({reserved,I,V}) -> {reserved,I,V}; 1445 (free) -> free 1446 end, Sr#sr.reg), 1447 reserve(Sr#sr.res, Reg, Sr#sr.stk). 1448 1449clear_dead_stk(Stk, Until, Vdb) -> 1450 map(fun ({V}) -> 1451 case vdb_find(V, Vdb) of 1452 {V,_,L} when L > Until -> {V}; 1453 _ -> dead %Remove anything else 1454 end; 1455 (free) -> free; 1456 (dead) -> dead 1457 end, Stk). 1458 1459%% sr_merge(Sr1, Sr2) -> Sr. 1460%% Merge two stack/register states keeping the longest of both stack 1461%% and register. Perform consistency check on both, elements must be 1462%% the same. Allow frame size 'void' to make easy creation of 1463%% "empty" frame. 1464 1465sr_merge(#sr{reg=R1,stk=S1,res=[]}, #sr{reg=R2,stk=S2,res=[]}) -> 1466 #sr{reg=longest(R1, R2),stk=longest(S1, S2),res=[]}; 1467sr_merge(void, S2) -> S2#sr{res=[]}; 1468sr_merge(S1, void) -> S1#sr{res=[]}. 1469 1470longest([H|T1], [H|T2]) -> [H|longest(T1, T2)]; 1471longest([dead|T1], [free|T2]) -> [dead|longest(T1, T2)]; 1472longest([free|T1], [dead|T2]) -> [dead|longest(T1, T2)]; 1473longest([dead|T1], []) -> [dead|T1]; 1474longest([], [dead|T2]) -> [dead|T2]; 1475longest([free|T1], []) -> [free|T1]; 1476longest([], [free|T2]) -> [free|T2]; 1477longest([], []) -> []. 1478 1479%% adjust_stack(Bef, FirstBefore, LastFrom, Vdb) -> {[Ainstr],Aft}. 1480%% Do complete stack adjustment by compressing stack and adding 1481%% variables to be saved. Try to optimise ordering on stack by 1482%% having reverse order to their lifetimes. 1483%% 1484%% In Beam, there is a fixed stack frame and no need to do stack compression. 1485 1486adjust_stack(Bef, Fb, Lf, Vdb) -> 1487 Stk0 = Bef#sr.stk, 1488 {Stk1,Saves} = save_stack(Stk0, Fb, Lf, Vdb), 1489 {saves(Saves, Bef#sr.reg, Stk1), 1490 Bef#sr{stk=Stk1}}. 1491 1492%% save_stack(Stack, FirstBefore, LastFrom, Vdb) -> {[SaveVar],NewStack}. 1493%% Save variables which are used past current point and which are not 1494%% already on the stack. 1495 1496save_stack(Stk0, Fb, Lf, Vdb) -> 1497 %% New variables that are in use but not on stack. 1498 New = [ {V,F,L} || {V,F,L} <- Vdb, 1499 F < Fb, 1500 L >= Lf, 1501 not on_stack(V, Stk0) ], 1502 %% Add new variables that are not just dropped immediately. 1503 %% N.B. foldr works backwards from the end!! 1504 Saves = [ V || {V,_,_} <- keysort(3, New) ], 1505 Stk1 = foldr(fun (V, Stk) -> put_stack(V, Stk) end, Stk0, Saves), 1506 {Stk1,Saves}. 1507 1508%% saves([SaveVar], Reg, Stk) -> [{move,Reg,Stk}]. 1509%% Generate move instructions to save variables onto stack. The 1510%% stack/reg info used is that after the new stack has been made. 1511 1512saves(Ss, Reg, Stk) -> 1513 Res = map(fun (V) -> 1514 {move,fetch_reg(V, Reg),fetch_stack(V, Stk)} 1515 end, Ss), 1516 Res. 1517 1518%% comment(C) -> ['%'{C}]. 1519 1520%comment(C) -> [{'%',C}]. 1521comment(_) -> []. 1522 1523%% fetch_var(VarName, StkReg) -> r{R} | sp{Sp}. 1524%% find_var(VarName, StkReg) -> ok{r{R} | sp{Sp}} | error. 1525%% Fetch/find a variable in either the registers or on the 1526%% stack. Fetch KNOWS it's there. 1527 1528fetch_var(V, Sr) -> 1529 case find_reg(V, Sr#sr.reg) of 1530 {ok,R} -> R; 1531 error -> fetch_stack(V, Sr#sr.stk) 1532 end. 1533 1534% find_var(V, Sr) -> 1535% case find_reg(V, Sr#sr.reg) of 1536% {ok,R} -> {ok,R}; 1537% error -> 1538% case find_stack(V, Sr#sr.stk) of 1539% {ok,S} -> {ok,S}; 1540% error -> error 1541% end 1542% end. 1543 1544load_vars(Vs, Regs) -> 1545 foldl(fun ({var,V}, Rs) -> put_reg(V, Rs) end, Regs, Vs). 1546 1547%% put_reg(Val, Regs) -> Regs. 1548%% load_reg(Val, Reg, Regs) -> Regs. 1549%% free_reg(Val, Regs) -> Regs. 1550%% find_reg(Val, Regs) -> ok{r{R}} | error. 1551%% fetch_reg(Val, Regs) -> r{R}. 1552%% Functions to interface the registers. 1553%% put_reg puts a value into a free register, 1554%% load_reg loads a value into a fixed register 1555%% free_reg frees a register containing a specific value. 1556 1557% put_regs(Vs, Rs) -> foldl(fun put_reg/2, Rs, Vs). 1558 1559put_reg(V, Rs) -> put_reg_1(V, Rs, 0). 1560 1561put_reg_1(V, [free|Rs], I) -> [{I,V}|Rs]; 1562put_reg_1(V, [{reserved,I,V}|Rs], I) -> [{I,V}|Rs]; 1563put_reg_1(V, [R|Rs], I) -> [R|put_reg_1(V, Rs, I+1)]; 1564put_reg_1(V, [], I) -> [{I,V}]. 1565 1566load_reg(V, R, Rs) -> load_reg_1(V, R, Rs, 0). 1567 1568load_reg_1(V, I, [_|Rs], I) -> [{I,V}|Rs]; 1569load_reg_1(V, I, [R|Rs], C) -> [R|load_reg_1(V, I, Rs, C+1)]; 1570load_reg_1(V, I, [], I) -> [{I,V}]; 1571load_reg_1(V, I, [], C) -> [free|load_reg_1(V, I, [], C+1)]. 1572 1573% free_reg(V, [{I,V}|Rs]) -> [free|Rs]; 1574% free_reg(V, [R|Rs]) -> [R|free_reg(V, Rs)]; 1575% free_reg(V, []) -> []. 1576 1577fetch_reg(V, [{I,V}|_]) -> {x,I}; 1578fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs). 1579 1580find_reg(V, [{I,V}|_]) -> {ok,{x,I}}; 1581find_reg(V, [_|SRs]) -> find_reg(V, SRs); 1582find_reg(_, []) -> error. 1583 1584%% For the bit syntax, we need a scratch register if we are constructing 1585%% a binary that will not be used. 1586 1587find_scratch_reg(Rs) -> find_scratch_reg(Rs, 0). 1588 1589find_scratch_reg([free|_], I) -> {x,I}; 1590find_scratch_reg([_|Rs], I) -> find_scratch_reg(Rs, I+1); 1591find_scratch_reg([], I) -> {x,I}. 1592 1593%%copy_reg(Val, R, Regs) -> load_reg(Val, R, Regs). 1594%%move_reg(Val, R, Regs) -> load_reg(Val, R, free_reg(Val, Regs)). 1595 1596%%clear_regs(Regs) -> map(fun (R) -> free end, Regs). 1597clear_regs(_) -> []. 1598 1599max_reg(Regs) -> 1600 foldl(fun ({I,_}, _) -> I; 1601 (_, Max) -> Max end, 1602 -1, Regs) + 1. 1603 1604%% put_stack(Val, [{Val}]) -> [{Val}]. 1605%% fetch_stack(Var, Stk) -> sp{S}. 1606%% find_stack(Var, Stk) -> ok{sp{S}} | error. 1607%% Functions to interface the stack. 1608 1609put_stack(Val, []) -> [{Val}]; 1610put_stack(Val, [dead|Stk]) -> [{Val}|Stk]; 1611put_stack(Val, [free|Stk]) -> [{Val}|Stk]; 1612put_stack(Val, [NotFree|Stk]) -> [NotFree|put_stack(Val, Stk)]. 1613 1614put_stack_carefully(Val, Stk0) -> 1615 case catch put_stack_carefully1(Val, Stk0) of 1616 error -> error; 1617 Stk1 when list(Stk1) -> Stk1 1618 end. 1619 1620put_stack_carefully1(_, []) -> throw(error); 1621put_stack_carefully1(Val, [dead|Stk]) -> [{Val}|Stk]; 1622put_stack_carefully1(Val, [free|Stk]) -> [{Val}|Stk]; 1623put_stack_carefully1(Val, [NotFree|Stk]) -> 1624 [NotFree|put_stack_carefully1(Val, Stk)]. 1625 1626fetch_stack(Var, Stk) -> fetch_stack(Var, Stk, 0). 1627 1628fetch_stack(V, [{V}|_], I) -> {yy,I}; 1629fetch_stack(V, [_|Stk], I) -> fetch_stack(V, Stk, I+1). 1630 1631% find_stack(Var, Stk) -> find_stack(Var, Stk, 0). 1632 1633% find_stack(V, [{V}|Stk], I) -> {ok,{yy,I}}; 1634% find_stack(V, [O|Stk], I) -> find_stack(V, Stk, I+1); 1635% find_stack(V, [], I) -> error. 1636 1637on_stack(V, Stk) -> keymember(V, 1, Stk). 1638 1639%% put_catch(CatchTag, Stack) -> Stack' 1640%% drop_catch(CatchTag, Stack) -> Stack' 1641%% Special interface for putting and removing catch tags, to ensure that 1642%% catches nest properly. Also used for try tags. 1643 1644put_catch(Tag, Stk0) -> put_catch(Tag, reverse(Stk0), []). 1645 1646put_catch(Tag, [], Stk) -> 1647 put_stack({catch_tag,Tag}, Stk); 1648put_catch(Tag, [{{catch_tag,_}}|_]=RevStk, Stk) -> 1649 reverse(RevStk, put_stack({catch_tag,Tag}, Stk)); 1650put_catch(Tag, [Other|Stk], Acc) -> 1651 put_catch(Tag, Stk, [Other|Acc]). 1652 1653drop_catch(Tag, [{{catch_tag,Tag}}|Stk]) -> [free|Stk]; 1654drop_catch(Tag, [Other|Stk]) -> [Other|drop_catch(Tag, Stk)]. 1655 1656%%% 1657%%% Finish the code generation for the bit syntax matching. 1658%%% 1659 1660bs_function({function,Name,Arity,CLabel,Asm0}=Func) -> 1661 case bs_needed(Asm0, 0, false, []) of 1662 {false,[]} -> Func; 1663 {true,Dict} -> 1664 Asm = bs_replace(Asm0, Dict, []), 1665 {function,Name,Arity,CLabel,Asm} 1666 end. 1667 1668%%% 1669%%% Pass 1: Found out which bs_restore's that are needed. For now we assume 1670%%% that a bs_restore is needed unless it is directly preceded by a bs_save. 1671%%% 1672 1673bs_needed([{bs_save,Name},{bs_restore,Name}|T], N, _BsUsed, Dict) -> 1674 bs_needed(T, N, true, Dict); 1675bs_needed([{bs_save,_Name}|T], N, _BsUsed, Dict) -> 1676 bs_needed(T, N, true, Dict); 1677bs_needed([{bs_restore,Name}|T], N, _BsUsed, Dict) -> 1678 case keysearch(Name, 1, Dict) of 1679 {value,{Name,_}} -> bs_needed(T, N, true, Dict); 1680 false -> bs_needed(T, N+1, true, [{Name,N}|Dict]) 1681 end; 1682bs_needed([{bs_init,_,_}|T], N, _, Dict) -> 1683 bs_needed(T, N, true, Dict); 1684bs_needed([{bs_init2,_,_,_,_,_}|T], N, _, Dict) -> 1685 bs_needed(T, N, true, Dict); 1686bs_needed([{bs_start_match,_,_}|T], N, _, Dict) -> 1687 bs_needed(T, N, true, Dict); 1688bs_needed([_|T], N, BsUsed, Dict) -> 1689 bs_needed(T, N, BsUsed, Dict); 1690bs_needed([], _, BsUsed, Dict) -> {BsUsed,Dict}. 1691 1692%%% 1693%%% Pass 2: Only needed if there were some bs_* instructions found. 1694%%% 1695%%% Remove any bs_save with a name that never were found to be restored 1696%%% in the first pass. 1697%%% 1698 1699bs_replace([{bs_save,Name}=Save,{bs_restore,Name}|T], Dict, Acc) -> 1700 bs_replace([Save|T], Dict, Acc); 1701bs_replace([{bs_save,Name}|T], Dict, Acc) -> 1702 case keysearch(Name, 1, Dict) of 1703 {value,{Name,N}} -> 1704 bs_replace(T, Dict, [{bs_save,N}|Acc]); 1705 false -> 1706 bs_replace(T, Dict, Acc) 1707 end; 1708bs_replace([{bs_restore,Name}|T], Dict, Acc) -> 1709 case keysearch(Name, 1, Dict) of 1710 {value,{Name,N}} -> 1711 bs_replace(T, Dict, [{bs_restore,N}|Acc]); 1712 false -> 1713 bs_replace(T, Dict, Acc) 1714 end; 1715bs_replace([{bs_init2,Fail,Bytes,Regs,Flags,Dst}|T0], Dict, Acc) -> 1716 case bs_find_test_heap(T0) of 1717 none -> 1718 bs_replace(T0, Dict, [{bs_init2,Fail,Bytes,0,Regs,Flags,Dst}|Acc]); 1719 {T,Words} -> 1720 bs_replace(T, Dict, [{bs_init2,Fail,Bytes,Words,Regs,Flags,Dst}|Acc]) 1721 end; 1722bs_replace([H|T], Dict, Acc) -> 1723 bs_replace(T, Dict, [H|Acc]); 1724bs_replace([], _, Acc) -> reverse(Acc). 1725 1726bs_find_test_heap(Is) -> 1727 bs_find_test_heap_1(Is, []). 1728 1729bs_find_test_heap_1([{bs_put_integer,_,_,_,_,_}=I|Is], Acc) -> 1730 bs_find_test_heap_1(Is, [I|Acc]); 1731bs_find_test_heap_1([{bs_put_float,_,_,_,_,_}=I|Is], Acc) -> 1732 bs_find_test_heap_1(Is, [I|Acc]); 1733bs_find_test_heap_1([{bs_put_binary,_,_,_,_,_}=I|Is], Acc) -> 1734 bs_find_test_heap_1(Is, [I|Acc]); 1735bs_find_test_heap_1([{test_heap,Words,_}|Is], Acc) -> 1736 {reverse(Acc, Is),Words}; 1737bs_find_test_heap_1(_, _) -> none. 1738 1739%% new_label(St) -> {L,St}. 1740 1741new_label(St) -> 1742 L = St#cg.lcount, 1743 {L,St#cg{lcount=L+1}}. 1744 1745flatmapfoldl(F, Accu0, [Hd|Tail]) -> 1746 {R,Accu1} = F(Hd, Accu0), 1747 {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail), 1748 {R++Rs,Accu2}; 1749flatmapfoldl(_, Accu, []) -> {[],Accu}. 1750 1751flatmapfoldr(F, Accu0, [Hd|Tail]) -> 1752 {Rs,Accu1} = flatmapfoldr(F, Accu0, Tail), 1753 {R,Accu2} = F(Hd, Accu1), 1754 {R++Rs,Accu2}; 1755flatmapfoldr(_, Accu, []) -> {[],Accu}. 1756