aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorBjörn Gustavsson <[email protected]>2018-02-28 04:42:19 +0100
committerBjörn Gustavsson <[email protected]>2018-03-02 13:04:17 +0100
commit8f057e62df58eac610d9b958118c4a536ca675da (patch)
tree5cb163001d49d84fcc4b1da2ca16c1ee245913df /lib
parentcebf6f0c68d231af8dcdb6bdf149ae9d870e9e6d (diff)
downloadotp-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.
Diffstat (limited to 'lib')
-rw-r--r--lib/compiler/src/beam_type.erl50
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