aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/compiler/src/beam_utils.erl55
-rw-r--r--lib/compiler/test/bs_construct_SUITE.erl24
2 files changed, 63 insertions, 16 deletions
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 0bc9d4cafe..b9c0cd7304 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -668,18 +668,30 @@ live_opt([{bs_add,Fail,[Src1,Src2,_],Dst}=I|Is], Regs0, D, Acc) ->
Regs1 = x_live([Src1,Src2], x_dead([Dst], Regs0)),
Regs = live_join_label(Fail, D, Regs1),
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init2,Fail,_,_,Live,_,_}=I|Is], _, D, Acc) ->
- Regs1 = live_call(Live),
- Regs = live_join_label(Fail, D, Regs1),
+live_opt([{bs_init2,Fail,Sz,Extra,Live0,Fl,Dst}|Is], Regs0, D, Acc) ->
+ Regs1 = x_dead([Dst], Regs0),
+ Live = live_regs(Regs1),
+ true = Live =< Live0, %Assertion.
+ Regs2 = live_call(Live),
+ Regs = live_join_label(Fail, D, Regs2),
+ I = {bs_init2,Fail,Sz,Extra,Live,Fl,Dst},
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_init_bits,Fail,Src1,_,Live,_,Src2}=I|Is], _, D, Acc) ->
- Regs1 = live_call(Live),
- Regs2 = x_live([Src1,Src2], Regs1),
+live_opt([{bs_init_bits,Fail,Sz,Extra,Live0,Fl,Dst}|Is], Regs0, D, Acc) ->
+ Regs1 = x_dead([Dst], Regs0),
+ Live = live_regs(Regs1),
+ true = Live =< Live0, %Assertion.
+ Regs2 = live_call(Live),
Regs = live_join_label(Fail, D, Regs2),
+ I = {bs_init_bits,Fail,Sz,Extra,Live,Fl,Dst},
live_opt(Is, Regs, D, [I|Acc]);
-live_opt([{bs_append,Fail,Src1,_,Live,_,Src2,_,Dst}=I|Is], _Regs0, D, Acc) ->
- Regs1 = x_dead([Dst], x_live([Src1,Src2], live_call(Live))),
- Regs = live_join_label(Fail, D, Regs1),
+live_opt([{bs_append,Fail,Bits,Extra,Live0,Unit,Src,Fl,Dst}|Is],
+ Regs0, D, Acc) ->
+ Regs1 = x_live([Src], x_dead([Dst], Regs0)),
+ Live = live_regs(Regs1),
+ true = Live =< Live0, %Assertion.
+ Regs2 = live_call(Live),
+ Regs = live_join_label(Fail, D, Regs2),
+ I = {bs_append,Fail,Bits,Extra,Live,Unit,Src,Fl,Dst},
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{bs_private_append,Fail,Src1,_,Src2,_,Dst}=I|Is], Regs0, D, Acc) ->
Regs1 = x_live([Src1,Src2], x_dead([Dst], Regs0)),
@@ -837,13 +849,24 @@ live_opt([{allocate_heap,_,_,Live}=I|Is], _, D, Acc) ->
live_opt([], _, _, Acc) -> Acc.
-live_opt_block([{set,[],[],{alloc,Live,_}}=I|Is], _, D, Acc) ->
- live_opt_block(Is, live_call(Live), D, [I|Acc]);
-live_opt_block([{set,Ds,Ss,Op}=I|Is], Regs0, D, Acc) ->
- Regs = case Op of
- {alloc,Live,_} -> live_call(Live);
- _ -> x_live(Ss, x_dead(Ds, Regs0))
- end,
+live_opt_block([{set,Ds,Ss,Op}=I0|Is], Regs0, D, Acc) ->
+ Regs1 = x_live(Ss, x_dead(Ds, Regs0)),
+ {I,Regs} = case Op of
+ {alloc,Live0,Alloc} ->
+ %% The life-time analysis used by the code generator
+ %% is sometimes too conservative, so it may be
+ %% possible to lower the number of live registers
+ %% based on the exact liveness information.
+ %% The main benefit is that more optimizations that
+ %% depend on liveness information (such as the
+ %% beam_bool and beam_dead passes) may be applied.
+ Live = live_regs(Regs1),
+ true = Live =< Live0, %Assertion.
+ I1 = {set,Ds,Ss,{alloc,Live,Alloc}},
+ {I1,live_call(Live)};
+ _ ->
+ {I0,Regs1}
+ end,
case Ds of
[{x,X}] ->
case (not is_live(X, Regs0)) andalso Op =:= move of
diff --git a/lib/compiler/test/bs_construct_SUITE.erl b/lib/compiler/test/bs_construct_SUITE.erl
index 9ab76449c7..a393aaeffd 100644
--- a/lib/compiler/test/bs_construct_SUITE.erl
+++ b/lib/compiler/test/bs_construct_SUITE.erl
@@ -360,6 +360,11 @@ in_catch(Config) when is_list(Config) ->
?line <<255>> = small(255, <<1,2,3,4,5,6,7,8,9>>),
?line <<1,2>> = small(<<7,8,9,10>>, 258),
?line <<>> = small(<<1,2,3,4,5>>, <<7,8,9,10>>),
+
+ <<15,240,0,42>> = small2(255, 42),
+ <<7:20>> = small2(<<1,2,3>>, 7),
+ <<300:12>> = small2(300, <<1,2,3>>),
+ <<>> = small2(<<1>>, <<2>>),
ok.
small(A, B) ->
@@ -381,6 +386,25 @@ small(A, B) ->
end,
<<ResA/binary,ResB/binary>>.
+small2(A, B) ->
+ case begin
+ case catch <<A:12>> of
+ {'EXIT',_} -> <<>>;
+ ResA0 -> ResA0
+ end
+ end of
+ ResA -> ok
+ end,
+ case begin
+ case catch <<B:20>> of
+ {'EXIT',_} -> <<>>;
+ ResB0 -> ResB0
+ end
+ end of
+ ResB -> ok
+ end,
+ <<ResA/binary-unit:1,ResB/binary-unit:1>>.
+
nasty_literals(Config) when is_list(Config) ->
case erlang:system_info(endian) of
big ->