From 8f057e62df58eac610d9b958118c4a536ca675da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Wed, 28 Feb 2018 04:42:19 +0100 Subject: 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. --- lib/compiler/src/beam_type.erl | 50 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 4 deletions(-) (limited to 'lib/compiler') 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 -- cgit v1.2.3