%% -*- 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).