From 971fc7b39934e9d3e0927d95c45bea6ad7e90566 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gustavsson?= Date: Tue, 13 Jan 2015 05:37:26 +0100 Subject: beam_bool: Correct live calculation for GC BIFs When optimizing boolean expressions, it is not always possible to find a number of live registers for a GC BIF that both preserves all source registers that will be tested and at the same time does not include registers that are not initialized. As currently implemented, we have incomplete information about the register calculated from the free variables. Some registers are marked as "reserved". Reserved registers means that we don't know anything about them; they may or may not be initialized. As a conservative correction (suitable for a maintenance release), we will abort the optimization if we find any reserved registers when calculating the number of live registers. We will not attempt to improve the information about the registers in this commit. By examining the coverage when running the existing compiler test suite we find that the optimization is aborted 15 times (before adding any new test cases). To put that in perspective, the optimization is successfully applied 4927 times, and aborted for other reasons 547 times. Reported-by: Ulf Norell Reported-by: Anthony Ramine --- lib/compiler/src/beam_bool.erl | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'lib/compiler/src') diff --git a/lib/compiler/src/beam_bool.erl b/lib/compiler/src/beam_bool.erl index dc4d7927e9..a452d30b61 100644 --- a/lib/compiler/src/beam_bool.erl +++ b/lib/compiler/src/beam_bool.erl @@ -163,7 +163,16 @@ bopt_block(Reg, Fail, OldIs, [{block,Bl0}|Acc0], St0) -> %% in guards, so it must have been another %% Core Erlang translator.) throw:protected_violation -> + failed; + + %% Failed to work out the live registers for a GC + %% BIF. For example, if the number of live registers + %% needed to be 4 because {x,3} was a source register, + %% but {x,2} was not known to be initialized, this + %% exception would be thrown. + throw:gc_bif_alloc_failure -> failed + end end. @@ -665,10 +674,16 @@ put_reg_1(V, [], I) -> [{I,V}]. fetch_reg(V, [{I,V}|_]) -> {x,I}; fetch_reg(V, [_|SRs]) -> fetch_reg(V, SRs). -live_regs(Regs) -> - foldl(fun ({I,_}, _) -> - I - end, -1, Regs)+1. +live_regs([{_,reserved}|_]) -> + %% We are not sure that this register is initialized, so we must + %% abort the optimization. + throw(gc_bif_alloc_failure); +live_regs([{I,_}]) -> + I+1; +live_regs([{_,_}|Regs]) -> + live_regs(Regs); +live_regs([]) -> + 0. %%% -- cgit v1.2.3