diff options
author | Björn Gustavsson <[email protected]> | 2019-02-26 13:31:16 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2019-02-28 12:18:23 +0100 |
commit | 72b503485b0d029f615c80c3e64680419cd690d9 (patch) | |
tree | 6df81eca7b82eb45f863eb3b809ad7fc9fb78d80 /lib/compiler/src/beam_ssa_opt.erl | |
parent | 300c64460d6ea19eb34f9d345a7e7770db7fa538 (diff) | |
download | otp-72b503485b0d029f615c80c3e64680419cd690d9.tar.gz otp-72b503485b0d029f615c80c3e64680419cd690d9.tar.bz2 otp-72b503485b0d029f615c80c3e64680419cd690d9.zip |
beam_ssa_opt: Use is_tagged_tuple more
Consider this code:
foo(X) ->
case X of
{ok,A} -> A;
error -> X
end.
The `is_tagged_tuple` instruction would not be used
because not all instructions in the tuple matching
sequence had the same failure label:
function t:foo(_0) {
0:
@ssa_bool:7 = bif:is_tuple _0
br @ssa_bool:7, label 8, label 4
8:
@ssa_arity = bif:tuple_size _0
@ssa_bool:9 = bif:'=:=' @ssa_arity, literal 2
br @ssa_bool:9, label 6, label 3
6:
_4 = get_tuple_element _0, literal 0
@ssa_bool = bif:'=:=' _4, literal ok
br @ssa_bool, label 5, label 3
5:
_3 = get_tuple_element _0, literal 1
ret _3
4:
@ssa_bool:11 = bif:'=:=' _0, literal error
br @ssa_bool:11, label 10, label 3
10:
ret _0
3:
_2 = put_tuple literal case_clause, _0
%% t.erl:5
@ssa_ret:12 = call remote (literal erlang):(literal error)/1, _2
ret @ssa_ret:12
}
Enhance the ssa_opt_record optimization to use
`is_tagged_tuple` even if all failure labels are not the
same:
function t:foo(_0) {
0:
@ssa_bool:7 = bif:is_tuple _0
br @ssa_bool:7, label 8, label 4
8:
@ssa_bool:9 = is_tagged_tuple _0, literal 2, literal ok
br @ssa_bool:9, label 6, label 3
6:
_3 = get_tuple_element _0, literal 1
ret _3
4:
@ssa_bool:11 = bif:'=:=' _0, literal error
br @ssa_bool:11, label 10, label 3
10:
ret _0
3:
_2 = put_tuple literal case_clause, _0
%% t.erl:5
@ssa_ret:12 = call remote (literal erlang):(literal error)/1, _2
ret @ssa_ret:12
}
The tuple test will be repeated, but since four instructions
are replaced by two instructions, the code will still be faster
and smaller.
Diffstat (limited to 'lib/compiler/src/beam_ssa_opt.erl')
-rw-r--r-- | lib/compiler/src/beam_ssa_opt.erl | 51 |
1 files changed, 30 insertions, 21 deletions
diff --git a/lib/compiler/src/beam_ssa_opt.erl b/lib/compiler/src/beam_ssa_opt.erl index ff9d562d67..bcf55f3fda 100644 --- a/lib/compiler/src/beam_ssa_opt.erl +++ b/lib/compiler/src/beam_ssa_opt.erl @@ -683,6 +683,14 @@ record_opt_is([#b_set{op={bif,is_tuple},dst=Bool,args=[Tuple]}=Set], no -> [Set] end; +record_opt_is([I|Is]=Is0, #b_br{bool=Bool}=Last, Blocks) -> + case is_tagged_tuple_1(Is0, Last, Blocks) of + {yes,_Fail,Tuple,Arity,Tag} -> + Args = [Tuple,Arity,Tag], + [I#b_set{op=is_tagged_tuple,dst=Bool,args=Args}]; + no -> + [I|record_opt_is(Is, Last, Blocks)] + end; record_opt_is([I|Is], Last, Blocks) -> [I|record_opt_is(Is, Last, Blocks)]; record_opt_is([], _Last, _Blocks) -> []. @@ -690,29 +698,30 @@ record_opt_is([], _Last, _Blocks) -> []. is_tagged_tuple(#b_var{}=Tuple, Bool, #b_br{bool=Bool,succ=Succ,fail=Fail}, Blocks) -> - SuccBlk = map_get(Succ, Blocks), - is_tagged_tuple_1(SuccBlk, Tuple, Fail, Blocks); + #b_blk{is=Is,last=Last} = map_get(Succ, Blocks), + case is_tagged_tuple_1(Is, Last, Blocks) of + {yes,Fail,Tuple,Arity,Tag} -> + {yes,Arity,Tag}; + _ -> + no + end; is_tagged_tuple(_, _, _, _) -> no. -is_tagged_tuple_1(#b_blk{is=Is,last=Last}, Tuple, Fail, Blocks) -> - case Is of - [#b_set{op={bif,tuple_size},dst=ArityVar, - args=[#b_var{}=Tuple]}, - #b_set{op={bif,'=:='}, - dst=Bool, - args=[ArityVar, #b_literal{val=ArityVal}=Arity]}] - when is_integer(ArityVal) -> - case Last of - #b_br{bool=Bool,succ=Succ,fail=Fail} -> - SuccBlk = map_get(Succ, Blocks), - case is_tagged_tuple_2(SuccBlk, Tuple, Fail) of - no -> - no; - {yes,Tag} -> - {yes,Arity,Tag} - end; - _ -> - no +is_tagged_tuple_1(Is, Last, Blocks) -> + case {Is,Last} of + {[#b_set{op={bif,tuple_size},dst=ArityVar, + args=[#b_var{}=Tuple]}, + #b_set{op={bif,'=:='}, + dst=Bool, + args=[ArityVar, #b_literal{val=ArityVal}=Arity]}], + #b_br{bool=Bool,succ=Succ,fail=Fail}} + when is_integer(ArityVal) -> + SuccBlk = map_get(Succ, Blocks), + case is_tagged_tuple_2(SuccBlk, Tuple, Fail) of + no -> + no; + {yes,Tag} -> + {yes,Fail,Tuple,Arity,Tag} end; _ -> no |