155
138
{ok,{Mod,Exp,Attr,Fs,Lc}}.
157
140
function({function,Name,Arity,CLabel,Is0}, Lc0) ->
158
Is1 = beam_jump:remove_unused_labels(Is0),
161
%% Optimize away dead code.
162
{Is3,Lc} = forward(Is2, Lc0),
164
Is = move_move_into_block(Is4, []),
165
{{function,Name,Arity,CLabel,Is},Lc}.
168
%%% Remove redundant is_boolean tests.
174
bopt_1([{test,is_boolean,_,_}=I|Is], Acc0) ->
175
case opt_is_bool(I, Acc0) of
176
no -> bopt_1(Is, [I|Acc0]);
177
yes -> bopt_1(Is, Acc0);
178
{yes,Acc} -> bopt_1(Is, Acc)
180
bopt_1([I|Is], Acc) -> bopt_1(Is, [I|Acc]);
181
bopt_1([], Acc) -> reverse(Acc).
183
opt_is_bool({test,is_boolean,{f,Lbl},[Reg]}, Acc) ->
184
opt_is_bool_1(Acc, Reg, Lbl).
186
opt_is_bool_1([{test,is_eq_exact,{f,Lbl},[Reg,{atom,true}]}|_], Reg, Lbl) ->
187
%% Instruction not needed in this context.
189
opt_is_bool_1([{test,is_ne_exact,{f,Lbl},[Reg,{atom,true}]}|Acc], Reg, Lbl) ->
190
%% Rewrite to shorter test.
191
{yes,[{test,is_eq_exact,{f,Lbl},[Reg,{atom,false}]}|Acc]};
192
opt_is_bool_1([{test,_,{f,Lbl},_}=Test|Acc0], Reg, Lbl) ->
193
case opt_is_bool_1(Acc0, Reg, Lbl) of
194
{yes,Acc} -> {yes,[Test|Acc]};
197
opt_is_bool_1(_, _, _) -> no.
142
Is1 = beam_jump:remove_unused_labels(Is0),
144
%% Initialize label information with the code
145
%% for the func_info label. Without it, a register
146
%% may seem to be live when it is not.
147
[{label,L},{func_info,_,_,_}=FI|_] = Is1,
148
D0 = beam_utils:empty_label_index(),
149
D = beam_utils:index_label(L, [FI], D0),
151
%% Optimize away dead code.
152
{Is2,Lc} = forward(Is1, Lc0),
153
Is3 = backward(Is2, D),
154
Is = move_move_into_block(Is3, []),
155
{{function,Name,Arity,CLabel,Is},Lc}
158
Stack = erlang:get_stacktrace(),
159
io:fwrite("Function: ~w/~w\n", [Name,Arity]),
160
erlang:raise(Class, Error, Stack)
199
163
%% We must split the basic block when we encounter instructions with labels,
200
164
%% such as catches and BIFs. All labels must be visible outside the blocks.
299
258
_ -> Blk %Keep move instruction.
301
260
forward([Block|Is], D, Lc, [LblI|Acc]);
261
forward([{label,Lbl}=LblI|[{move,Lit,Dst}|Is1]=Is0], D, Lc, Acc) ->
262
Is = case gb_trees:lookup({Lbl,Dst}, D) of
264
%% The move instruction seems to be redundant, but also make
265
%% sure that the instruction preceeding the label
266
%% cannot fall through to the move instruction.
267
case is_unreachable_after(Acc) of
268
false -> Is0; %Must keep move instruction.
269
true -> Is1 %Safe to remove move instruction.
271
_ -> Is0 %Keep move instruction.
273
forward(Is, D, Lc, [LblI|Acc]);
302
274
forward([{test,is_eq_exact,_,[Dst,Src]}=I,
303
275
{block,[{set,[Dst],[Src],move}|Bl]}|Is], D, Lc, Acc) ->
304
276
forward([I,{block,Bl}|Is], D, Lc, Acc);
341
313
%%% Scan instructions in reverse execution order and remove dead code.
345
backward(Is, beam_utils:empty_label_index(), []).
319
backward([{test,is_eq_exact,Fail,[Dst,{integer,Arity}]}=I|
320
[{bif,tuple_size,Fail,[Reg],Dst}|Is]=Is0], D, Acc) ->
321
%% Provided that Dst is killed following this sequence,
322
%% we can rewrite the instructions like this:
324
%% bif tuple_size Fail Reg Dst ==> is_tuple Fail Reg
325
%% is_eq_exact Fail Dst Integer test_arity Fail Reg Integer
327
%% (still two instructions, but they they will be combined to
328
%% one by the loader).
329
case beam_utils:is_killed(Dst, Acc, D) andalso (Arity bsr 32) =:= 0 of
331
%% Not safe because the register Dst is not killed
332
%% (probably cannot not happen in practice) or the arity
333
%% does not fit in 32 bits (the loader will fail to load
334
%% the module). We must move the first instruction to the
335
%% accumulator to avoid an infinite loop.
336
backward(Is0, D, [I|Acc]);
339
backward([{test,test_arity,Fail,[Reg,Arity]},
340
{test,is_tuple,Fail,[Reg]}|Is], D, Acc)
347
342
backward([{label,Lbl}=L|Is], D, Acc) ->
348
343
backward(Is, beam_utils:index_label(Lbl, Acc, D), [L|Acc]);
349
344
backward([{select_val,Reg,{f,Fail0},{list,List0}}|Is], D, Acc) ->
373
368
throw:not_possible -> backward(Is0, D, [J|Acc])
375
backward([{test,bs_start_match2,{f,To0},[Src|_]=Info}|Is], D, Acc) ->
370
backward([{test,bs_start_match2,{f,To0},Live,[Src|_]=Info,Dst}|Is], D, Acc) ->
376
371
To = shortcut_bs_start_match(To0, Src, D),
377
I = {test,bs_start_match2,{f,To},Info},
372
I = {test,bs_start_match2,{f,To},Live,Info,Dst},
378
373
backward(Is, D, [I|Acc]);
379
backward([{test,Op,{f,To0},Ops}|Is], D, Acc) ->
380
To = shortcut_bs_test(To0, Is, D),
374
backward([{test,is_eq_exact=Op,{f,To0},[Reg,{atom,Val}]=Ops}|Is], D, Acc) ->
375
To1 = shortcut_bs_test(To0, Is, D),
376
To = shortcut_fail_label(To1, Reg, Val, D),
381
377
I = {test,Op,{f,To},Ops},
382
378
backward(Is, D, [I|Acc]);
383
backward([{block,[{'%live',_}]}|Is], D, Acc) ->
384
%% A redundant block could prevent some jump optimizations in beam_jump.
386
backward(Is, D, Acc);
379
backward([{test,Op,{f,To0},Ops0}|Is], D, Acc) ->
380
To1 = shortcut_bs_test(To0, Is, D),
381
To2 = shortcut_label(To1, D),
382
%% Try to shortcut a repeated test:
384
%% test Op {f,Fail1} Operands test Op {f,Fail2} Operands
386
%% Fail1: test Op {f,Fail2} Operands Fail1: test Op {f,Fail2} Operands
388
To = case beam_utils:code_at(To2, D) of
389
[{test,Op,{f,To3},Ops}|_] ->
390
case equal_ops(Ops0, Ops) of
397
I = {test,Op,{f,To},Ops0},
398
backward(Is, D, [I|Acc]);
399
backward([{test,Op,{f,To0},Live,Ops0,Dst}|Is], D, Acc) ->
400
To1 = shortcut_bs_test(To0, Is, D),
401
To2 = shortcut_label(To1, D),
402
%% Try to shortcut a repeated test:
404
%% test Op {f,Fail1} _ Ops _ test Op {f,Fail2} _ Ops _
406
%% Fail1: test Op {f,Fail2} _ Ops _ Fail1: test Op {f,Fail2} _ Ops _
408
To = case beam_utils:code_at(To2, D) of
409
[{test,Op,{f,To3},_,Ops,_}|_] ->
410
case equal_ops(Ops0, Ops) of
417
I = {test,Op,{f,To},Live,Ops0,Dst},
418
backward(Is, D, [I|Acc]);
387
419
backward([{kill,_}=I|Is], D, [Exit|_]=Acc) ->
388
420
case beam_jump:is_exit_instruction(Exit) of
389
421
false -> backward(Is, D, [I|Acc]);
390
422
true -> backward(Is, D, Acc)
392
backward([{'%live',_}|Is], D, Acc) ->
393
backward(Is, D, Acc);
394
424
backward([I|Is], D, Acc) ->
395
425
backward(Is, D, [I|Acc]);
396
426
backward([], _D, Acc) -> Acc.
428
equal_ops([{field_flags,FlA0}|T0], [{field_flags,FlB0}|T1]) ->
429
FlA = lists:keydelete(anno, 1, FlA0),
430
FlB = lists:keydelete(anno, 1, FlB0),
431
FlA =:= FlB andalso equal_ops(T0, T1);
432
equal_ops([Op|T0], [Op|T1]) ->
434
equal_ops([], []) -> true;
435
equal_ops(_, _) -> false.
398
437
shortcut_select_list([{_,Val}=Lit,{f,To0}|T], Reg, D, Acc) ->
399
438
To = shortcut_select_label(To0, Reg, Val, D),
400
439
shortcut_select_list(T, Reg, D, [{f,To},Lit|Acc]);
415
454
shortcut_select_label(To, Reg, Val, D);
416
455
[{test,is_eq_exact,{f,_},[Reg,{atom,Val}]},{label,To}|_] when is_atom(Val) ->
417
456
shortcut_select_label(To, Reg, Val, D);
418
[{test,is_eq_exact,{f,To},[Reg,{atom,_}]}|_] when is_atom(Val) ->
457
[{test,is_eq_exact,{f,_},[Reg,{atom,Val}]},{jump,{f,To}}|_] when is_atom(Val) ->
458
shortcut_select_label(To, Reg, Val, D);
459
[{test,is_eq_exact,{f,To},[Reg,{atom,AnotherVal}]}|_]
460
when is_atom(Val), Val =/= AnotherVal ->
419
461
shortcut_select_label(To, Reg, Val, D);
420
462
[{test,is_ne_exact,{f,To},[Reg,{atom,Val}]}|_] when is_atom(Val) ->
421
463
shortcut_select_label(To, Reg, Val, D);