%% -*- 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_icode_cfg). -export([bb/2, bb_add/3, cfg_to_linear/1, is_closure/1, closure_arity/1, linear_to_cfg/1, labels/1, start_label/1, pp/1, pp/2, params/1, params_update/2, pred/2, redirect/4, remove_trivial_bbs/1, remove_unreachable_code/1, succ/2, visit/2, is_visited/2, none_visited/0 ]). -export([postorder/1, reverse_postorder/1]). -define(ICODE_CFG, true). % needed by cfg.inc %%-define(DO_ASSERT, true). -include("../main/hipe.hrl"). -include("hipe_icode.hrl"). -include("../flow/hipe_bb.hrl"). -include("../flow/cfg.hrl"). -include("../flow/cfg.inc"). %%---------------------------------------------------------------------- %% Prototypes for exported functions which are Icode specific %%---------------------------------------------------------------------- -spec labels(cfg()) -> [icode_lbl()]. -spec postorder(cfg()) -> [icode_lbl()]. -spec reverse_postorder(cfg()) -> [icode_lbl()]. -spec params(cfg()) -> hipe_icode:params(). -spec params_update(cfg(), hipe_icode:params()) -> cfg(). -spec is_visited(icode_lbl(), gb_sets:set()) -> boolean(). -spec visit(icode_lbl(), gb_sets:set()) -> gb_sets:set(). -spec bb(cfg(), icode_lbl()) -> 'not_found' | bb(). -spec bb_add(cfg(), icode_lbl(), bb()) -> cfg(). -spec pred(cfg(), icode_lbl()) -> [icode_lbl()]. -spec succ(cfg(), icode_lbl()) -> [icode_lbl()]. -spec redirect(cfg(), icode_lbl(), icode_lbl(), icode_lbl()) -> cfg(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% %% Interface to Icode %% -spec linear_to_cfg(#icode{}) -> cfg(). linear_to_cfg(LinearIcode) -> %% hipe_icode_pp:pp(Icode), Code = hipe_icode:icode_code(LinearIcode), IsClosure = hipe_icode:icode_is_closure(LinearIcode), StartLabel = hipe_icode:label_name(hd(Code)), CFG0 = mk_empty_cfg(hipe_icode:icode_fun(LinearIcode), StartLabel, hipe_icode:icode_data(LinearIcode), IsClosure, hipe_icode:icode_is_leaf(LinearIcode), hipe_icode:icode_params(LinearIcode)), CFG1 = info_update(CFG0, hipe_icode:icode_info(LinearIcode)), CFG2 = case IsClosure of true -> closure_arity_update(CFG1, hipe_icode:icode_closure_arity(LinearIcode)); false -> CFG1 end, ?opt_start_timer("Get BBs icode"), FullCFG = take_bbs(Code, CFG2), ?opt_stop_timer("Get BBs icode"), FullCFG. %% remove_blocks(CFG, []) -> %% CFG; %% remove_blocks(CFG, [Lbl|Lbls]) -> %% remove_blocks(bb_remove(CFG, Lbl), Lbls). -spec is_label(icode_instr()) -> boolean(). is_label(Instr) -> hipe_icode:is_label(Instr). label_name(Instr) -> hipe_icode:label_name(Instr). mk_label(Name) -> hipe_icode:mk_label(Name). mk_goto(Name) -> hipe_icode:mk_goto(Name). branch_successors(Instr) -> hipe_icode:successors(Instr). fails_to(Instr) -> hipe_icode:fails_to(Instr). %% True if instr has no effect. -spec is_comment(icode_instr()) -> boolean(). is_comment(Instr) -> hipe_icode:is_comment(Instr). %% True if instr is just a jump (no side-effects). -spec is_goto(icode_instr()) -> boolean(). is_goto(Instr) -> hipe_icode:is_goto(Instr). -spec is_branch(icode_instr()) -> boolean(). is_branch(Instr) -> hipe_icode:is_branch(Instr). -spec is_pure_branch(icode_instr()) -> boolean(). is_pure_branch(Instr) -> case Instr of #icode_if{} -> true; #icode_goto{} -> true; #icode_switch_val{} -> true; #icode_switch_tuple_arity{} -> true; #icode_type{} -> true; %% false cases below -- XXX: are they correct? #icode_label{} -> false; #icode_move{} -> false; #icode_phi{} -> false; #icode_call{} -> false; #icode_enter{} -> false; #icode_return{} -> false; #icode_begin_try{} -> false; #icode_end_try{} -> false; #icode_begin_handler{} -> false; #icode_fail{} -> false; #icode_comment{} -> false end. -spec is_phi(icode_instr()) -> boolean(). is_phi(I) -> hipe_icode:is_phi(I). phi_remove_pred(I, Pred) -> hipe_icode:phi_remove_pred(I, Pred). %% phi_redirect_pred(I, OldPred, NewPred) -> %% hipe_icode:phi_redirect_pred(I, OldPred, NewPred). redirect_jmp(Jmp, ToOld, ToNew) -> hipe_icode:redirect_jmp(Jmp, ToOld, ToNew). redirect_ops(_, CFG, _) -> %% We do not refer to labels in Icode ops. CFG. %%---------------------------------------------------------------------------- -spec pp(cfg()) -> 'ok'. pp(CFG) -> hipe_icode_pp:pp(cfg_to_linear(CFG)). -spec pp(io:device(), cfg()) -> 'ok'. pp(Dev, CFG) -> hipe_icode_pp:pp(Dev, cfg_to_linear(CFG)). %%---------------------------------------------------------------------------- -spec cfg_to_linear(cfg()) -> #icode{}. cfg_to_linear(CFG) -> Code = linearize_cfg(CFG), IsClosure = is_closure(CFG), Icode = hipe_icode:mk_icode(function(CFG), params(CFG), IsClosure, is_leaf(CFG), Code, data(CFG), hipe_gensym:var_range(icode), hipe_gensym:label_range(icode)), Icode1 = hipe_icode:icode_info_update(Icode, info(CFG)), case IsClosure of true -> hipe_icode:icode_closure_arity_update(Icode1, closure_arity(CFG)); false -> Icode1 end.