diff options
author | Björn Gustavsson <[email protected]> | 2018-02-28 04:42:19 +0100 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2018-03-02 13:04:17 +0100 |
commit | 8f057e62df58eac610d9b958118c4a536ca675da (patch) | |
tree | 5cb163001d49d84fcc4b1da2ca16c1ee245913df | |
parent | cebf6f0c68d231af8dcdb6bdf149ae9d870e9e6d (diff) | |
download | otp-8f057e62df58eac610d9b958118c4a536ca675da.tar.gz otp-8f057e62df58eac610d9b958118c4a536ca675da.tar.bz2 otp-8f057e62df58eac610d9b958118c4a536ca675da.zip |
beam_type: Make sure to kill all dependencies when killing a register
Make sure to kill all dependencies when a register is killed. For example,
in the following code, when the type information for {x,0} is killed in
the last instruction, there will still be type information for {x,1} referring
to {x,0}:
{get_tuple_element,{x,0},0,{x,1}}.
{test,is_eq_exact,{f,5},[{x,1},{atom,tag}]}.
{get_tuple_element,{x,0},1,{x,2}}.
{get_tuple_element,{x,0},2,{x,0}}.
This does not seems to have caused any problems in the past, but it may
cause problems in the future with a register allocator that reuses register
more aggressively.
-rw-r--r-- | lib/compiler/src/beam_type.erl | 50 |
1 files changed, 46 insertions, 4 deletions
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl index 56ee64db39..28f36db399 100644 --- a/lib/compiler/src/beam_type.erl +++ b/lib/compiler/src/beam_type.erl @@ -472,8 +472,14 @@ update({set,[D],Args,{bif,N,_}}, Ts) -> false -> unary_op_type(N) end, tdb_store(D, Type, Ts); -update({set,[D],[S],{get_tuple_element,0}}, Ts) -> - tdb_store(D, {tuple_element,S,0}, Ts); +update({set,[D],[S],{get_tuple_element,0}}, Ts0) -> + if + D =:= S -> + tdb_store(D, any, Ts0); + true -> + Ts = tdb_store(D, {tuple_element,S,0}, Ts0), + tdb_store(S, {tuple,min_size,1,[]}, Ts) + end; update({set,[D],[S],{alloc,_,{gc_bif,float,{f,0}}}}, Ts0) -> %% Make sure we reject non-numeric literal argument. case possibly_numeric(S) of @@ -917,9 +923,45 @@ tdb_copy(Literal, D, Ts) -> %% a description of the possible types. tdb_store(Reg, any, Ts) -> - orddict:erase(Reg, Ts); + erase(Reg, Ts); tdb_store(Reg, Type, Ts) -> - orddict:store(Reg, verified_type(Type), Ts). + store(Reg, verified_type(Type), Ts). + +store(Key, New, [{K,_}|_]=Dict) when Key < K -> + [{Key,New}|Dict]; +store(Key, New, [{K,Val}=E|Dict]) when Key > K -> + case Val of + {tuple_element,Key,_} -> store(Key, New, Dict); + _ -> [E|store(Key, New, Dict)] + end; +store(Key, New, [{_K,Old}|Dict]) -> %Key == K + case Old of + {tuple,_,_,_} -> + [{Key,New}|erase_tuple_element(Key, Dict)]; + _ -> + [{Key,New}|Dict] + end; +store(Key, New, []) -> [{Key,New}]. + +erase(Key, [{K,_}=E|Dict]) when Key < K -> + [E|Dict]; +erase(Key, [{K,Val}=E|Dict]) when Key > K -> + case Val of + {tuple_element,Key,_} -> erase(Key, Dict); + _ -> [E|erase(Key, Dict)] + end; +erase(Key, [{_K,Val}|Dict]) -> %Key == K + case Val of + {tuple,_,_,_} -> erase_tuple_element(Key, Dict); + _ -> Dict + end; +erase(_, []) -> []. + +erase_tuple_element(Key, [{_,{tuple_element,Key,_}}|Dict]) -> + erase_tuple_element(Key, Dict); +erase_tuple_element(Key, [E|Dict]) -> + [E|erase_tuple_element(Key, Dict)]; +erase_tuple_element(_Key, []) -> []. %% tdb_meet(Register, Type, Ts0) -> Ts. %% Update information of a register that is used as the source for an |