diff options
author | Björn Gustavsson <[email protected]> | 2019-01-25 15:26:57 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2019-01-28 05:34:58 +0100 |
commit | 9528e7a5de22ffa8ce2557e45fb744d2c3548bf5 (patch) | |
tree | b69b04bacc3d5d1f1d6c846d41a9aa808afbc722 /lib/compiler | |
parent | d479269f2805aba973d1ff3dd7cc7387908cb3ed (diff) | |
download | otp-9528e7a5de22ffa8ce2557e45fb744d2c3548bf5.tar.gz otp-9528e7a5de22ffa8ce2557e45fb744d2c3548bf5.tar.bz2 otp-9528e7a5de22ffa8ce2557e45fb744d2c3548bf5.zip |
Fix crash in beam_ssa_type
To improve compilation times, beam_ssa_type keeps track of variables
that are only used once and don't keep types for those variables. As
currently implemented, it turns to be unsafe. Change it to only keep
track of variables that are only used in the terminator of the block
they are defined in.
https://bugs.erlang.org/browse/ERL-840
Diffstat (limited to 'lib/compiler')
-rw-r--r-- | lib/compiler/src/beam_ssa_type.erl | 24 | ||||
-rw-r--r-- | lib/compiler/test/beam_type_SUITE.erl | 16 |
2 files changed, 30 insertions, 10 deletions
diff --git a/lib/compiler/src/beam_ssa_type.erl b/lib/compiler/src/beam_ssa_type.erl index 38ea5e6914..8bd6772ac5 100644 --- a/lib/compiler/src/beam_ssa_type.erl +++ b/lib/compiler/src/beam_ssa_type.erl @@ -1072,15 +1072,23 @@ simplify_not(#b_br{bool=#b_var{}=V,succ=Succ,fail=Fail}=Br0, Ts, Ds) -> %%% %%% Calculate the set of variables that are only used once in the -%%% block that they are defined in. That will allow us to discard type -%%% information for variables that will never be referenced by the -%%% successor blocks, potentially improving compilation times. +%%% terminator of the block that defines them. That will allow us to +%%% discard type information for variables that will never be +%%% referenced by the successor blocks, potentially improving +%%% compilation times. %%% used_once(Linear, Args) -> Map0 = used_once_1(reverse(Linear), #{}), Map = maps:without(Args, Map0), - cerl_sets:from_list(maps:keys(Map)). + Used0 = cerl_sets:from_list(maps:keys(Map)), + Used1 = used_in_terminators(Linear, []), + cerl_sets:intersection(Used0, Used1). + +used_in_terminators([{_,#b_blk{last=Last}}|Bs], Acc) -> + used_in_terminators(Bs, beam_ssa:used(Last) ++ Acc); +used_in_terminators([], Acc) -> + cerl_sets:from_list(Acc). used_once_1([{L,#b_blk{is=Is,last=Last}}|Bs], Uses0) -> Uses = used_once_2([Last|reverse(Is)], L, Uses0), @@ -1177,7 +1185,7 @@ get_type(#b_literal{val=Val}, _Ts) -> %% failed and that L is not 'cons'. 'cons' can be subtracted from the %% previously known type for L and the result put in FailTypes. -infer_types(#b_var{}=V, Ts, #d{ds=Ds,once=Once}) -> +infer_types(#b_var{}=V, Ts, #d{ds=Ds}) -> #{V:=#b_set{op=Op,args=Args}} = Ds, Types0 = infer_type(Op, Args, Ds), @@ -1195,11 +1203,7 @@ infer_types(#b_var{}=V, Ts, #d{ds=Ds,once=Once}) -> is_singleton_type(T) end, EqTypes0), - %% Don't bother updating the types for variables that - %% are never used again. - Types2 = Types1 ++ Types0, - Types = [P || {InfV,_}=P <- Types2, not cerl_sets:is_element(InfV, Once)], - + Types = Types1 ++ Types0, {meet_types(EqTypes++Types, Ts),subtract_types(Types, Ts)}. infer_eq_type({bif,'=:='}, [#b_var{}=Src,#b_literal{}=Lit], Ts, Ds) -> diff --git a/lib/compiler/test/beam_type_SUITE.erl b/lib/compiler/test/beam_type_SUITE.erl index 6efa98de44..a7ffc3f60a 100644 --- a/lib/compiler/test/beam_type_SUITE.erl +++ b/lib/compiler/test/beam_type_SUITE.erl @@ -222,6 +222,9 @@ coverage(Config) -> booleans(_Config) -> {'EXIT',{{case_clause,_},_}} = (catch do_booleans_1(42)), + ok = do_booleans_2(42, 41), + error = do_booleans_2(42, 42), + AnyAtom = id(atom), true = is_atom(AnyAtom), false = is_boolean(AnyAtom), @@ -250,6 +253,19 @@ do_booleans_1(B) -> no -> no end. +do_booleans_2(A, B) -> + Not = not do_booleans_cmp(A, B), + case Not of + true -> + case Not of + true -> error; + false -> ok + end; + false -> ok + end. + +do_booleans_cmp(A, B) -> A > B. + setelement(_Config) -> T0 = id({a,42}), {a,_} = T0, |