📄 hipe_icode.erl
字号:
mk_new_reg/0, %% mk_new_reg() mk_phi/1, %% mk_phi(Id) mk_phi/2 %% mk_phi(Id, ArgList) ]).%%%% Identifiers%%-export([%% is_fail/1, is_return/1, is_move/1, %% is_begin_try/1, is_begin_handler/1, %% is_end_try/1, is_goto/1, is_label/1, is_comment/1, is_const/1, is_const_fun/1, is_var/1, is_annotated_var/1, is_fvar/1, is_reg/1, is_var_or_fvar_or_reg/1, %% is_uncond/1, %% is_fmove/1, is_phi/1]).%%%% Selectors%%-export([phi_dst/1, phi_id/1, %% phi_args/1, phi_arg/2, phi_arglist/1, phi_enter_pred/3, phi_remove_pred/2, phi_redirect_pred/3, move_dst/1, move_src/1, move_src_update/2, begin_try_label/1, begin_try_successor/1, begin_handler_dstlist/1, label_name/1, comment_text/1, return_vars/1, fail_args/1, fail_class/1, fail_label/1, fail_set_label/2, var_name/1, var_annotation/1, fvar_name/1, %% reg_name/1, reg_is_gcsafe/1, const_value/1, %% info/1, fmove_dst/1, fmove_src/1 ]).%%%% Misc%%-export([args/1, uses/1, defines/1, is_safe/1, strip_comments/1, subst/2, subst_uses/2, subst_defines/2, redirect_jmp/3, successors/1, fails_to/1, is_branch/1 ]).-export([highest_var/1, highest_label/1]).%%---------------------------------------------------------------------%% %% Icode%%%%---------------------------------------------------------------------%% @spec mk_icode(Fun::mfa(), Params::[var()], Closure::bool(), %% Leaf::bool(), Code::[icode_instruction()],%% VarRange::{integer(),integer()}, %% LabelRange::{integer(),integer()}) -> #icode{}%%mk_icode(Fun, Params, Closure, Leaf, Code, VarRange, LabelRange) -> #icode{'fun'=Fun, params=Params, code=Code, is_closure=Closure, is_leaf=Leaf, data=hipe_consttab:new(), var_range=VarRange, label_range=LabelRange}.%% @spec mk_icode(Fun::mfa(), Params::[var()], Closure::bool(), Leaf::bool(), %% Code::[icode_instruction()], Data::data(),%% VarRange::{integer(),integer()}, %% LabelRange::{integer(),integer()}) -> #icode{}%%mk_icode(Fun, Params, Closure, Leaf, Code, Data, VarRange, LabelRange) -> #icode{'fun'=Fun, params=Params, code=Code, data=Data, is_closure=Closure, is_leaf=Leaf, var_range=VarRange, label_range=LabelRange}.mk_typed_icode(Fun, Params, Closure, Leaf, Code, VarRange, LabelRange, ArgType) -> #icode{'fun'=Fun, params=Params, code=Code, is_closure=Closure, is_leaf=Leaf, data=hipe_consttab:new(), var_range=VarRange, label_range=LabelRange, info=[{arg_type, ArgType}]}.%% @spec icode_fun(I::#icode{}) -> mfa()icode_fun(#icode{'fun'=MFA}) -> MFA.%% @spec icode_params(I::#icode{}) -> [var()]icode_params(#icode{params=Params}) -> Params.%% @spec icode_params_update(I::#icode{}, [var()]) -> #icode{}icode_params_update(Icode, Params) -> Icode#icode{params=Params}.%% @spec icode_is_closure(I::#icode{}) -> bool()icode_is_closure(#icode{is_closure=Closure}) -> Closure.%% @spec icode_is_leaf(I::#icode{}) -> bool()icode_is_leaf(#icode{is_leaf=Leaf}) -> Leaf.%% @spec icode_code(I::#icode{}) -> [icode_instruction()]icode_code(#icode{code=Code}) -> Code.%% @spec icode_code_update(I::#icode{}, [icode_instruction()]) -> #icode{}icode_code_update(Icode, NewCode) -> Vmax = highest_var(NewCode), Lmax = highest_label(NewCode), Icode#icode{code=NewCode, var_range={0,Vmax}, label_range={0,Lmax}}.%% @spec icode_data(I::#icode{}) -> data()icode_data(#icode{data=Data}) -> Data.%% %% @spec icode_data_update(I::#icode{}, data()) -> #icode{}%% icode_data_update(Icode, NewData) -> Icode#icode{data=NewData}.icode_var_range(#icode{var_range=VarRange}) -> VarRange.icode_label_range(#icode{label_range=LabelRange}) -> LabelRange.icode_info(#icode{info=Info}) -> Info.icode_info_update(Icode, Info) -> Icode#icode{info=Info}.icode_closure_arity_update(Icode, Arity) -> Icode#icode{closure_arity=Arity}.icode_closure_arity(#icode{closure_arity=Arity}) -> Arity. %% ____________________________________________________________________%% Instructions%%%%%% if%%mk_if(Op, Args, TrueLbl, FalseLbl) -> #'if'{op=Op, args=Args, true_label=TrueLbl, false_label=FalseLbl, p=0.5}.%% mk_if(Op, Args, TrueLbl, FalseLbl, P) ->%% #'if'{op=Op, args=Args, true_label=TrueLbl, false_label=FalseLbl, p=P}.if_op(#'if'{op=Op}) -> Op.if_op_update(IF, NewOp) -> IF#'if'{op=NewOp}.if_args(#'if'{args=Args}) -> Args.if_true_label(#'if'{true_label=TrueLbl}) -> TrueLbl.if_true_label_update(IF, TrueLbl) -> IF#'if'{true_label=TrueLbl}.if_false_label(#'if'{false_label=FalseLbl}) -> FalseLbl.if_false_label_update(IF, FalseLbl) -> IF#'if'{false_label=FalseLbl}.if_pred(#'if'{p=P}) -> P.%%%% switch_val%%mk_switch_val(Arg, FailLbl, Length, Cases) -> #switch_val{arg=Arg, fail_label=FailLbl, length=Length, cases=Cases}.switch_val_arg(#switch_val{arg=Arg}) -> Arg.switch_val_fail_label(#switch_val{fail_label=FailLbl}) -> FailLbl.switch_val_fail_label_update(SV, FailLbl) -> SV#switch_val{fail_label=FailLbl}.%% switch_val_length(#switch_val{length=Length}) -> Length.switch_val_cases(#switch_val{cases=Cases}) -> Cases.switch_val_cases_update(SV, NewCases) -> SV#switch_val{cases = NewCases}.%%%% switch_tuple_arity%%mk_switch_tuple_arity(Arg, FailLbl, Length, Cases) -> #switch_tuple_arity{arg=Arg, fail_label=FailLbl, length=Length, cases=Cases}.switch_tuple_arity_arg(#switch_tuple_arity{arg=Arg}) -> Arg.switch_tuple_arity_fail_label(#switch_tuple_arity{fail_label=FailLbl}) -> FailLbl.switch_tuple_arity_fail_label_update(S, FailLbl) -> S#switch_tuple_arity{fail_label=FailLbl}.%% switch_tuple_arity_length(#switch_tuple_arity{length=Length}) -> Length.switch_tuple_arity_cases(#switch_tuple_arity{cases=Cases}) -> Cases.switch_tuple_arity_cases_update(Cond, NewCases) -> Cond#switch_tuple_arity{cases = NewCases}.%%%% type%%mk_type(X, Type, TrueLbl, FalseLbl) -> #type{type=Type, args=X, true_label=TrueLbl, false_label=FalseLbl, p=0.5}.mk_type(X, Type, TrueLbl, FalseLbl, P) -> #type{type=Type, args=X, true_label=TrueLbl, false_label=FalseLbl, p=P}.type_type(#type{type=Type}) -> Type.type_args(#type{args=Args}) -> Args.%% type_args_update(T, Args) -> T#type{args=Args}.type_true_label(#type{true_label=TrueLbl}) -> TrueLbl.type_false_label(#type{false_label=FalseLbl}) -> FalseLbl.type_pred(#type{p=P}) -> P.is_type(#type{}) -> true;is_type(_) -> false.%%%% goto%%mk_goto(Lbl) -> #goto{label=Lbl}.goto_label(#goto{label=Lbl}) -> Lbl.is_goto(#goto{}) -> true;is_goto(_) -> false.%%%% return%%mk_return(Vars) -> #return{vars=Vars}.return_vars(#return{vars=Vars}) -> Vars.is_return(#return{}) -> true;is_return(_) -> false. %%%% fail%%%% mk_fail(Args) when is_list(Args) -> #fail{class=error, args=Args}.mk_fail(Args, Class) when is_list(Args) -> case Class of error -> ok; exit -> ok; rethrow -> ok; throw -> ok; _ -> exit({bad_fail_class, Class}) end, #fail{class=Class, args=Args}.%% mk_fail(Args, Class, Label) when is_list(Args) ->%% #fail{class=Class, args=Args, fail_label=Label}.fail_class(#fail{class=Class}) -> Class.fail_args(#fail{args=Args}) -> Args.fail_label(#fail{fail_label=Label}) -> Label.fail_set_label(I=#fail{}, Label) -> I#fail{fail_label = Label}.%%%% move%%mk_move(Dst, Src) -> #move{dst=Dst, src=Src}.move_dst(#move{dst=Dst}) -> Dst.move_src(#move{src=Src}) -> Src.move_src_update(M, NewSrc) -> M#move{src=NewSrc}.is_move(#move{}) -> true;is_move(_) -> false.%%%% phi%%%% The id field is not entirely redundant. It is used in mappings%% in the SSA pass since the dst field can change.mk_phi(Var) -> #phi{dst = Var, id = Var, arglist = []}.mk_phi(Var, ArgList) -> #phi{dst = Var, id = Var, arglist = ArgList}.phi_dst(#phi{dst=Dst}) -> Dst.phi_id(#phi{id=Id}) -> Id.phi_arglist(#phi{arglist=ArgList}) -> ArgList.phi_args(P) -> [X || {_,X} <- phi_arglist(P)].phi_arg(P, Pred) -> case lists:keysearch(Pred, 1, phi_arglist(P)) of {value, {_, Var}} -> Var; false -> exit({'No such predecessor to phi', {Pred, P}}) end.is_phi(#phi{}) -> true;is_phi(_) -> false.phi_enter_pred(Phi, Pred, Var) -> Phi#phi{arglist=[{Pred,Var}|lists:keydelete(Pred, 1, phi_arglist(Phi))]}.phi_remove_pred(Phi, Pred) -> NewArgList = lists:keydelete(Pred, 1, phi_arglist(Phi)), case NewArgList of [Arg] -> %% the phi should be turned into a move instruction {_Label,Var} = Arg, mk_move(phi_dst(Phi), Var); [_|_] -> Phi#phi{arglist=NewArgList} end.phi_argvar_subst(P, Subst) -> NewArgList = [{Pred, subst1(Subst, Var)} || {Pred,Var} <- phi_arglist(P)], P#phi{arglist=NewArgList}.phi_redirect_pred(P, OldPred, NewPred) -> Subst = [{OldPred, NewPred}], NewArgList = [{subst1(Subst, Pred), Var} || {Pred,Var} <- phi_arglist(P)], P#phi{arglist=NewArgList}.%%%% primop and guardop%%%% Whether a function is a "primop" - i.e., an internal thing - or not,%% is really only shown by its name. An {M,F,A} always represents a%% function in some Erlang module (althought it might be a BIF, and%% could possibly be inline expanded). It is convenient to let the%% constructor functions check the name and set the type automatically,%% especially for guardops - some guardops are primitives and some are%% MFA:s, and this way we won't have to rewrite all calls to mk_guardop%% to flag whether they are primops or not.mk_primop(DstList, Fun, ArgList) -> mk_primop(DstList, Fun, ArgList, [], []).mk_primop(DstList, Fun, ArgList, Continuation, Fail) -> Type = op_type(Fun), make_call(DstList, Fun, ArgList, Type, Continuation, Fail, false).%% Note that a 'guardop' is just a call that occurred in a guard. In%% this case, we should always have continuation labels True and False.mk_guardop(DstList, Fun, ArgList, True, False) -> Type = op_type(Fun), make_call(DstList, Fun, ArgList, Type, True, False, true).op_type(Fun) -> case is_mfa(Fun) of true -> remote; false -> primop end.is_mfa({M,F,A}) when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 -> true;is_mfa(_) -> false.%%%% call%%mk_typed_call(Dst, M, F, Args, Type, DstType) -> Call = mk_call(Dst, M, F, Args, Type), Call#call{dst_type=DstType}.mk_call(DstList, M, F, ArgList, Type) -> mk_call(DstList, M, F, ArgList, Type, [], [], false).%% mk_call(DstList, M, F, ArgList, Type, Continuation, Fail) ->%% mk_call(DstList, M, F, ArgList, Type, Continuation, Fail, false).mk_call(DstList, M, F, ArgList, Type, Continuation, Fail, Guard) when is_atom(M), is_atom(F) -> case Type of local -> ok; remote -> ok; _ -> exit({bad_call_type, Type}) end, Fun = {M,F,length(ArgList)}, make_call(DstList, Fun, ArgList, Type, Continuation, Fail, Guard).%% The common constructor for all calls (for internal use only)%%%% Note: If the "guard" flag is `true', it means that if the call fails,%% we can simply jump to the Fail label (if it exists) without%% generating any additional exception information - it isn't needed.%%make_call(DstList, Fun, ArgList, Type, Continuation, Fail, InGuard) -> #call{dstlist=DstList, 'fun'=Fun, args=ArgList, type=Type, continuation=Continuation, fail_label=Fail, in_guard=InGuard}.call_dstlist(#call{dstlist=DstList}) -> DstList.call_dstlist_update(C,Dest) -> C#call{dstlist=Dest}.call_type(#call{type=Type}) -> Type.call_dst_type(#call{dst_type=DstType}) -> DstType.%% @spec (C::call()) -> [arg()]call_args(#call{args=Args}) -> Args.%% @spec (C::call(), [arg()]) -> call()call_args_update(C,Args) -> C#call{args=Args}.call_fun(#call{'fun'=Fun}) -> Fun.%% Note that updating the name field requires recomputing the call type,%% in case it changes from a remote/local call to a primop call.call_fun_update(C, Fun) -> Type = case is_mfa(Fun) of true -> call_type(C); false -> primop end, C#call{'fun'=Fun, type=Type}.call_continuation(#call{continuation=Continuation}) -> Continuation.call_fail_label(#call{fail_label=Fail}) -> Fail.call_set_continuation(I, Continuation) -> I#call{continuation = Continuation}.call_set_fail_label(I=#call{}, Fail) -> case Fail of [] -> I#call{fail_label=Fail, in_guard=false}; _ -> I#call{fail_label=Fail} end.is_call(#call{}) -> true;is_call(_) -> false.call_in_guard(#call{in_guard=InGuard}) -> InGuard.%%%% enter%%mk_enter(M, F, Args, Type) when is_atom(M), is_atom(F) -> case Type of local -> ok; remote -> ok; _ -> exit({bad_enter_type, Type}) end, #enter{'fun'={M,F,length(Args)}, args=Args, type=Type}.enter_fun(#enter{'fun'=Fun}) -> Fun.enter_fun_update(E, Fun) -> Type = case is_mfa(Fun) of true -> enter_type(E); false -> primop end, E#enter{'fun'=Fun, type=Type}.enter_args(#enter{args=Args}) -> Args.enter_args_update(E, Args) -> E#enter{args=Args}.enter_type(#enter{type=Type}) -> Type.is_enter(#enter{}) -> true;is_enter(_) -> false. mk_enter_primop(Op, Args) -> #enter{'fun'=Op, args=Args, type=primop}.%%%% begin_try%%%% The reason that begin_try is a branch instruction is just so that it%% keeps the fail-to block linked into the cfg, until the exception%% handling instructions are eliminated.mk_begin_try(Label, Successor) -> #begin_try{label=Label, successor=Successor}.begin_try_label(#begin_try{label=Label}) -> Label.begin_try_successor(#begin_try{successor=Successor}) -> Successor.%%%% end_try%%mk_end_try() -> #end_try{}.%%%% begin_handler%%mk_begin_handler(Dstlist) -> #begin_handler{dstlist=Dstlist}.begin_handler_dstlist(#begin_handler{dstlist=Dstlist}) -> Dstlist.is_begin_handler(#begin_handler{}) -> true;is_begin_handler(_) -> false.%%%% label%%mk_label(Name) when is_integer(Name) -> #label{name=Name}.label_name(#label{name=Name}) -> Name.is_label(#label{}) ->true;is_label(_) -> false.%%%% comment%%%% @spec mk_comment(Txt::term()) -> #comment{}%% @doc If `Txt' is a list of characters (possibly deep), it will be%% printed as a string; otherwise, `Txt' will be printed as a term.mk_comment(Txt) -> #comment{text=Txt}.comment_text(#comment{text=Txt}) -> Txt.%% @spec is_comment(Instr::icode_instruction()) -> bool()%% @doc True if this is the Icode instruction for comments.is_comment(#comment{}) -> true;is_comment(_) -> false.%% ____________________________________________________________________%% %%%% Arguments (variables and constants)%%-record(const, {value}).-record(const_fun, {'fun'}).mk_const(C) -> #const{value={flat,C}}.%% mk_const_fun(MFA,U,I,Args) -> {const,{const_fun,{MFA,U,I,Args}}}.const_value(#const{value={flat,X}}) -> X;const_value(#const{value=#const_fun{'fun'=X}}) -> X.%% @spec is_const(icode_arg()) -> bool()is_const(#const{}) -> true;is_const(_) -> false.%% @spec is_const_fun(icode_arg()) -> bool()is_const_fun(#const{value=#const_fun{}}) -> true;is_const_fun(_) -> false.-record(var, {name}). % % type=erl_types:t_any()}). % type()mk_var(V) -> #var{name=V}.var_name(#var{name=Name}) -> Name.%% @spec is_var(icode_arg()) -> bool()is_var(#var{}) -> true;is_var(_) -> false.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -