diff options
author | Björn Gustavsson <[email protected]> | 2012-08-14 09:52:51 +0200 |
---|---|---|
committer | Björn Gustavsson <[email protected]> | 2012-10-09 10:08:58 +0200 |
commit | 3605e00470d8e04710317b88e135e28082ff27d3 (patch) | |
tree | 0c9add23fe8b6484043e861d393820439dc326fc /lib/compiler/src | |
parent | cda99c83652fca9473eadba2608c14e5feffa0a0 (diff) | |
download | otp-3605e00470d8e04710317b88e135e28082ff27d3.tar.gz otp-3605e00470d8e04710317b88e135e28082ff27d3.tar.bz2 otp-3605e00470d8e04710317b88e135e28082ff27d3.zip |
beam_utils: Correct usage calculations for GC BIFs in blocks
The usage calculation only looked at the allocation in GC BIFs, not
at the source and destination registers. Also, if there is a failure
label, make sure that we test whether the register can be used there.
Diffstat (limited to 'lib/compiler/src')
-rw-r--r-- | lib/compiler/src/beam_utils.erl | 44 |
1 files changed, 34 insertions, 10 deletions
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl index 3b24cbfaba..7e4a476dab 100644 --- a/lib/compiler/src/beam_utils.erl +++ b/lib/compiler/src/beam_utils.erl @@ -87,7 +87,7 @@ is_killed_at(R, Lbl, D) when is_integer(Lbl) -> %% across branches. is_not_used(R, Is, D) -> - St = #live{bl=fun check_used_block/2,lbl=D,res=gb_trees:empty()}, + St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()}, case check_liveness(R, Is, St) of {killed,_} -> true; {used,_} -> false; @@ -102,7 +102,7 @@ is_not_used(R, Is, D) -> %% across branches. is_not_used_at(R, Lbl, D) -> - St = #live{bl=fun check_used_block/2,lbl=D,res=gb_trees:empty()}, + St = #live{bl=check_used_block_fun(D),lbl=D,res=gb_trees:empty()}, case check_liveness_at(R, Lbl, St) of {killed,_} -> true; {used,_} -> false; @@ -612,26 +612,50 @@ check_killed_block(_, []) -> transparent. %% %% (Unknown instructions will cause an exception.) -check_used_block({x,X}=R, [{set,_,_,{alloc,Live,_}}|Is]) -> +check_used_block_fun(D) -> + fun(R, Is) -> check_used_block(R, Is, D) end. + +check_used_block({x,X}=R, [{set,Ds,Ss,{alloc,Live,Op}}|Is], D) -> if X >= Live -> killed; - true -> check_used_block(R, Is) + true -> + case member(R, Ss) orelse + is_reg_used_at(R, Op, D) of + true -> used; + false -> + case member(R, Ds) of + true -> killed; + false -> check_used_block(R, Is, D) + end + end end; -check_used_block(R, [{set,Ds,Ss,_Op}|Is]) -> - case member(R, Ss) of +check_used_block(R, [{set,Ds,Ss,Op}|Is], D) -> + case member(R, Ss) orelse + is_reg_used_at(R, Op, D) of true -> used; false -> case member(R, Ds) of true -> killed; - false -> check_used_block(R, Is) + false -> check_used_block(R, Is, D) end end; -check_used_block(R, [{'%live',Live}|Is]) -> +check_used_block(R, [{'%live',Live}|Is], D) -> case R of {x,X} when X >= Live -> killed; - _ -> check_used_block(R, Is) + _ -> check_used_block(R, Is, D) end; -check_used_block(_, []) -> transparent. +check_used_block(_, [], _) -> transparent. + +is_reg_used_at(R, {gc_bif,_,{f,Lbl}}, D) -> + is_reg_used_at_1(R, Lbl, D); +is_reg_used_at(R, {bif,_,{f,Lbl}}, D) -> + is_reg_used_at_1(R, Lbl, D); +is_reg_used_at(_, _, _) -> false. + +is_reg_used_at_1(_, 0, _) -> + false; +is_reg_used_at_1(R, Lbl, D) -> + not is_not_used_at(R, Lbl, D). index_labels_1([{label,Lbl}|Is0], Acc) -> Is = lists:dropwhile(fun({label,_}) -> true; |