aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/icode
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hipe/icode')
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl31
-rw-r--r--lib/hipe/icode/hipe_icode_type.erl21
2 files changed, 31 insertions, 21 deletions
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 100bc0b0e2..610578dfbc 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -148,7 +148,8 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) ->
{Code3,_Env3} = mk_debug_calltrace(MFA, Env1, Code2),
{Code3,_Env3} = {Code2,Env1}),
%% For stack optimization
- Leafness = leafness(Code3),
+ IsClosure = get_closure_info(MFA, ClosureInfo) =/= not_a_closure,
+ Leafness = leafness(Code3, IsClosure),
IsLeaf = is_leaf_code(Leafness),
Code4 =
[FunLbl |
@@ -156,7 +157,6 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) ->
false -> Code3;
true -> [mk_redtest()|Code3]
end],
- IsClosure = get_closure_info(MFA, ClosureInfo) =/= not_a_closure,
Code5 = hipe_icode:mk_icode(MFA, FunArgs, IsClosure, IsLeaf,
remove_dead_code(Code4),
hipe_gensym:var_range(icode),
@@ -173,12 +173,12 @@ trans_mfa_code(M,F,A, FunBeamCode, ClosureInfo) ->
mk_redtest() -> hipe_icode:mk_primop([], redtest, []).
-leafness(Is) -> % -> true, selfrec, or false
- leafness(Is, true).
+leafness(Is, IsClosure) -> % -> true, selfrec, closure, or false
+ leafness(Is, IsClosure, true).
-leafness([], Leafness) ->
+leafness([], _IsClosure, Leafness) ->
Leafness;
-leafness([I|Is], Leafness) ->
+leafness([I|Is], IsClosure, Leafness) ->
case I of
#icode_comment{} ->
%% BEAM self-tailcalls become gotos, but they leave
@@ -191,7 +191,7 @@ leafness([I|Is], Leafness) ->
'self_tail_recursive' -> selfrec; % call_only to selfrec
_ -> Leafness
end,
- leafness(Is, NewLeafness);
+ leafness(Is, IsClosure, NewLeafness);
#icode_call{} ->
case hipe_icode:call_type(I) of
'primop' ->
@@ -199,12 +199,12 @@ leafness([I|Is], Leafness) ->
call_fun -> false; % Calls closure
enter_fun -> false; % Calls closure
#apply_N{} -> false;
- _ -> leafness(Is, Leafness) % Other primop calls are ok
+ _ -> leafness(Is, IsClosure, Leafness) % Other primop calls are ok
end;
T when T =:= 'local' orelse T =:= 'remote' ->
{M,F,A} = hipe_icode:call_fun(I),
case erlang:is_builtin(M, F, A) of
- true -> leafness(Is, Leafness);
+ true -> leafness(Is, IsClosure, Leafness);
false -> false
end
end;
@@ -223,11 +223,12 @@ leafness([I|Is], Leafness) ->
T when T =:= 'local' orelse T =:= 'remote' ->
{M,F,A} = hipe_icode:enter_fun(I),
case erlang:is_builtin(M, F, A) of
- true -> leafness(Is, Leafness);
+ true -> leafness(Is, IsClosure, Leafness);
+ _ when IsClosure -> leafness(Is, IsClosure, closure);
_ -> false
end
end;
- _ -> leafness(Is, Leafness)
+ _ -> leafness(Is, IsClosure, Leafness)
end.
%% XXX: this old stuff is passed around but essentially unused
@@ -235,12 +236,20 @@ is_leaf_code(Leafness) ->
case Leafness of
true -> true;
selfrec -> true;
+ closure -> false;
false -> false
end.
needs_redtest(Leafness) ->
case Leafness of
true -> false;
+ %% A "leaf" closure may contain tailcalls to non-closures in addition to
+ %% what other leaves may contain. Omitting the redtest is useful to generate
+ %% shorter code for closures generated by (fun F/A), and is safe since
+ %% control flow cannot return to a "leaf" closure again without a reduction
+ %% being consumed. This is true since no function that can call a closure
+ %% will ever have its redtest omitted.
+ closure -> false;
selfrec -> true;
false -> true
end.
diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl
index 815d1e57a8..aafaeb5a0a 100644
--- a/lib/hipe/icode/hipe_icode_type.erl
+++ b/lib/hipe/icode/hipe_icode_type.erl
@@ -1410,9 +1410,10 @@ transform_element2(I) ->
NewIndex =
case test_type(integer, IndexType) of
true ->
- case t_number_vals(IndexType) of
- unknown -> unknown;
- [_|_] = Vals -> {number, Vals}
+ case {number_min(IndexType), number_max(IndexType)} of
+ {Lb0, Ub0} when is_integer(Lb0), is_integer(Ub0) ->
+ {number, Lb0, Ub0};
+ {_, _} -> unknown
end;
_ -> unknown
end,
@@ -1427,19 +1428,19 @@ transform_element2(I) ->
_ -> unknown
end,
case {NewIndex, MinSize} of
- {{number, [_|_] = Ns}, {tuple, A}} when is_integer(A) ->
- case lists:all(fun(X) -> 0 < X andalso X =< A end, Ns) of
+ {{number, Lb, Ub}, {tuple, A}} when is_integer(A) ->
+ case 0 < Lb andalso Ub =< A of
true ->
- case Ns of
- [Idx] ->
+ case {Lb, Ub} of
+ {Idx, Idx} ->
[_, Tuple] = hipe_icode:args(I),
update_call_or_enter(I, #unsafe_element{index = Idx}, [Tuple]);
- [_|_] ->
+ {_, _} ->
NewFun = {element, [MinSize, valid]},
update_call_or_enter(I, NewFun)
end;
false ->
- case lists:all(fun(X) -> hipe_tagscheme:is_fixnum(X) end, Ns) of
+ case lists:all(fun(X) -> hipe_tagscheme:is_fixnum(X) end, [Lb, Ub]) of
true ->
NewFun = {element, [MinSize, fixnums]},
update_call_or_enter(I, NewFun);
@@ -1454,7 +1455,7 @@ transform_element2(I) ->
NewFun = {element, [MinSize, fixnums]},
update_call_or_enter(I, NewFun);
false ->
- NewFun = {element, [MinSize, NewIndex]},
+ NewFun = {element, [MinSize, NewIndex]},
update_call_or_enter(I, NewFun)
end
end.