1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2018-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%% Purpose: Convert the Kernel Erlang format to the SSA format.
21
22-module(beam_kernel_to_ssa).
23
24%% The main interface.
25-export([module/2]).
26
27-import(lists, [all/2,append/1,flatmap/2,foldl/3,
28                keysort/2,mapfoldl/3,map/2,member/2,
29                reverse/1,reverse/2,sort/1]).
30
31-include("v3_kernel.hrl").
32-include("beam_ssa.hrl").
33
34-type label() :: beam_ssa:label().
35
36%% Main codegen structure.
37-record(cg, {lcount=1 :: label(),   %Label counter
38             bfail=1 :: label(),
39             catch_label=none :: 'none' | label(),
40             vars=#{} :: map(),     %Defined variables.
41             break=0 :: label(),    %Break label
42             recv=0 :: label(),     %Receive label
43             ultimate_failure=0 :: label(), %Label for ultimate match failure.
44             labels=#{} :: #{atom() => label()},
45             no_make_fun3=false :: boolean()
46            }).
47
48%% Internal records.
49-record(cg_break, {args :: [beam_ssa:value()],
50                   phi :: label()
51                  }).
52-record(cg_phi, {vars :: [beam_ssa:b_var()]
53                }).
54-record(cg_unreachable, {}).
55
56-spec module(#k_mdef{}, [compile:option()]) -> {'ok',#b_module{}}.
57
58module(#k_mdef{name=Mod,exports=Es,attributes=Attr,body=Forms}, Opts) ->
59    NoMakeFun3 = proplists:get_bool(no_make_fun3, Opts),
60    Body = functions(Forms, Mod, NoMakeFun3),
61    Module = #b_module{name=Mod,exports=Es,attributes=Attr,body=Body},
62    {ok,Module}.
63
64functions(Forms, Mod, NoMakeFun3) ->
65    [function(F, Mod, NoMakeFun3) || F <- Forms].
66
67function(#k_fdef{anno=Anno0,func=Name,arity=Arity,
68                 vars=As0,body=Kb}, Mod, NoMakeFun3) ->
69    try
70        #k_match{} = Kb,                   %Assertion.
71
72        %% Generate the SSA form immediate format.
73        St0 = #cg{no_make_fun3=NoMakeFun3},
74        {As,St1} = new_ssa_vars(As0, St0),
75        {Asm,St} = cg_fun(Kb, St1),
76        Anno1 = line_anno(Anno0),
77        Anno = Anno1#{func_info=>{Mod,Name,Arity}},
78        #b_function{anno=Anno,args=As,bs=Asm,cnt=St#cg.lcount}
79    catch
80        Class:Error:Stack ->
81            io:fwrite("Function: ~w/~w\n", [Name,Arity]),
82            erlang:raise(Class, Error, Stack)
83    end.
84
85%% cg_fun([Lkexpr], [HeadVar], State) -> {[Ainstr],State}
86
87cg_fun(Ke, St0) ->
88    {UltimateFail,FailIs,St1} = make_failure(badarg, St0),
89    ?EXCEPTION_BLOCK = UltimateFail,            %Assertion.
90    St2 = St1#cg{bfail=UltimateFail,ultimate_failure=UltimateFail},
91    {B,St} = cg(Ke, St2),
92    Asm = [{label,0}|B++FailIs],
93    finalize(Asm, St).
94
95make_failure(Reason, St0) ->
96    {Lbl,St1} = new_label(St0),
97    {Dst,St} = new_ssa_var('@ssa_ret', St1),
98    Is = [{label,Lbl},
99          #b_set{op=call,dst=Dst,
100                 args=[#b_remote{mod=#b_literal{val=erlang},
101                                 name=#b_literal{val=error},
102                                 arity=1},
103                       #b_literal{val=Reason}]},
104          #b_ret{arg=Dst}],
105    {Lbl,Is,St}.
106
107%% cg(Lkexpr, State) -> {[Ainstr],State}.
108%%  Generate code for a kexpr.
109
110cg(#k_match{body=M,ret=Rs}, St) ->
111    do_match_cg(M, Rs, St);
112cg(#k_seq{arg=Arg,body=Body}, St0) ->
113    {ArgIs,St1} = cg(Arg, St0),
114    {BodyIs,St} = cg(Body, St1),
115    {ArgIs++BodyIs,St};
116cg(#k_call{anno=Le,op=Func,args=As,ret=Rs}, St) ->
117    call_cg(Func, As, Rs, Le, St);
118cg(#k_enter{anno=Le,op=Func,args=As}, St) ->
119    enter_cg(Func, As, Le, St);
120cg(#k_bif{anno=Le}=Bif, St) ->
121    bif_cg(Bif, Le, St);
122cg(#k_try{arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th,ret=Rs}, St) ->
123    try_cg(Ta, Vs, Tb, Evs, Th, Rs, St);
124cg(#k_try_enter{arg=Ta,vars=Vs,body=Tb,evars=Evs,handler=Th}, St) ->
125    try_enter_cg(Ta, Vs, Tb, Evs, Th, St);
126cg(#k_catch{body=Cb,ret=[R]}, St) ->
127    do_catch_cg(Cb, R, St);
128cg(#k_put{anno=Le,arg=Con,ret=Var}, St) ->
129    put_cg(Var, Con, Le, St);
130cg(#k_return{args=[Ret0]}, St) ->
131    Ret = ssa_arg(Ret0, St),
132    {[#b_ret{arg=Ret}],St};
133cg(#k_break{args=Bs}, #cg{break=Br}=St) ->
134    Args = ssa_args(Bs, St),
135    {[#cg_break{args=Args,phi=Br}],St};
136cg(#k_letrec_goto{label=Label,first=First,then=Then,ret=Rs},
137   #cg{break=OldBreak,labels=Labels0}=St0) ->
138    {Tf,St1} = new_label(St0),
139    {B,St2} = new_label(St1),
140    Labels = Labels0#{Label=>Tf},
141    {Fis,St3} = cg(First, St2#cg{labels=Labels,break=B}),
142    {Sis,St4} = cg(Then, St3),
143    St5 = St4#cg{labels=Labels0},
144    {BreakVars,St} = new_ssa_vars(Rs, St5),
145    Phi = #cg_phi{vars=BreakVars},
146    {Fis ++ [{label,Tf}] ++ Sis ++ [{label,B},Phi],St#cg{break=OldBreak}};
147cg(#k_goto{label=Label}, #cg{labels=Labels}=St) ->
148    Branch = map_get(Label, Labels),
149    {[make_uncond_branch(Branch)],St}.
150
151%% match_cg(Matc, [Ret], State) -> {[Ainstr],State}.
152%%  Generate code for a match.
153
154do_match_cg(M, Rs, #cg{bfail=Bfail,break=OldBreak}=St0) ->
155    {B,St1} = new_label(St0),
156    {Mis,St2} = match_cg(M, Bfail, St1#cg{break=B}),
157    St3 = St2#cg{break=OldBreak},
158    {BreakVars,St} = new_ssa_vars(Rs, St3),
159    {Mis ++ [{label,B},#cg_phi{vars=BreakVars}],St}.
160
161%% match_cg(Match, Fail, State) -> {[Ainstr],State}.
162%%  Generate code for a match tree.
163
164match_cg(#k_alt{first=F,then=S}, Fail, St0) ->
165    {Tf,St1} = new_label(St0),
166    {Fis,St2} = match_cg(F, Tf, St1),
167    {Sis,St3} = match_cg(S, Fail, St2),
168    {Fis ++ [{label,Tf}] ++ Sis,St3};
169match_cg(#k_select{var=#k_var{}=V,types=Scs}, Fail, St) ->
170    match_fmf(fun (S, F, Sta) ->
171                      select_cg(S, V, F, Fail, Sta)
172              end, Fail, St, Scs);
173match_cg(#k_guard{clauses=Gcs}, Fail, St) ->
174    match_fmf(fun (G, F, Sta) ->
175                      guard_clause_cg(G, F, Sta)
176              end, Fail, St, Gcs);
177match_cg(Ke, _Fail, St0) ->
178    cg(Ke, St0).
179
180%% select_cg(Sclause, V, TypeFail, ValueFail, State) -> {Is,State}.
181%%  Selecting type and value needs two failure labels, TypeFail is the
182%%  label to jump to of the next type test when this type fails, and
183%%  ValueFail is the label when this type is correct but the value is
184%%  wrong.  These are different as in the second case there is no need
185%%  to try the next type, it will always fail.
186
187select_cg(#k_type_clause{type=k_binary,values=[S]}, Var, Tf, Vf, St) ->
188    select_binary(S, Var, Tf, Vf, St);
189select_cg(#k_type_clause{type=k_bin_seg,values=Vs}, Var, Tf, _Vf, St) ->
190    select_bin_segs(Vs, Var, Tf, St);
191select_cg(#k_type_clause{type=k_bin_int,values=Vs}, Var, Tf, _Vf, St) ->
192    select_bin_segs(Vs, Var, Tf, St);
193select_cg(#k_type_clause{type=k_bin_end,values=[S]}, Var, Tf, _Vf, St) ->
194    select_bin_end(S, Var, Tf, St);
195select_cg(#k_type_clause{type=k_map,values=Vs}, Var, Tf, Vf, St) ->
196    select_map(Vs, Var, Tf, Vf, St);
197select_cg(#k_type_clause{type=k_cons,values=[S]}, Var, Tf, Vf, St) ->
198    select_cons(S, Var, Tf, Vf, St);
199select_cg(#k_type_clause{type=k_nil,values=[S]}, Var, Tf, Vf, St) ->
200    select_nil(S, Var, Tf, Vf, St);
201select_cg(#k_type_clause{type=k_literal,values=Vs}, Var, Tf, Vf, St) ->
202    select_literal(Vs, Var, Tf, Vf, St);
203select_cg(#k_type_clause{type=Type,values=Scs}, Var, Tf, Vf, St0) ->
204    {Vis,St1} =
205        mapfoldl(fun (S, Sta) ->
206                         {Val,Is,Stb} = select_val(S, Var, Vf, Sta),
207                         {{Is,[Val]},Stb}
208                 end, St0, Scs),
209    OptVls = combine(lists:sort(combine(Vis))),
210    {Vls,Sis,St2} = select_labels(OptVls, St1, [], []),
211    Arg = ssa_arg(Var, St2),
212    {Is,St} = select_val_cg(Type, Arg, Vls, Tf, Vf, Sis, St2),
213    {Is,St}.
214
215select_val_cg(k_atom, {bool,Dst}, Vls, _Tf, _Vf, Sis, St) ->
216    %% Generate a br instruction for a known boolean value from
217    %% the `wait_timeout` instruction.
218    #b_var{} = Dst,                             %Assertion.
219    [{#b_literal{val=false},Fail},{#b_literal{val=true},Succ}] = sort(Vls),
220    Br = #b_br{bool=Dst,succ=Succ,fail=Fail},
221    {[Br|Sis],St};
222select_val_cg(k_atom, {succeeded,Dst}, Vls, _Tf, _Vf, Sis, St0) ->
223    [{#b_literal{val=false},Fail},{#b_literal{val=true},Succ}] = sort(Vls),
224    #b_var{} = Dst,                             %Assertion.
225    %% Generate a `succeeded` instruction and two-way branch
226    %% following the `peek_message` instruction.
227    {Bool,St} = new_ssa_var('@ssa_bool', St0),
228    Succeeded = #b_set{op={succeeded,guard},dst=Bool,args=[Dst]},
229    Br = #b_br{bool=Bool,succ=Succ,fail=Fail},
230    {[Succeeded,Br|Sis],St};
231select_val_cg(k_tuple, Tuple, Vls, Tf, Vf, Sis, St0) ->
232    {Is0,St1} = make_cond_branch({bif,is_tuple}, [Tuple], Tf, St0),
233    {Arity,St2} = new_ssa_var('@ssa_arity', St1),
234    GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
235    {Is,St} = select_val_cg(k_int, Arity, Vls, Vf, Vf, Sis, St2),
236    {Is0++[GetArity]++Is,St};
237select_val_cg(Type, R, Vls, Tf, Vf, Sis, St0) ->
238    {TypeIs,St1} = if
239                       Tf =:= Vf ->
240                           %% The type and value failure labels are the same;
241                           %% we don't need a type test.
242                           {[],St0};
243                       true ->
244                           %% Different labels for type failure and
245                           %% label failure; we need a type test.
246                           Test = select_type_test(Type),
247                           make_cond_branch(Test, [R], Tf, St0)
248                   end,
249    case Vls of
250        [{Val,Succ}] ->
251            {Is,St} = make_cond({bif,'=:='}, [R,Val], Vf, Succ, St1),
252            {TypeIs++Is++Sis,St};
253        [_|_] ->
254            {TypeIs++[#b_switch{arg=R,fail=Vf,list=Vls}|Sis],St1}
255    end.
256
257select_type_test(k_int) -> {bif,is_integer};
258select_type_test(k_atom) -> {bif,is_atom};
259select_type_test(k_float) -> {bif,is_float}.
260
261combine([{Is,Vs1},{Is,Vs2}|Vis]) -> combine([{Is,Vs1 ++ Vs2}|Vis]);
262combine([V|Vis]) -> [V|combine(Vis)];
263combine([]) -> [].
264
265select_labels([{Is,Vs}|Vis], St0, Vls, Sis) ->
266    {Lbl,St1} = new_label(St0),
267    select_labels(Vis, St1, add_vls(Vs, Lbl, Vls), [[{label,Lbl}|Is]|Sis]);
268select_labels([], St, Vls, Sis) ->
269    {Vls,append(Sis),St}.
270
271add_vls([V|Vs], Lbl, Acc) ->
272    add_vls(Vs, Lbl, [{#b_literal{val=V},Lbl}|Acc]);
273add_vls([], _, Acc) -> Acc.
274
275select_literal(S, V, Tf, Vf, St) ->
276    Src = ssa_arg(V, St),
277    F = fun(ValClause, Fail, St0) ->
278                {Val,ValIs,St1} = select_val(ValClause, V, Vf, St0),
279                Args = [Src,#b_literal{val=Val}],
280                {Is,St2} = make_cond_branch({bif,'=:='}, Args, Fail, St1),
281                {Is++ValIs,St2}
282        end,
283    match_fmf(F, Tf, St, S).
284
285select_cons(#k_val_clause{val=#k_cons{hd=Hd,tl=Tl},body=B},
286            V, Tf, Vf, St0) ->
287    Es = [Hd,Tl],
288    {Eis,St1} = select_extract_cons(V, Es, St0),
289    {Bis,St2} = match_cg(B, Vf, St1),
290    Src = ssa_arg(V, St2),
291    {Is,St} = make_cond_branch(is_nonempty_list, [Src], Tf, St2),
292    {Is ++ Eis ++ Bis,St}.
293
294select_nil(#k_val_clause{val=#k_literal{val=[]},body=B}, V, Tf, Vf, St0) ->
295    {Bis,St1} = match_cg(B, Vf, St0),
296    Src = ssa_arg(V, St1),
297    {Is,St} = make_cond_branch({bif,'=:='}, [Src,#b_literal{val=[]}], Tf, St1),
298    {Is ++ Bis,St}.
299
300select_binary(#k_val_clause{val=#k_binary{segs=#k_var{name=Ctx0}},body=B},
301              #k_var{}=Src, Tf, Vf, St0) ->
302    {Ctx,St1} = new_ssa_var(Ctx0, St0),
303    {Bis0,St2} = match_cg(B, Vf, St1),
304    {TestIs,St} = make_succeeded(Ctx, {guard, Tf}, St2),
305    Bis1 = [#b_set{op=bs_start_match,dst=Ctx,
306                   args=[#b_literal{val=new},
307                         ssa_arg(Src, St)]}] ++ TestIs ++ Bis0,
308    Bis = finish_bs_matching(Bis1),
309    {Bis,St}.
310
311finish_bs_matching([#b_set{op=bs_match,
312                           args=[#b_literal{val=string},Ctx,#b_literal{val=BinList}]}=Set|Is])
313  when is_list(BinList) ->
314    I = Set#b_set{args=[#b_literal{val=string},Ctx,
315                        #b_literal{val=list_to_bitstring(BinList)}]},
316    finish_bs_matching([I|Is]);
317finish_bs_matching([I|Is]) ->
318    [I|finish_bs_matching(Is)];
319finish_bs_matching([]) -> [].
320
321make_cond(Cond, Args, Fail, Succ, St0) ->
322    {Bool,St} = new_ssa_var('@ssa_bool', St0),
323    Bif = #b_set{op=Cond,dst=Bool,args=Args},
324    Br = #b_br{bool=Bool,succ=Succ,fail=Fail},
325    {[Bif,Br],St}.
326
327make_cond_branch(Cond, Args, Fail, St0) ->
328    {Bool,St1} = new_ssa_var('@ssa_bool', St0),
329    {Succ,St} = new_label(St1),
330    Bif = #b_set{op=Cond,dst=Bool,args=Args},
331    Br = #b_br{bool=Bool,succ=Succ,fail=Fail},
332    {[Bif,Br,{label,Succ}],St}.
333
334make_uncond_branch(Fail) ->
335    #b_br{bool=#b_literal{val=true},succ=Fail,fail=Fail}.
336
337%%
338%% Success checks need to be treated differently in bodies and guards; a check
339%% in a guard can be safely removed when we know it fails because we know
340%% there's never any side-effects, but in bodies the checked instruction may
341%% throw an exception and we need to ensure it isn't optimized away.
342%%
343%% Checks are expressed as {succeeded,guard} and {succeeded,body} respectively,
344%% where the latter has a side-effect (see beam_ssa:no_side_effect/1) and the
345%% former does not. This ensures that passes like ssa_opt_dead and ssa_opt_live
346%% won't optimize away pure operations that may throw an exception, since their
347%% result is used in {succeeded,body}.
348%%
349%% Other than the above details, the two variants are equivalent and most
350%% passes that care about them can simply match {succeeded,_}.
351%%
352
353make_succeeded(Var, {guard, Fail}, St) ->
354    make_succeeded_1(Var, guard, Fail, St);
355make_succeeded(Var, {in_catch, CatchLbl}, St) ->
356    make_succeeded_1(Var, body, CatchLbl, St);
357make_succeeded(Var, {no_catch, Fail}, St) ->
358    #cg{ultimate_failure=Fail} = St,            %Assertion
359    make_succeeded_1(Var, body, Fail, St).
360
361make_succeeded_1(Var, Kind, Fail, St0) ->
362    {Bool,St1} = new_ssa_var('@ssa_bool', St0),
363    {Succ,St} = new_label(St1),
364
365    Check = [#b_set{op={succeeded,Kind},dst=Bool,args=[Var]},
366             #b_br{bool=Bool,succ=Succ,fail=Fail}],
367
368    {Check ++ [{label,Succ}], St}.
369
370%% Instructions for selection of binary segments.
371
372select_bin_segs(Scs, Ivar, Tf, St) ->
373    match_fmf(fun(S, Fail, Sta) ->
374                      select_bin_seg(S, Ivar, Fail, Sta)
375              end, Tf, St, Scs).
376
377select_bin_seg(#k_val_clause{val=#k_bin_seg{size=Size,unit=U,type=T,
378                                            seg=Seg,flags=Fs,next=Next},
379                             body=B,anno=Anno},
380               #k_var{}=Src, Fail, St0) ->
381    LineAnno = line_anno(Anno),
382    Ctx = get_context(Src, St0),
383    {Mis,St1} = select_extract_bin(Next, Size, U, T, Fs, Fail,
384                                   Ctx, LineAnno, St0),
385    {Extracted,St2} = new_ssa_var(Seg#k_var.name, St1),
386    {Bis,St} = match_cg(B, Fail, St2),
387    BsGet = #b_set{op=bs_extract,dst=Extracted,args=[ssa_arg(Next, St)]},
388    Is = Mis ++ [BsGet] ++ Bis,
389    {Is,St};
390select_bin_seg(#k_val_clause{val=#k_bin_int{size=Sz,unit=U,flags=Fs,
391                                            val=Val,next=Next},
392                             body=B},
393               #k_var{}=Src, Fail, St0) ->
394    Ctx = get_context(Src, St0),
395    {Mis,St1} = select_extract_int(Next, Val, Sz, U, Fs, Fail,
396                                     Ctx, St0),
397    {Bis,St} = match_cg(B, Fail, St1),
398    Is = case Mis ++ Bis of
399             [#b_set{op=bs_match,args=[#b_literal{val=string},OtherCtx1,Bin1]},
400              #b_set{op={succeeded,guard},dst=Bool1},
401              #b_br{bool=Bool1,succ=Succ,fail=Fail},
402              {label,Succ},
403              #b_set{op=bs_match,dst=Dst,args=[#b_literal{val=string},_OtherCtx2,Bin2]}|
404              [#b_set{op={succeeded,guard},dst=Bool2},
405               #b_br{bool=Bool2,fail=Fail}|_]=Is0] ->
406                 %% We used to do this optimization later, but it
407                 %% turns out that in huge functions with many
408                 %% string matching instructions, it's a huge win
409                 %% to do the combination now. To avoid copying the
410                 %% binary data again and again, we'll combine bitstrings
411                 %% in a list and convert all of it to a bitstring later.
412                 {#b_literal{val=B1},#b_literal{val=B2}} = {Bin1,Bin2},
413                 Bin = #b_literal{val=[B1,B2]},
414                 Set = #b_set{op=bs_match,dst=Dst,args=[#b_literal{val=string},OtherCtx1,Bin]},
415                 [Set|Is0];
416             Is0 ->
417                 Is0
418         end,
419    {Is,St}.
420
421get_context(#k_var{}=Var, St) ->
422    ssa_arg(Var, St).
423
424select_bin_end(#k_val_clause{val=#k_bin_end{},body=B}, Src, Tf, St0) ->
425    Ctx = get_context(Src, St0),
426    {Bis,St1} = match_cg(B, Tf, St0),
427    {TestIs,St} = make_cond_branch(bs_test_tail, [Ctx,#b_literal{val=0}], Tf, St1),
428    Is = TestIs++Bis,
429    {Is,St}.
430
431select_extract_bin(#k_var{name=Hd}, Size0, Unit, Type, Flags, Vf,
432                   Ctx, Anno, St0) ->
433    {Dst,St1} = new_ssa_var(Hd, St0),
434    Size = case {Size0,ssa_arg(Size0, St0)} of
435               {#k_var{},#b_literal{val=all}} ->
436                   %% The size `all` is used for the size of the final binary
437                   %% segment in a pattern. Using `all` explicitly is not allowed,
438                   %% so we convert it to an obvious invalid size.
439                   #b_literal{val=bad_size};
440               {_,Size1} ->
441                   Size1
442           end,
443    build_bs_instr(Anno, Type, Vf, Ctx, Size, Unit, Flags, Dst, St1).
444
445select_extract_int(#k_var{name=Tl}, 0, #k_literal{val=0}, _U, _Fs, _Vf,
446                   Ctx, St0) ->
447    St = set_ssa_var(Tl, Ctx, St0),
448    {[],St};
449select_extract_int(#k_var{name=Tl}, Val, #k_literal{val=Sz}, U, Fs, Vf,
450                   Ctx, St0) when is_integer(Sz) ->
451    {Dst,St1} = new_ssa_var(Tl, St0),
452    Bits = U*Sz,
453    Bin = case member(big, Fs) of
454              true ->
455                  <<Val:Bits>>;
456              false ->
457                  true = member(little, Fs),	%Assertion.
458                  <<Val:Bits/little>>
459          end,
460    Bits = bit_size(Bin),			%Assertion.
461    {TestIs,St} = make_succeeded(Dst, {guard, Vf}, St1),
462    Set = #b_set{op=bs_match,dst=Dst,
463                 args=[#b_literal{val=string},Ctx,#b_literal{val=Bin}]},
464    {[Set|TestIs],St}.
465
466build_bs_instr(Anno, Type, Fail, Ctx, Size, Unit0, Flags0, Dst, St0) ->
467    Unit = #b_literal{val=Unit0},
468    Flags = #b_literal{val=Flags0},
469    NeedSize = bs_need_size(Type),
470    TypeArg = #b_literal{val=Type},
471    Get = case NeedSize of
472              true ->
473                  #b_set{anno=Anno,op=bs_match,dst=Dst,
474                         args=[TypeArg,Ctx,Flags,Size,Unit]};
475              false ->
476                  #b_set{anno=Anno,op=bs_match,dst=Dst,
477                         args=[TypeArg,Ctx,Flags]}
478          end,
479    {Is,St} = make_succeeded(Dst, {guard, Fail}, St0),
480    {[Get|Is],St}.
481
482select_val(#k_val_clause{val=#k_tuple{es=Es},body=B}, V, Vf, St0) ->
483    {Eis,St1} = select_extract_tuple(V, Es, St0),
484    {Bis,St2} = match_cg(B, Vf, St1),
485    {length(Es),Eis ++ Bis,St2};
486select_val(#k_val_clause{val=#k_literal{val=Val},body=B}, _V, Vf, St0) ->
487    {Bis,St1} = match_cg(B, Vf, St0),
488    {Val,Bis,St1}.
489
490%% select_extract_tuple(Src, [V], State) -> {[E],State}.
491%%  Extract tuple elements, but only if they are actually used.
492%%
493%%  Not extracting tuple elements that are not used is an
494%%  optimization for compile time and memory use during compilation.
495%%  It is probably worthwhile because it is common to extract only a
496%%  few elements from a huge record.
497
498select_extract_tuple(Src, Vs, St0) ->
499    Tuple = ssa_arg(Src, St0),
500    F = fun (#k_var{anno=Anno,name=V}, {Elem,S0}) ->
501                case member(unused, Anno) of
502                    true ->
503                        {[],{Elem+1,S0}};
504                    false ->
505                        Args = [Tuple,#b_literal{val=Elem}],
506                        {Dst,S} = new_ssa_var(V, S0),
507                        Get = #b_set{op=get_tuple_element,
508                                     dst=Dst,args=Args},
509                        {[Get],{Elem+1,S}}
510                end
511        end,
512    {Es,{_,St}} = flatmapfoldl(F, {0,St0}, Vs),
513    {Es,St}.
514
515select_map(Scs, V, Tf, Vf, St0) ->
516    MapSrc = ssa_arg(V, St0),
517    {Is,St1} =
518        match_fmf(fun(#k_val_clause{val=#k_map{op=exact,es=Es},
519                                    body=B}, Fail, St1) ->
520                          select_map_val(V, Es, B, Fail, St1)
521                  end, Vf, St0, Scs),
522    {TestIs,St} = make_cond_branch({bif,is_map}, [MapSrc], Tf, St1),
523    {TestIs++Is,St}.
524
525select_map_val(V, Es, B, Fail, St0) ->
526    {Eis,St1} = select_extract_map(Es, V, Fail, St0),
527    {Bis,St2} = match_cg(B, Fail, St1),
528    {Eis++Bis,St2}.
529
530select_extract_map([P|Ps], Src, Fail, St0) ->
531    MapSrc = ssa_arg(Src, St0),
532    #k_map_pair{key=Key0,val=#k_var{name=Dst0}} = P,
533    Key = ssa_arg(Key0, St0),
534    {Dst,St1} = new_ssa_var(Dst0, St0),
535    Set = #b_set{op=get_map_element,dst=Dst,args=[MapSrc,Key]},
536    {TestIs,St2} = make_succeeded(Dst, {guard, Fail}, St1),
537    {Is,St} = select_extract_map(Ps, Src, Fail, St2),
538    {[Set|TestIs]++Is,St};
539select_extract_map([], _, _, St) ->
540    {[],St}.
541
542select_extract_cons(Src0, [#k_var{name=Hd},#k_var{name=Tl}], St0) ->
543    Src = ssa_arg(Src0, St0),
544    {HdDst,St1} = new_ssa_var(Hd, St0),
545    {TlDst,St2} = new_ssa_var(Tl, St1),
546    GetHd = #b_set{op=get_hd,dst=HdDst,args=[Src]},
547    GetTl = #b_set{op=get_tl,dst=TlDst,args=[Src]},
548    {[GetHd,GetTl],St2}.
549
550guard_clause_cg(#k_guard_clause{guard=G,body=B}, Fail, St0) ->
551    {Gis,St1} = guard_cg(G, Fail, St0),
552    {Bis,St} = match_cg(B, Fail, St1),
553    {Gis ++ Bis,St}.
554
555%% guard_cg(Guard, Fail, State) -> {[Ainstr],State}.
556%%  A guard is a boolean expression of tests.  Tests return true or
557%%  false.  A fault in a test causes the test to return false.  Tests
558%%  never return the boolean, instead we generate jump code to go to
559%%  the correct exit point.  Primops and tests all go to the next
560%%  instruction on success or jump to a failure label.
561
562guard_cg(#k_try{arg=Ts,vars=[],body=#k_break{args=[]},
563                evars=[],handler=#k_break{args=[]}},
564         Fail,
565         #cg{bfail=OldBfail,break=OldBreak}=St0) ->
566    %% Do a try/catch without return value for effect. The return
567    %% value is not checked; success passes on to the next instruction
568    %% and failure jumps to Fail.
569    {Next,St1} = new_label(St0),
570    {Tis,St2} = guard_cg(Ts, Fail, St1#cg{bfail=Fail,break=Next}),
571    Is = Tis ++ [{label,Next},#cg_phi{vars=[]}],
572    {Is,St2#cg{bfail=OldBfail,break=OldBreak}};
573guard_cg(#k_test{op=Test0,args=As}, Fail, St0) ->
574    #k_remote{mod=#k_literal{val=erlang},name=#k_literal{val=Test}} = Test0,
575    test_cg(Test, false, As, Fail, St0);
576guard_cg(#k_seq{arg=Arg,body=Body}, Fail, St0) ->
577    {ArgIs,St1} = guard_cg(Arg, Fail, St0),
578    {BodyIs,St} = guard_cg(Body, Fail, St1),
579    {ArgIs++BodyIs,St};
580guard_cg(G, _Fail, St) ->
581    cg(G, St).
582
583test_cg('=/=', Inverted, As, Fail, St) ->
584    test_cg('=:=', not Inverted, As, Fail, St);
585test_cg('/=', Inverted, As, Fail, St) ->
586    test_cg('==', not Inverted, As, Fail, St);
587test_cg(Test, Inverted, As0, Fail, St0) ->
588    As = ssa_args(As0, St0),
589    case {Test,ssa_args(As0, St0)} of
590        {is_record,[Tuple,#b_literal{val=Atom}=Tag,#b_literal{val=Int}=Arity]}
591          when is_atom(Atom), is_integer(Int) ->
592            false = Inverted,                   %Assertion.
593            test_is_record_cg(Fail, Tuple, Tag, Arity, St0);
594        {_,As} ->
595            {Bool,St1} = new_ssa_var('@ssa_bool', St0),
596            {Succ,St} = new_label(St1),
597            Bif = #b_set{op={bif,Test},dst=Bool,args=As},
598            Br = case Inverted of
599                     false -> #b_br{bool=Bool,succ=Succ,fail=Fail};
600                     true -> #b_br{bool=Bool,succ=Fail,fail=Succ}
601                 end,
602            {[Bif,Br,{label,Succ}],St}
603    end.
604
605test_is_record_cg(Fail, Tuple, TagVal, ArityVal, St0) ->
606    {Arity,St1} = new_ssa_var('@ssa_arity', St0),
607    {Tag,St2} = new_ssa_var('@ssa_tag', St1),
608    {Is0,St3} = make_cond_branch({bif,is_tuple}, [Tuple], Fail, St2),
609    GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
610    {Is1,St4} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], Fail, St3),
611    GetTag = #b_set{op=get_tuple_element,dst=Tag,
612                    args=[Tuple,#b_literal{val=0}]},
613    {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], Fail, St4),
614    Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2,
615    {Is,St}.
616
617%% match_fmf(Fun, LastFail, State, [Clause]) -> {Is,State}.
618%%  This is a special flatmapfoldl for match code gen where we
619%%  generate a "failure" label for each clause. The last clause uses
620%%  an externally generated failure label, LastFail.  N.B. We do not
621%%  know or care how the failure labels are used.
622
623match_fmf(F, LastFail, St, [H]) ->
624    F(H, LastFail, St);
625match_fmf(F, LastFail, St0, [H|T]) ->
626    {Fail,St1} = new_label(St0),
627    {R,St2} = F(H, Fail, St1),
628    {Rs,St3} = match_fmf(F, LastFail, St2, T),
629    {R ++ [{label,Fail}] ++ Rs,St3}.
630
631%% fail_context(State) -> {Where,FailureLabel}.
632%%       Where = guard | no_catch | in_catch
633%%  Return an indication of which part of a function code is
634%%  being generated for and the appropriate failure label to
635%%  use.
636%%
637%%  Where has the following meaning:
638%%
639%%     guard     - Inside a guard.
640%%     no_catch  - In a function body, not in the scope of
641%%                 a try/catch or catch.
642%%     in_catch  - In the scope of a try/catch or catch.
643
644fail_context(#cg{catch_label=Catch,bfail=Fail,ultimate_failure=Ult}) ->
645    if
646        Fail =/= Ult ->
647            {guard,Fail};
648        Catch =:= none ->
649            {no_catch,Fail};
650        is_integer(Catch) ->
651            {in_catch,Catch}
652    end.
653
654%% call_cg(Func, [Arg], [Ret], Le, State) ->
655%%      {[Ainstr],State}.
656%% enter_cg(Func, [Arg], Le, St) -> {[Ainstr],St}.
657%%  Generate code for call and enter.
658
659call_cg(Func, As, [], Le, St) ->
660    call_cg(Func, As, [#k_var{name='@ssa_ignored'}], Le, St);
661call_cg(Func, As, [#k_var{name=R}|MoreRs]=Rs, Le, St0) ->
662    case fail_context(St0) of
663        {guard,Fail} ->
664            %% Inside a guard. The only allowed function call is to
665            %% erlang:error/1,2. We will generate a branch to the
666            %% failure branch.
667            #k_remote{mod=#k_literal{val=erlang},
668                      name=#k_literal{val=error}} = Func, %Assertion.
669            St = set_unused_ssa_vars(Rs, St0),
670            {[make_uncond_branch(Fail),#cg_unreachable{}],St};
671        FailCtx ->
672            %% Ordinary function call in a function body.
673            Args = ssa_args([Func|As], St0),
674            {Ret,St1} = new_ssa_var(R, St0),
675            Call = #b_set{anno=line_anno(Le),op=call,dst=Ret,args=Args},
676
677            %% If this is a call to erlang:error(), MoreRs could be a
678            %% nonempty list of variables that each need a value.
679            St2 = set_unused_ssa_vars(MoreRs, St1),
680
681            {TestIs,St} = make_succeeded(Ret, FailCtx, St2),
682            {[Call|TestIs],St}
683    end.
684
685enter_cg(Func, As0, Le, St0) ->
686    As = ssa_args([Func|As0], St0),
687    {Ret,St} = new_ssa_var('@ssa_ret', St0),
688    Call = #b_set{anno=line_anno(Le),op=call,dst=Ret,args=As},
689    {[Call,#b_ret{arg=Ret}],St}.
690
691%% bif_cg(#k_bif{}, Le,State) -> {[Ainstr],State}.
692%%  Generate code for a guard BIF or primop.
693
694bif_cg(#k_bif{anno=A,op=#k_internal{name=Name},args=As,ret=Rs}, _Le, St) ->
695    internal_cg(line_anno(A), Name, As, Rs, St);
696bif_cg(#k_bif{op=#k_remote{mod=#k_literal{val=erlang},name=#k_literal{val=Name}},
697              args=As,ret=Rs}, Le, St) ->
698    bif_cg(Name, As, Rs, Le, St).
699
700%% internal_cg(Bif, [Arg], [Ret], Le, State) ->
701%%      {[Ainstr],State}.
702
703internal_cg(_Anno, Op0, As, [#k_var{name=Dst0}], St0)
704  when Op0 =:= raise; Op0 =:= raw_raise ->
705    Args = ssa_args(As, St0),
706    Op = fix_op(Op0, St0),
707    {Dst,St} = new_ssa_var(Dst0, St0),
708    Set = #b_set{op=Op,dst=Dst,args=Args},
709    case fail_context(St) of
710        {no_catch,_Fail} ->
711            %% No current catch in this function. Follow the raw_raise/resume
712            %% instruction by a return (instead of branching to
713            %% ?EXCEPTION_MARKER) to ensure that the trim optimization can be
714            %% applied. (Allowing control to pass through to the next
715            %% instruction would mean that the type for the try/catch construct
716            %% would be `any`.)
717            Is = [Set,#b_ret{arg=Dst},#cg_unreachable{}],
718            {Is,St};
719        {in_catch,Fail} ->
720            Is = [Set,make_uncond_branch(Fail),#cg_unreachable{}],
721            {Is,St}
722    end;
723internal_cg(Anno, recv_peek_message, [], [#k_var{name=Succeeded0},
724                                          #k_var{name=Dst0}], St0) ->
725    {Dst,St1} = new_ssa_var(Dst0, St0),
726    St = new_succeeded_value(Succeeded0, Dst, St1),
727    Set = #b_set{ anno=Anno,
728                  op=peek_message,
729                  dst=Dst,
730                  args=[#b_literal{val=none}] },
731    {[Set],St};
732internal_cg(_Anno, recv_wait_timeout, As, [#k_var{name=Succeeded0}], St0) ->
733    %% Note that the `wait_timeout` instruction can potentially branch in three
734    %% different directions:
735    %%
736    %% * A new message is available in the message queue. `wait_timeout`
737    %%   branches to the given label.
738    %%
739    %% * The timeout expired. `wait_timeout` transfers control to the next
740    %%   instruction.
741    %%
742    %% * The value for timeout duration is invalid (either not an integer or
743    %%   negative or too large). A `timeout_value` exception will be raised.
744    %%
745    %% `wait_timeout` will be represented like this in SSA code:
746    %%
747    %%       WaitBool = wait_timeout TimeoutValue
748    %%       Succeeded = succeeded:body WaitBool
749    %%       br Succeeded, ^good_timeout_value, ^bad_timeout_value
750    %%
751    %%   good_timeout_value:
752    %%       br WaitBool, ^timeout_expired, ^new_message_received
753    %%
754    Args = ssa_args(As, St0),
755    {Wait,St1} = new_ssa_var('@ssa_wait', St0),
756    {Succ,St2} = make_succeeded(Wait, fail_context(St1), St1),
757    St = new_bool_value(Succeeded0, Wait, St2),
758    Set = #b_set{op=wait_timeout,dst=Wait,args=Args},
759    {[Set|Succ],St};
760internal_cg(Anno, Op0, As, [#k_var{name=Dst0}], St0) when is_atom(Op0) ->
761    %% This behaves like a function call.
762    {Dst,St} = new_ssa_var(Dst0, St0),
763    Args = ssa_args(As, St),
764    Op = fix_op(Op0, St),
765    Set = #b_set{anno=Anno,op=Op,dst=Dst,args=Args},
766    {[Set],St};
767internal_cg(Anno, Op0, As, [], St0) when is_atom(Op0) ->
768    %% This behaves like a function call.
769    {Dst,St} = new_ssa_var('@ssa_ignored', St0),
770    Args = ssa_args(As, St),
771    Op = fix_op(Op0, St),
772    Set = #b_set{anno=Anno,op=Op,dst=Dst,args=Args},
773    {[Set],St}.
774
775fix_op(make_fun, #cg{no_make_fun3=true}) -> old_make_fun;
776fix_op(raise, _) -> resume;
777fix_op(Op, _) -> Op.
778
779bif_cg(Bif, As0, [#k_var{name=Dst0}], Le, St0) ->
780    {Dst,St1} = new_ssa_var(Dst0, St0),
781    case {Bif,ssa_args(As0, St0)} of
782        {is_record,[Tuple,#b_literal{val=Atom}=Tag,
783                    #b_literal{val=Int}=Arity]}
784          when is_atom(Atom), is_integer(Int) ->
785            bif_is_record_cg(Dst, Tuple, Tag, Arity, St1);
786        {_,As} ->
787            I = #b_set{anno=line_anno(Le),op={bif,Bif},dst=Dst,args=As},
788            case erl_bifs:is_safe(erlang, Bif, length(As)) of
789                false ->
790                    FailCtx = fail_context(St1),
791                    {Is,St} = make_succeeded(Dst, FailCtx, St1),
792                    {[I|Is],St};
793                true->
794                    {[I],St1}
795            end
796        end.
797
798bif_is_record_cg(Dst, Tuple, TagVal, ArityVal, St0) ->
799    {Arity,St1} = new_ssa_var('@ssa_arity', St0),
800    {Tag,St2} = new_ssa_var('@ssa_tag', St1),
801    {Phi,St3} = new_label(St2),
802    {False,St4} = new_label(St3),
803    {Is0,St5} = make_cond_branch({bif,is_tuple}, [Tuple], False, St4),
804    GetArity = #b_set{op={bif,tuple_size},dst=Arity,args=[Tuple]},
805    {Is1,St6} = make_cond_branch({bif,'=:='}, [Arity,ArityVal], False, St5),
806    GetTag = #b_set{op=get_tuple_element,dst=Tag,
807                    args=[Tuple,#b_literal{val=0}]},
808    {Is2,St} = make_cond_branch({bif,'=:='}, [Tag,TagVal], False, St6),
809    Is3 = [#cg_break{args=[#b_literal{val=true}],phi=Phi},
810           {label,False},
811           #cg_break{args=[#b_literal{val=false}],phi=Phi},
812           {label,Phi},
813           #cg_phi{vars=[Dst]}],
814    Is = Is0 ++ [GetArity] ++ Is1 ++ [GetTag] ++ Is2 ++ Is3,
815    {Is,St}.
816
817%% try_cg(TryBlock, [BodyVar], TryBody, [ExcpVar], TryHandler, [Ret], St) ->
818%%         {[Ainstr],St}.
819
820try_cg(Ta, Vs, Tb, Evs, Th, Rs, St0) ->
821    {B,St1} = new_label(St0),			%Body label
822    {H,St2} = new_label(St1),			%Handler label
823    {E,St3} = new_label(St2),			%End label
824    {Next,St4} = new_label(St3),
825    {TryTag,St5} = new_ssa_var('@ssa_catch_tag', St4),
826    {SsaVs,St6} = new_ssa_vars(Vs, St5),
827    {SsaEvs,St7} = new_ssa_vars(Evs, St6),
828    {Ais,St8} = cg(Ta, St7#cg{break=B,catch_label=H}),
829
830    %% We try to avoid constructing a try/catch if the expression to
831    %% be evaluated don't have any side effects and if the error
832    %% reason is not explicitly matched.
833    %%
834    %% Starting in OTP 23, segment sizes in binary matching and keys
835    %% in map matching are allowed to be arbitrary guard
836    %% expressions. Those expressions are evaluated in a try/catch
837    %% so that matching can continue with the next clause if the evaluation
838    %% of such expression fails.
839    %%
840    %% It is not allowed to use try/catch during matching in a receive
841    %% (the try/catch would force the saving of fragile message references
842    %% to the stack frame). Therefore, avoiding creating try/catch is
843    %% not merely an optimization but necessary for correctness.
844
845    case {Vs,Tb,Th,is_guard_cg_safe_list(Ais)} of
846        {[#k_var{name=X}],#k_break{args=[#k_var{name=X}]},
847         #k_break{args=[#k_literal{}]},true} ->
848            %% There are no instructions that will clobber X registers
849            %% and the exception is not matched. Therefore, a
850            %% try/catch is not needed. This code is probably located
851            %% in a guard.
852            {ProtIs,St9} = guard_cg(Ta, H, St7#cg{break=B,bfail=H}),
853            {His,St10} = cg(Th, St9),
854            {RetVars,St} = new_ssa_vars(Rs, St10),
855            Is = ProtIs ++ [{label,H}] ++ His ++
856                [{label,B},#cg_phi{vars=RetVars}],
857            {Is,St#cg{break=St0#cg.break,bfail=St7#cg.bfail}};
858        {[#k_var{name=X}],#k_break{args=[#k_literal{}=SuccLit0,#k_var{name=X}]},
859         #k_break{args=[#k_literal{val=false},#k_literal{}]},true} ->
860            %% There are no instructions that will clobber X registers
861            %% and the exception is not matched. Therefore, a
862            %% try/catch is not needed. This code probably evaluates
863            %% a key expression in map matching.
864            {FinalLabel,St9} = new_label(St7),
865            {ProtIs,St10} = guard_cg(Ta, H, St9#cg{break=B,bfail=H}),
866            {His,St11} = cg(Th, St10#cg{break=FinalLabel}),
867            {RetVars,St12} = new_ssa_vars(Rs, St11),
868            {Result,St} = new_ssa_var('@ssa_result', St12),
869            SuccLit = ssa_arg(SuccLit0, St),
870            Is = ProtIs ++ [{label,H}] ++ His ++
871                [{label,B},
872                 #cg_phi{vars=[Result]},
873                 #cg_break{args=[SuccLit,Result],phi=FinalLabel},
874                 {label,FinalLabel},
875                 #cg_phi{vars=RetVars}],
876            {Is,St#cg{break=St0#cg.break,bfail=St7#cg.bfail}};
877        {_,#k_break{args=[]},#k_break{args=[]},true} ->
878            %% There are no instructions that will clobber X registers
879            %% and the exception is not matched. Therefore, a
880            %% try/catch is not needed. This code probably does the
881            %% size calculation for a segment in binary matching.
882            {ProtIs,St9} = guard_cg(Ta, H, St7#cg{break=B,bfail=H}),
883            {His,St10} = cg(Th, St9),
884            {RetVars,St} = new_ssa_vars(Rs, St10),
885            Is = ProtIs ++ [{label,H}] ++ His ++
886                [{label,B},#cg_phi{vars=RetVars}],
887            {Is,St#cg{break=St0#cg.break,bfail=St7#cg.bfail}};
888        {_,_,_,_} ->
889            %% The general try/catch (not in a guard).
890            St9 = St8#cg{break=E,catch_label=St7#cg.catch_label},
891            {Bis,St10} = cg(Tb, St9),
892            {His,St11} = cg(Th, St10),
893            {BreakVars,St12} = new_ssa_vars(Rs, St11),
894            {CatchedAgg,St13} = new_ssa_var('@ssa_agg', St12),
895            ExtractVs = extract_vars(SsaEvs, CatchedAgg, 0),
896            KillTryTag = #b_set{op=kill_try_tag,args=[TryTag]},
897            Args = [#b_literal{val='try'},TryTag],
898            Handler = [{label,H},
899                       #b_set{op=landingpad,dst=CatchedAgg,args=Args}] ++
900                ExtractVs ++ [KillTryTag],
901            {[#b_set{op=new_try_tag,dst=TryTag,args=[#b_literal{val='try'}]},
902              #b_br{bool=TryTag,succ=Next,fail=H},
903              {label,Next}] ++ Ais ++
904                 [{label,B},#cg_phi{vars=SsaVs},KillTryTag] ++ Bis ++
905                 Handler ++ His ++
906                 [{label,E},#cg_phi{vars=BreakVars}],
907             St13#cg{break=St0#cg.break}}
908    end.
909
910is_guard_cg_safe_list(Is) ->
911    all(fun is_guard_cg_safe/1, Is).
912
913is_guard_cg_safe(#b_set{op=call,args=Args}) ->
914    case Args of
915        [#b_remote{mod=#b_literal{val=erlang},
916                   name=#b_literal{val=error},
917                   arity=1}|_] ->
918            true;
919        _ ->
920            false
921    end;
922is_guard_cg_safe(#b_set{}=I) -> not beam_ssa:clobbers_xregs(I);
923is_guard_cg_safe(#b_br{}) -> true;
924is_guard_cg_safe(#b_switch{}) -> true;
925is_guard_cg_safe(#cg_break{}) -> true;
926is_guard_cg_safe(#cg_phi{}) -> true;
927is_guard_cg_safe({label,_}) -> true;
928is_guard_cg_safe(#cg_unreachable{}) -> false.
929
930try_enter_cg(Ta, Vs, Tb, Evs, Th, St0) ->
931    {B,St1} = new_label(St0),			%Body label
932    {H,St2} = new_label(St1),			%Handler label
933    {Next,St3} = new_label(St2),
934    {TryTag,St4} = new_ssa_var('@ssa_catch_tag', St3),
935    {SsaVs,St5} = new_ssa_vars(Vs, St4),
936    {SsaEvs,St6} = new_ssa_vars(Evs, St5),
937    {Ais,St7} = cg(Ta, St6#cg{break=B,catch_label=H}),
938    St8 = St7#cg{catch_label=St6#cg.catch_label},
939    {Bis,St9} = cg(Tb, St8),
940    {His,St10} = cg(Th, St9),
941    {CatchedAgg,St} = new_ssa_var('@ssa_agg', St10),
942    ExtractVs = extract_vars(SsaEvs, CatchedAgg, 0),
943    KillTryTag = #b_set{op=kill_try_tag,args=[TryTag]},
944    Args = [#b_literal{val='try'},TryTag],
945    Handler = [{label,H},
946               #b_set{op=landingpad,dst=CatchedAgg,args=Args}] ++
947        ExtractVs ++ [KillTryTag],
948    {[#b_set{op=new_try_tag,dst=TryTag,args=[#b_literal{val='try'}]},
949      #b_br{bool=TryTag,succ=Next,fail=H},
950      {label,Next}] ++  Ais ++
951         [{label,B},#cg_phi{vars=SsaVs},KillTryTag] ++ Bis ++
952         Handler ++ His,
953     St#cg{break=St0#cg.break}}.
954
955extract_vars([V|Vs], Agg, N) ->
956    I = #b_set{op=extract,dst=V,args=[Agg,#b_literal{val=N}]},
957    [I|extract_vars(Vs, Agg, N+1)];
958extract_vars([], _, _) -> [].
959
960%% do_catch_cg(CatchBlock, Ret, St) -> {[Ainstr],St}.
961
962do_catch_cg(Block, #k_var{name=R}, St0) ->
963    {B,St1} = new_label(St0),
964    {Next,St2} = new_label(St1),
965    {H,St3} = new_label(St2),
966    {CatchReg,St4} = new_ssa_var('@ssa_catch_tag', St3),
967    {Dst,St5} = new_ssa_var(R, St4),
968    {Succ,St6} = new_label(St5),
969    {Cis,St7} = cg(Block, St6#cg{break=Succ,catch_label=H}),
970    {CatchedVal,St8} = new_ssa_var('@catched_val', St7),
971    {SuccVal,St9} = new_ssa_var('@success_val', St8),
972    {CatchedAgg,St10} = new_ssa_var('@ssa_agg', St9),
973    {CatchEndVal,St} = new_ssa_var('@catch_end_val', St10),
974    Args = [#b_literal{val='catch'},CatchReg],
975    {[#b_set{op=new_try_tag,dst=CatchReg,args=[#b_literal{val='catch'}]},
976      #b_br{bool=CatchReg,succ=Next,fail=H},
977      {label,Next}] ++ Cis ++
978         [{label,H},
979          #b_set{op=landingpad,dst=CatchedAgg,args=Args},
980          #b_set{op=extract,dst=CatchedVal,
981                 args=[CatchedAgg,#b_literal{val=0}]},
982          #cg_break{args=[CatchedVal],phi=B},
983          {label,Succ},
984          #cg_phi{vars=[SuccVal]},
985          #cg_break{args=[SuccVal],phi=B},
986          {label,B},#cg_phi{vars=[CatchEndVal]},
987          #b_set{op=catch_end,dst=Dst,args=[CatchReg,CatchEndVal]}],
988     St#cg{break=St1#cg.break,catch_label=St1#cg.catch_label}}.
989
990%% put_cg([Var], Constr, Le, Vdb, Bef, St) -> {[Ainstr],St}.
991%%  Generate code for constructing terms.
992
993put_cg([#k_var{name=R}], #k_cons{hd=Hd,tl=Tl}, _Le, St0) ->
994    Args = ssa_args([Hd,Tl], St0),
995    {Dst,St} = new_ssa_var(R, St0),
996    PutList = #b_set{op=put_list,dst=Dst,args=Args},
997    {[PutList],St};
998put_cg([#k_var{name=R}], #k_tuple{es=Es}, _Le, St0) ->
999    {Ret,St} = new_ssa_var(R, St0),
1000    Args = ssa_args(Es, St),
1001    PutTuple = #b_set{op=put_tuple,dst=Ret,args=Args},
1002    {[PutTuple],St};
1003put_cg([#k_var{name=R}], #k_binary{segs=Segs}, Le, St0) ->
1004    FailCtx = fail_context(St0),
1005    {Dst,St1} = new_ssa_var(R, St0),
1006    cg_binary(Dst, Segs, FailCtx, Le, St1);
1007put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,
1008                                es=[#k_map_pair{key=#k_var{}=K,val=V}]},
1009       Le, St0) ->
1010    %% Map: single variable key.
1011    SrcMap = ssa_arg(Map, St0),
1012    LineAnno = line_anno(Le),
1013    List = [ssa_arg(K, St0),ssa_arg(V, St0)],
1014    {Dst,St1} = new_ssa_var(R, St0),
1015    {Is,St} = put_cg_map(LineAnno, Op, SrcMap, Dst, List, St1),
1016    {Is,St};
1017put_cg([#k_var{name=R}], #k_map{op=Op,var=Map,es=Es}, Le, St0) ->
1018    %% Map: one or more literal keys.
1019    [] = [Var || #k_map_pair{key=#k_var{}=Var} <- Es], %Assertion
1020    SrcMap = ssa_arg(Map, St0),
1021    LineAnno = line_anno(Le),
1022    List = flatmap(fun(#k_map_pair{key=K,val=V}) ->
1023                           [ssa_arg(K, St0),ssa_arg(V, St0)]
1024                   end, Es),
1025    {Dst,St1} = new_ssa_var(R, St0),
1026    {Is,St} = put_cg_map(LineAnno, Op, SrcMap, Dst, List, St1),
1027    {Is,St};
1028put_cg([#k_var{name=R}], Con0, _Le, St0) ->
1029    %% Create an alias for a variable or literal.
1030    Con = ssa_arg(Con0, St0),
1031    St = set_ssa_var(R, Con, St0),
1032    {[],St}.
1033
1034put_cg_map(LineAnno, Op, SrcMap, Dst, List, St0) ->
1035    Args = [#b_literal{val=Op},SrcMap|List],
1036    PutMap = #b_set{anno=LineAnno,op=put_map,dst=Dst,args=Args},
1037    if
1038        Op =:= assoc ->
1039            {[PutMap],St0};
1040        true ->
1041            FailCtx = fail_context(St0),
1042            {Is,St} = make_succeeded(Dst, FailCtx, St0),
1043            {[PutMap|Is],St}
1044    end.
1045
1046%%%
1047%%% Code generation for constructing binaries.
1048%%%
1049
1050cg_binary(Dst, Segs0, FailCtx, Le, St0) ->
1051    {PutCode0,SzCalc0,St1} = cg_bin_put(Segs0, FailCtx, St0),
1052    LineAnno = line_anno(Le),
1053    Anno = Le,
1054    case PutCode0 of
1055        [#b_set{op=bs_put,dst=Bin,args=[_,_,Src,#b_literal{val=all}|_]},
1056         #b_set{op={succeeded,_},dst=Bool,args=[Bin]},
1057         #b_br{bool=Bool},
1058         {label,_}|_] ->
1059            #k_bin_seg{unit=Unit0,next=Segs} = Segs0,
1060            Unit = #b_literal{val=Unit0},
1061            {PutCode,SzCalc1,St2} = cg_bin_put(Segs, FailCtx, St1),
1062            {_,SzVar,SzCode0,St3} = cg_size_calc(1, SzCalc1, FailCtx, St2),
1063            SzCode = cg_bin_anno(SzCode0, LineAnno),
1064            Args = case member(single_use, Anno) of
1065                       true ->
1066                           [#b_literal{val=private_append},Src,SzVar,Unit];
1067                       false ->
1068                           [#b_literal{val=append},Src,SzVar,Unit]
1069                   end,
1070            BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args},
1071            {TestIs,St} = make_succeeded(Dst, FailCtx, St3),
1072            {SzCode ++ [BsInit] ++ TestIs ++ PutCode,St};
1073        [#b_set{op=bs_put}|_] ->
1074            {Unit,SzVar,SzCode0,St2} = cg_size_calc(8, SzCalc0, FailCtx, St1),
1075            SzCode = cg_bin_anno(SzCode0, LineAnno),
1076            Args = [#b_literal{val=new},SzVar,Unit],
1077            BsInit = #b_set{anno=LineAnno,op=bs_init,dst=Dst,args=Args},
1078            {TestIs,St} = make_succeeded(Dst, FailCtx, St2),
1079            {SzCode ++ [BsInit] ++ TestIs ++ PutCode0,St}
1080    end.
1081
1082cg_bin_anno([Set|Sets], Anno) ->
1083    [Set#b_set{anno=Anno}|Sets];
1084cg_bin_anno([], _) -> [].
1085
1086%% cg_size_calc(PreferredUnit, SzCalc, FailCtx, St0) ->
1087%%         {ActualUnit,SizeVariable,SizeCode,St}.
1088%%  Generate size calculation code.
1089
1090cg_size_calc(Unit, error, _FailCtx, St) ->
1091    {#b_literal{val=Unit},#b_literal{val=badarg},[],St};
1092cg_size_calc(8, [{1,_}|_]=SzCalc, FailCtx, St) ->
1093    cg_size_calc(1, SzCalc, FailCtx, St);
1094cg_size_calc(8, SzCalc, FailCtx, St0) ->
1095    {Var,Pre,St} = cg_size_calc_1(SzCalc, FailCtx, St0),
1096    {#b_literal{val=8},Var,Pre,St};
1097cg_size_calc(1, SzCalc0, FailCtx, St0) ->
1098    SzCalc = map(fun({8,#b_literal{val=Size}}) ->
1099                         {1,#b_literal{val=8*Size}};
1100                    ({8,{{bif,byte_size},Src}}) ->
1101                         {1,{{bif,bit_size},Src}};
1102                    ({8,{_,_}=UtfCalc}) ->
1103                         {1,{'*',#b_literal{val=8},UtfCalc}};
1104                    ({_,_}=Pair) ->
1105                         Pair
1106                 end, SzCalc0),
1107    {Var,Pre,St} = cg_size_calc_1(SzCalc, FailCtx, St0),
1108    {#b_literal{val=1},Var,Pre,St}.
1109
1110cg_size_calc_1(SzCalc, FailCtx, St0) ->
1111    cg_size_calc_2(SzCalc, #b_literal{val=0}, FailCtx, St0).
1112
1113cg_size_calc_2([{_,{'*',Unit,{_,_}=Bif}}|T], Sum0, FailCtx, St0) ->
1114    {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0),
1115    {BifDst,Pre1,St2} = cg_size_bif(Bif, FailCtx, St1),
1116    {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, Unit, FailCtx, St2),
1117    {Sum,Pre0++Pre1++Pre2,St};
1118cg_size_calc_2([{_,#b_literal{}=Sz}|T], Sum0, FailCtx, St0) ->
1119    {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0),
1120    {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, FailCtx, St1),
1121    {Sum,Pre0++Pre,St};
1122cg_size_calc_2([{_,#b_var{}=Sz}|T], Sum0, FailCtx, St0) ->
1123    {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0),
1124    {Sum,Pre,St} = cg_size_add(Sum1, Sz, #b_literal{val=1}, FailCtx, St1),
1125    {Sum,Pre0++Pre,St};
1126cg_size_calc_2([{_,{_,_}=Bif}|T], Sum0, FailCtx, St0) ->
1127    {Sum1,Pre0,St1} = cg_size_calc_2(T, Sum0, FailCtx, St0),
1128    {BifDst,Pre1,St2} = cg_size_bif(Bif, FailCtx, St1),
1129    {Sum,Pre2,St} = cg_size_add(Sum1, BifDst, #b_literal{val=1}, FailCtx, St2),
1130    {Sum,Pre0++Pre1++Pre2,St};
1131cg_size_calc_2([], Sum, _FailCtx, St) ->
1132    {Sum,[],St}.
1133
1134cg_size_bif(#b_var{}=Var, _FailCtx, St) ->
1135    {Var,[],St};
1136cg_size_bif({Name,Src}, FailCtx, St0) ->
1137    {Dst,St1} = new_ssa_var('@ssa_bif', St0),
1138    Bif = #b_set{op=Name,dst=Dst,args=[Src]},
1139    {TestIs,St} = make_succeeded(Dst, FailCtx, St1),
1140    {Dst,[Bif|TestIs],St}.
1141
1142cg_size_add(#b_literal{val=0}, Val, #b_literal{val=1}, _FailCtx, St) ->
1143    {Val,[],St};
1144cg_size_add(#b_literal{val=A}, #b_literal{val=B}, #b_literal{val=U}, _FailCtx, St) ->
1145    {#b_literal{val=A+B*U},[],St};
1146cg_size_add(A, B, Unit, FailCtx, St0) ->
1147    {Dst,St1} = new_ssa_var('@ssa_sum', St0),
1148    {TestIs,St} = make_succeeded(Dst, FailCtx, St1),
1149    BsAdd = #b_set{op=bs_add,dst=Dst,args=[A,B,Unit]},
1150    {Dst,[BsAdd|TestIs],St}.
1151
1152cg_bin_put(Seg, FailCtx, St) ->
1153    cg_bin_put_1(Seg, FailCtx, [], [], St).
1154
1155cg_bin_put_1(#k_bin_seg{size=Size0,unit=U,type=T,flags=Fs,seg=Src0,next=Next},
1156             FailCtx, Acc, SzCalcAcc, St0) ->
1157    [Src,Size] = ssa_args([Src0,Size0], St0),
1158    NeedSize = bs_need_size(T),
1159    TypeArg = #b_literal{val=T},
1160    Flags = #b_literal{val=Fs},
1161    Unit = #b_literal{val=U},
1162    Args = case NeedSize of
1163               true -> [TypeArg,Flags,Src,Size,Unit];
1164               false -> [TypeArg,Flags,Src]
1165           end,
1166    {Dst,St1} = new_ssa_var('@ssa_bs_put', St0),
1167    {TestIs,St} = make_succeeded(Dst, FailCtx, St1),
1168    Is = [#b_set{op=bs_put,dst=Dst,args=Args}|TestIs],
1169    SzCalc = bin_size_calc(T, Src, Size, U),
1170    cg_bin_put_1(Next, FailCtx, reverse(Is, Acc), [SzCalc|SzCalcAcc], St);
1171cg_bin_put_1(#k_bin_end{}, _, Acc, SzCalcAcc, St) ->
1172    SzCalc = fold_size_calc(SzCalcAcc, 0, []),
1173    {reverse(Acc),SzCalc,St}.
1174
1175bs_need_size(utf8) -> false;
1176bs_need_size(utf16) -> false;
1177bs_need_size(utf32) -> false;
1178bs_need_size(_) -> true.
1179
1180bin_size_calc(utf8, Src, _Size, _Unit) ->
1181    {8,{bs_utf8_size,Src}};
1182bin_size_calc(utf16, Src, _Size, _Unit) ->
1183    {8,{bs_utf16_size,Src}};
1184bin_size_calc(utf32, _Src, _Size, _Unit) ->
1185    {8,#b_literal{val=4}};
1186bin_size_calc(binary, Src, #b_literal{val=all}, Unit) ->
1187    case Unit rem 8 of
1188        0 -> {8,{{bif,byte_size},Src}};
1189        _ -> {1,{{bif,bit_size},Src}}
1190    end;
1191bin_size_calc(_Type, _Src, Size, Unit) ->
1192    {Unit,Size}.
1193
1194fold_size_calc([{Unit,#b_literal{val=Size}}|T], Bits, Acc) ->
1195    if
1196        is_integer(Size) ->
1197            fold_size_calc(T, Bits + Unit*Size, Acc);
1198        true ->
1199            error
1200    end;
1201fold_size_calc([{U,#b_var{}}=H|T], Bits, Acc) when U =:= 1; U =:= 8 ->
1202    fold_size_calc(T, Bits, [H|Acc]);
1203fold_size_calc([{U,#b_var{}=Var}|T], Bits, Acc) ->
1204    fold_size_calc(T, Bits, [{1,{'*',#b_literal{val=U},Var}}|Acc]);
1205fold_size_calc([{_,_}=H|T], Bits, Acc) ->
1206    fold_size_calc(T, Bits, [H|Acc]);
1207fold_size_calc([], Bits, Acc) ->
1208    Bytes = Bits div 8,
1209    RemBits = Bits rem 8,
1210    Sizes = sort([{1,#b_literal{val=RemBits}},{8,#b_literal{val=Bytes}}|Acc]),
1211    [Pair || {_,Sz}=Pair <- Sizes, Sz =/= #b_literal{val=0}].
1212
1213%%%
1214%%% Utilities for creating the SSA types.
1215%%%
1216
1217ssa_args(As, St) ->
1218    [ssa_arg(A, St) || A <- As].
1219
1220ssa_arg(#k_var{name=V}, #cg{vars=Vars}) -> map_get(V, Vars);
1221ssa_arg(#k_literal{val=V}, _) -> #b_literal{val=V};
1222ssa_arg(#k_remote{mod=Mod0,name=Name0,arity=Arity}, St) ->
1223    Mod = ssa_arg(Mod0, St),
1224    Name = ssa_arg(Name0, St),
1225    #b_remote{mod=Mod,name=Name,arity=Arity};
1226ssa_arg(#k_local{name=Name,arity=Arity}, _) when is_atom(Name) ->
1227    #b_local{name=#b_literal{val=Name},arity=Arity}.
1228
1229new_succeeded_value(VarBase, Var, #cg{vars=Vars0}=St) ->
1230    Vars = Vars0#{VarBase=>{succeeded,Var}},
1231    St#cg{vars=Vars}.
1232
1233new_bool_value(VarBase, Var, #cg{vars=Vars0}=St) ->
1234    Vars = Vars0#{VarBase=>{bool,Var}},
1235    St#cg{vars=Vars}.
1236
1237new_ssa_vars(Vs, St) ->
1238    mapfoldl(fun(#k_var{name=V}, S) ->
1239                     new_ssa_var(V, S)
1240             end, St, Vs).
1241
1242new_ssa_var(VarBase, #cg{lcount=Uniq,vars=Vars}=St0)
1243  when is_atom(VarBase); is_integer(VarBase) ->
1244    case Vars of
1245        #{VarBase:=_} ->
1246            Var = #b_var{name={VarBase,Uniq}},
1247            St = St0#cg{lcount=Uniq+1,vars=Vars#{VarBase=>Var}},
1248            {Var,St};
1249        #{} ->
1250            Var = #b_var{name=VarBase},
1251            St = St0#cg{vars=Vars#{VarBase=>Var}},
1252            {Var,St}
1253    end.
1254
1255set_unused_ssa_vars(Vars, St) ->
1256    foldl(fun(#k_var{name=V}, S) ->
1257                  set_ssa_var(V, #b_literal{val=unused}, S)
1258          end, St, Vars).
1259
1260set_ssa_var(VarBase, Val, #cg{vars=Vars}=St)
1261  when is_atom(VarBase); is_integer(VarBase) ->
1262    St#cg{vars=Vars#{VarBase=>Val}}.
1263
1264%% new_label(St) -> {L,St}.
1265
1266new_label(#cg{lcount=Next}=St) ->
1267    {Next,St#cg{lcount=Next+1}}.
1268
1269%% line_anno(Le) -> #{} | #{location:={File,Line}}.
1270%%  Create a location annotation, containing information about the
1271%%  current filename and line number.  The annotation should be
1272%%  included in any operation that could cause an exception.
1273
1274line_anno([Line,{file,Name}]) when is_integer(Line) ->
1275    line_anno_1(Name, Line);
1276line_anno([{Line,Column},{file,Name}]) when is_integer(Line),
1277                                            is_integer(Column) ->
1278    line_anno_1(Name, Line);
1279line_anno([_|_]=A) ->
1280    {Name,Line} = find_loc(A, no_file, 0),
1281    line_anno_1(Name, Line);
1282line_anno([]) ->
1283    #{}.
1284
1285line_anno_1(no_file, _) ->
1286    #{};
1287line_anno_1(_, 0) ->
1288    %% Missing line number or line number 0.
1289    #{};
1290line_anno_1(Name, Line) ->
1291    #{location=>{Name,Line}}.
1292
1293find_loc([Line|T], File, _) when is_integer(Line) ->
1294    find_loc(T, File, Line);
1295find_loc([{Line, Column}|T], File, _) when is_integer(Line),
1296                                           is_integer(Column) ->
1297    find_loc(T, File, Line);
1298find_loc([{file,File}|T], _, Line) ->
1299    find_loc(T, File, Line);
1300find_loc([_|T], File, Line) ->
1301    find_loc(T, File, Line);
1302find_loc([], File, Line) -> {File,Line}.
1303
1304flatmapfoldl(F, Accu0, [Hd|Tail]) ->
1305    {R,Accu1} = F(Hd, Accu0),
1306    {Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
1307    {R++Rs,Accu2};
1308flatmapfoldl(_, Accu, []) -> {[],Accu}.
1309
1310%%%
1311%%% Finalize the code.
1312%%%
1313
1314finalize(Asm0, St0) ->
1315    Asm1 = fix_phis(Asm0),
1316    {Asm,St} = fix_sets(Asm1, [], St0),
1317    {build_map(Asm),St}.
1318
1319%% fix_phis(Is0) -> Is.
1320%%  Rewrite #cg_break{} and #cg_phi{} records to #b_set{} records.
1321%%  A #cg_break{} is rewritten to an unconditional branch, and
1322%%  and a #cg_phi{} is rewritten to one or more phi nodes.
1323
1324fix_phis(Is) ->
1325    fix_phis_1(Is, none, #{}).
1326
1327fix_phis_1([{label,Lbl},#cg_phi{vars=Vars}|Is0], _Lbl, Map0) ->
1328    case Map0 of
1329        #{Lbl:=Pairs} ->
1330            %% This phi node was referenced by at least one #cg_break{}.
1331            %% Create the phi nodes.
1332            Phis = gen_phis(Vars, Pairs),
1333            Map = maps:remove(Lbl, Map0),
1334            [{label,Lbl}] ++ Phis ++ fix_phis_1(Is0, Lbl, Map);
1335        #{} ->
1336            %% No #cg_break{} instructions reference this label.
1337            %% #cg_break{} instructions must reference the labels for
1338            %% #cg_phi{} instructions; therefore this label is
1339            %% unreachable and can be dropped.
1340            Is = drop_upto_label(Is0),
1341            fix_phis_1(Is, none, Map0)
1342    end;
1343fix_phis_1([{label,L}=I|Is], _Lbl, Map) ->
1344    [I|fix_phis_1(Is, L, Map)];
1345fix_phis_1([#cg_unreachable{}|Is0], _Lbl, Map) ->
1346    Is = drop_upto_label(Is0),
1347    fix_phis_1(Is, none, Map);
1348fix_phis_1([#cg_break{args=Args,phi=Target}|Is], Lbl, Map) when is_integer(Lbl) ->
1349    %% Pair each argument with the label for this block and save in the map.
1350    Pairs1 = case Map of
1351                 #{Target:=Pairs0} -> Pairs0;
1352                 #{} -> []
1353             end,
1354    Pairs = [[{Arg,Lbl} || Arg <- Args]|Pairs1],
1355    I = make_uncond_branch(Target),
1356    [I|fix_phis_1(Is, none, Map#{Target=>Pairs})];
1357fix_phis_1([I|Is], Lbl, Map) ->
1358    [I|fix_phis_1(Is, Lbl, Map)];
1359fix_phis_1([], _, Map) ->
1360    [] = maps:to_list(Map),                     %Assertion.
1361    [].
1362
1363gen_phis([V|Vs], Preds0) ->
1364    {Pairs,Preds} = collect_preds(Preds0, [], []),
1365    [_|_] = Pairs,                              %Assertion.
1366    [#b_set{op=phi,dst=V,args=Pairs}|gen_phis(Vs, Preds)];
1367gen_phis([], _) -> [].
1368
1369collect_preds([[First|Rest]|T], ColAcc, RestAcc) ->
1370    collect_preds(T, [First|ColAcc], [Rest|RestAcc]);
1371collect_preds([], ColAcc, RestAcc) ->
1372    {keysort(2, ColAcc),RestAcc}.
1373
1374drop_upto_label([{label,_}|_]=Is) -> Is;
1375drop_upto_label([_|Is]) -> drop_upto_label(Is).
1376
1377%% fix_sets(Is0, Acc, St0) -> {Is,St}.
1378%%  Ensure that #b_set.dst is filled in with a proper variable.
1379%%  (For convenience, for instructions that don't have a useful return value,
1380%%  the code generator would set #b_set.dst to `none`.)
1381
1382fix_sets([#b_set{op=remove_message,dst=Dst}=Set,#b_ret{arg=Dst}=Ret|Is], Acc, St) ->
1383    %% The remove_message instruction, which is an instruction without
1384    %% value, was used in effect context in an `after` block. Example:
1385    %%
1386    %%   try
1387    %%       . . .
1388    %%   after
1389    %%       .
1390    %%       .
1391    %%       .
1392    %%       receive _ -> ignored end
1393    %%   end,
1394    %%   ok.
1395    %%
1396    fix_sets(Is, [Ret#b_ret{arg=#b_literal{val=ok}},Set|Acc], St);
1397fix_sets([#b_set{dst=none}=Set|Is], Acc, St0) ->
1398    {Dst,St} = new_ssa_var('@ssa_ignored', St0),
1399    I = Set#b_set{dst=Dst},
1400    fix_sets(Is, [I|Acc], St);
1401fix_sets([I|Is], Acc, St) ->
1402    fix_sets(Is, [I|Acc], St);
1403fix_sets([], Acc, St) ->
1404    {reverse(Acc),St}.
1405
1406%% build_map(Is) -> #{}.
1407%%  Split up the sequential instruction stream into blocks and
1408%%  store them in a map.
1409
1410build_map(Is) ->
1411    Linear0 = build_graph_1(Is, [], []),
1412    Linear = beam_ssa:trim_unreachable(Linear0),
1413    maps:from_list(Linear).
1414
1415build_graph_1([{label,L}|Is], Lbls, []) ->
1416    build_graph_1(Is, [L|Lbls], []);
1417build_graph_1([{label,L}|Is], Lbls, [_|_]=BlockAcc) ->
1418    make_blocks(Lbls, BlockAcc) ++ build_graph_1(Is, [L], []);
1419build_graph_1([I|Is], Lbls, BlockAcc) ->
1420    build_graph_1(Is, Lbls, [I|BlockAcc]);
1421build_graph_1([], Lbls, BlockAcc) ->
1422    make_blocks(Lbls, BlockAcc).
1423
1424make_blocks(Lbls, [Last0|Is0]) ->
1425    Is = reverse(Is0),
1426    Last = beam_ssa:normalize(Last0),
1427    Block = #b_blk{is=Is,last=Last},
1428    [{L,Block} || L <- Lbls].
1429