%% -*- erlang-indent-level: 2 -*-
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%% http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
-module(hipe_rtl_cfg).
-export([init/1,
labels/1,
params/1, params_update/2,
start_label/1,
succ/2,
pred/2,
bb/2, bb_add/3, bb_insert_between/5,
redirect/4,
remove_trivial_bbs/1, remove_unreachable_code/1,
linearize/1,
pp/1, pp/2]).
-export([preorder/1, postorder/1, reverse_postorder/1]).
-define(RTL_CFG, true). % needed for cfg.inc below
-include("../main/hipe.hrl").
-include("hipe_rtl.hrl").
-include("../flow/cfg.hrl").
-include("../flow/cfg.inc").
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% CFG interface to RTL.
%%
init(Rtl) ->
%% hipe_rtl:pp(Rtl),
Code = hipe_rtl:rtl_code(Rtl),
StartLabel = hipe_rtl:label_name(hd(Code)),
CFG0 = mk_empty_cfg(hipe_rtl:rtl_fun(Rtl),
StartLabel,
hipe_rtl:rtl_data(Rtl),
hipe_rtl:rtl_is_closure(Rtl),
hipe_rtl:rtl_is_leaf(Rtl),
hipe_rtl:rtl_params(Rtl)),
CFG = info_update(CFG0, hipe_rtl:rtl_info(Rtl)),
take_bbs(Code, CFG).
%% @spec is_comment(hipe_rtl:rtl_instruction()) -> boolean()
%% @doc Succeeds if Instr has no effect.
is_comment(Instr) ->
hipe_rtl:is_comment(Instr).
%% @spec is_goto(hipe_rtl:rtl_instruction()) -> boolean()
%% @doc Succeeds if Instr is just a jump (no side-effects).
is_goto(Instr) ->
hipe_rtl:is_goto(Instr).
is_label(Instr) ->
hipe_rtl:is_label(Instr).
label_name(Instr) ->
hipe_rtl:label_name(Instr).
mk_label(Name) ->
hipe_rtl:mk_label(Name).
mk_goto(Name) ->
hipe_rtl:mk_goto(Name).
branch_successors(Instr) ->
case Instr of
#alub{} -> [hipe_rtl:alub_true_label(Instr),
hipe_rtl:alub_false_label(Instr)];
#switch{} -> hipe_rtl:switch_labels(Instr);
#call{} ->
case hipe_rtl:call_fail(Instr) of
[] -> [hipe_rtl:call_continuation(Instr)];
Fail -> [hipe_rtl:call_continuation(Instr),Fail]
end;
#goto{} -> [hipe_rtl:goto_label(Instr)];
#goto_index{} -> hipe_rtl:goto_index_labels(Instr);
_ -> []
end.
fails_to(Instr) ->
case Instr of
#call{} -> [hipe_rtl:call_fail(Instr)];
_ -> []
end.
is_branch(Instr) ->
case Instr of
#alub{} -> true;
#switch{} -> true;
#goto{} -> true;
#goto_index{} -> true;
#enter{} -> true;
#return{} -> true;
#call{} ->
case hipe_rtl:call_fail(Instr) of
[] ->
case hipe_rtl:call_continuation(Instr) of
[] -> false;
_ -> true
end;
_ -> true
end;
_ -> false
end.
is_pure_branch(Instr) ->
case Instr of
#alub{} -> not hipe_rtl:alub_has_dst(Instr);
#switch{} -> true;
#goto{} -> true;
_ -> false
end.
redirect_jmp(Jmp, ToOld, ToNew) ->
hipe_rtl:redirect_jmp(Jmp, ToOld, ToNew).
redirect_ops([Label|Labels], CFG, Map) ->
BB = bb(CFG, Label),
Code = hipe_bb:code(BB),
NewCode = [rewrite(I,Map) || I <- Code],
NewCFG = bb_add(CFG, Label, hipe_bb:code_update(BB, NewCode)),
redirect_ops(Labels, NewCFG, Map);
redirect_ops([],CFG,_) -> CFG.
rewrite(I, Map) ->
case I of
#load_address{} ->
case hipe_rtl:load_address_type(I) of
constant -> I;
_ ->
NewL =
find_new_label(hipe_rtl:load_address_addr(I), Map),
hipe_rtl:load_address_addr_update(I, NewL)
end;
_ -> I
end.
pp(CFG) ->
hipe_rtl:pp(linearize(CFG)).
pp(Dev, CFG) ->
hipe_rtl:pp(Dev, linearize(CFG)).
linearize(CFG) ->
Code = linearize_cfg(CFG),
Rtl = hipe_rtl:mk_rtl(function(CFG),
params(CFG),
is_closure(CFG),
is_leaf(CFG),
Code,
data(CFG),
hipe_gensym:var_range(rtl),
hipe_gensym:label_range(rtl)),
hipe_rtl:rtl_info_update(Rtl, info(CFG)).
%% %% Warning: this arity might not be the true arity.
%% %% The true arity of a closure usually differs.
%% arity(CFG) ->
%% {_M,_F,A} = function(CFG),
%% A.
%% init_gensym(CFG)->
%% HighestVar = find_highest_var(CFG),
%% HighestLabel = find_highest_label(CFG),
%% hipe_gensym:init(),
%% hipe_gensym:set_var(rtl, HighestVar),
%% hipe_gensym:set_label(rtl, HighestLabel).
%%
%% highest_var(Code)->
%% hipe_rtl:highest_var(Code).
is_phi(I) ->
hipe_rtl:is_phi(I).
phi_remove_pred(I, Pred) ->
hipe_rtl:phi_remove_pred(I, Pred).
phi_redirect_pred(I, OldPred, NewPred) ->
hipe_rtl:phi_redirect_pred(I, OldPred, NewPred).