📄 hipe_icode.erl
字号:
%% -*- erlang-indent-level: 2 -*-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% HiPE Intermediate Code%% ====================================================================%% Filename : hipe_icode.erl%% Module : hipe_icode%% Purpose : Provide primops for the Icode data structure.%% History : 1997-? Erik Johansson (happi@csd.uu.se): Created.%% 2001-01-30 EJ (happi@csd.uu.se):%% Apply, primop, guardop removed%% 2003-03-15 ES (happi@acm.org):%% Started commenting in Edoc.%% Moved pretty printer to separate file.%%%% $Id$%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@doc%% This module implements "Linear Icode" and Icode instructions. %% %% <p> Icode is a simple (in that it has few instructions) imperative%% language, used as the first Intermediate Code in the HiPE compiler.%% Icode is closely related to Erlang, and Icode instructions operate%% on Erlang terms. </p>%%%% <h2><a href="#type-icode">Icode</a></h2>%%%% <p> Linear Icode for a function consists of:%% <ul>%% <li> the function's name (`{M,F,A}'), </li>%% <li> a list of parameters, </li>%% <li> a list of instructions, </li>%% <li> data, </li>%% <li> information about whether the function is a leaf function, </li>%% <li> information about whether the function is a closure, and </li>%% <li> the range for labels and variables in the code. </li>%% </ul>%% </p>%%%% <h2><a href="#type-icode_instruction">Icode Instructions</a> (and%% their components)</h2>%%%% Control flow:%% <dl>%% <dt><code><a href="#type-if">'if'</a> %% {Cond::<a href="#type-cond">cond()</a>, %% Args::[<a href="#type-arg">arg()</a>],%% TrueLabel::<a href="#type-label_name">label_name()</a>, %% FalseLabel::<a href="#type-label_name">label_name()</a>%% } :: %% <a href="#type-icode_instruction">icode_instruction()</a></code></dt>%% <dd>%% The if instruction compares the arguments (Args) with%% condition (Cond) and jumps to either TrueLabel or%% FalseLabel. (At the moment...) There are only binary%% conditions so the number of arguments should be two.%% <p>%% An if instructions ends a basic block and should be followed%% by a label (or be the last instruction of the code).%% </p></dd>%%%% <dt><code><a href="#type-switch_val">switch_val</a> %% {Arg::<a href="#type-arg">arg()</a>, %% FailLabel::<a href="#type-label_name">label_name()</a>, %% Length::integer(), %% Cases::[{<a href="#type-symbol">symbol()</a>,<a%% href="#type-label_name">label_name()</a>}] %% }::%% <a href="#type-icode_instruction">icode_instruction()</a></code></dt>%% <dd>%% The switch_val instruction compares the argument Arg to the%% symbols in the lists Cases, control is transfered to the label%% that corresponds to the first symbol that matches. If no%% symbol matches control is transfered to FailLabel. (NOTE: The%% length argument is not currently in use.)%% <p>%% The switch_val instruction can be assumed to be implemented as%% efficiently as possible given the symbols in the case%% list. (Jump-table, bianry-serach, or nested ifs)%% </p><p>%% A switch_val instructions ends a basic block and should be%% followed by a label (or be the last instruction of the code).%% </p></dd>%%%% <dt><code><a href="#type-switch_tuple_arity">switch_tuple_arity</a>%% {%% Arg::<a href="#type-arg">arg()</a>, %% FailLabel::<a href="#type-label_name">label_name()</a>, %% Length::integer(), %% Cases::[{integer(),<a href="#type-label_name">label_name()</a>}]%% }::%% <a href="#type-icode_instruction">icode_instruction()</a></code></dt>%% <dd>%% The switch_tuple_arity instruction compares the size of the%% tuple in the argument Arg to the integers in the lists Cases,%% control is transfered to the label that corresponds to the%% first integer that matches. If no integer matches control is%% transfered to FailLabel. (NOTE: The length argument is not%% currently in use.)%% <p>%% The switch_tuple_arity instruction can be assumed to be%% implemented as efficently as possible given the symbols in the%% case list. (Jump-table, bianry-serach, or nested ifs)%% </p><p>%% A switch_tuple_arity instructions ends a basic block and%% should be followed by a label (or be the last instruction of%% the code).%% </p></dd>%%%% <dt>`type {typ_expr, arg, true_label, false_label}}'</dt>%% <dt>`goto {label}'</dt>%% <dt>`label {name}'</dt>%% </dl>%%%% Moves:%% <dl>%% <dt>`move {dst, src}'</dt>%% <dt>`fmove {dst, src}'</dt>%% <dt>`phi {dst, arglist}'</dt>%% </dl>%%%% Function application:%% <dl>%% <dt>`call {[dst], fun, [arg], type, continuation, fail,%% in_guard}'</dt>%% <dd>%% Where `type' is one of {`local', `remote', `primop'}%% and `in_guard' is either `true' or `false'.</dd>%% <dt>`enter {fun, [arg], type}'</dt>%% <dd>%% Where `type' is one of {`local', `remote', `primop'}%% and `in_guard' is either `true' or `false'.</dd>%% <dt>`return {[var]}'</dt>%% <dd>%% <strong>WARNING:</strong> Multiple return values are yet not%% fully implemented and tested.%% </dd>%% </dl>%%%% Error handling:%% <dl>%% <dt>`begin_try {label, successor}'</dt>%% <dt>`end_try'</dt>%% <dt>`begin_handler {dstlist}'</dt>%% <dt>`fail {Args, Class}'</dt>%% <dd>Where `Class' is one of %% {`exit', `throw', `error', `rethrow'}. For `error/2', `[args]'%% is `[Reason,Trace]'. For `rethrow', `Args' is%% `[Exception,Reason]' - this only occurs in autogenerated code.%% </dd>%% </dl>%%%% Comments:%% <dl>%% <dt>`comment{Text::string()}'</dt>%% </dl>%%%% <h4>Notes</h4>%%%% <p> A constant can only show up on the RHS of a `move' instruction%% and in `if' and `switch_*'</p>%% <p>%% Classification of primops should be like this:%% <ul>%% <li> `erlang:exit/1, erlang:throw/1, erlang:error/1,%% erlang:error/2, erlang:fault/1',%% and `erlang:fault/2' should use the%% {@link fail(). fail-instruction} in Icode.</li>%% <li> Calls or tail-recursive calls to BIFs, operators, or internal%% functions should be implemented with `call' or `enter' %% respectively, with the primop flag set.</li>%% <li> All other Erlang functions should be implemented with `call'%% or `enter' respectively, without the primop flag set.</li>%% </ul>%% </p>%%%% <h4>Primops</h4>%%%% <pre>%% Constructors:%% cons - [Car, Cdr]%% mktuple - [Element1, Element2, ..., ElementN]%% call_fun - [BoundArg1, ..., BoundArgN, Fun]%% enter_fun - [BoundArg1, ..., BoundArgN, Fun]%% #mkfun{} - [FreeVar1, FreeVar2, ..., FreeVarN]%%%% Binaries:%% bs_init%% {bs_put_string, Bytes, Size}%% bs_final%%%% Selectors:%% element - [Index, Tuple]%% unsafe_hd - [List]%% unsafe_tl - [List]%% #unsafe_element{} - [Tuple]%% #unsafe_update_element{} - [Tuple, Val]%% #closure_element{} - [Fun]%%%% Arithmetic: [Arg1, Arg2]%% '+', '-', '*', '/', 'div', 'rem',%% 'band', 'bor', 'bxor', 'bnot', 'bsl', 'bsr'%%%% Receive: %% check_get_msg - []%% next_msg - []%% select_msg - []%% set_timeout - [Timeout]%% clear_timeout - []%% suspend_msg - []%%%% </pre>%%%% <h4>Guardops: (primops that can be used in guards and can fail)</h4>%% <pre>%% Selectors:%% unsafe_hd - [List]%% unsafe_tl - [List]%% #element{} - [Index, Tuple]%% #unsafe_element{} - [Tuple]%%%% Arithmetic: [Arg1, Arg2]%% '+', '-', '*', '/', 'div', 'rem',%% 'band', 'bor', 'bxor', 'bnot', 'bsl', 'bsr',%% fix_add, fix_sub %% Do these exist?%%%% Concurrency:%% {erlang,self,0} - []%% </pre>%%%%%% <h4>Relational Operations (Cond in if instruction)</h4>%% <pre>%% gt, lt, geq, leq,%% eqeq, neq, exact_eqeq, exact_neq%% </pre>%%%% <h4>Type tests</h4>%% <pre>%% list%% nil%% cons%% tuple%% {tuple, N}%% atom%% {atom, Atom}%% constant%% number%% integer%% {integer, N}%% fixnum%% bignum%% float%% pid%% port%% {record, Atom, Size}%% reference%% binary%% function%% </pre>%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%=====================================================================-module(hipe_icode).-include("../main/hipe.hrl").-include("hipe_icode.hrl").%% @type icode(Fun, Params, IsClosure, IsLeaf, Code, Data, VarRange,LabelRange)%% Fun = mfa()%% Params = [var()]%% IsClosure = bool()%% IsLeaf = bool()%% Code = [icode_instruction()]%% Data = data()%% VarRange = {integer(),integer()}%% LabelRange = {integer(),integer()}%%%% @type icode_instruction(I) %% I = if() | switch_val() | switch_tuple_arity() | type() | goto()%% | label() | move() | fmove() | phi() | call() | enter() | return() %% | begin_try() | end_try() | begin_handler() | fail() | comment()%%%% @type if(Cond, Args, TrueLabel, FalseLabel)%% Cond = cond()%% Args = [arg()]%% TrueLabel = label_name()%% FalseLabel = label_name()%%%% @type switch_val(Arg, FailLabel, Length, Cases) %% Arg = arg()%% FailLabel=label_name()%% Length = integer()%% Cases = [{symbol(),label_name()}]%%%% @type switch_tuple_arity(Arg, FailLabel, Length, Cases)%% Arg = arg()%% FailLabel = label_name()%% Length = integer()%% Cases = [{symbol(), label_name()}]%%%% @type type(TypeExpr, Arg, True_label, False_label)%% TypeExpr = type_type()%% Args = [arg()]%% TrueLabel = label_name()%% FalseLabel = label_name()%%%% @type goto(Label) Label = label_name()%%%% @type label(Name) Name = label_name()%%%% @type move(Dst, Src) Dst = var() Src = arg()%%%% @type fmove(Dst, Src) Dst = fvar() Src = farg()%%%% @type phi(Dst, Id, Arglist) %% Dst = var() | fvar()%% Id = var() | fvar()%% Arglist = [{Pred, Src}]%% Pred = label_name()%% Src = var() | fvar() %%%% @type call(Dst, Fun, Arg, Type, Continuation, InGuard)%% Dst = [var()]%% Fun = mfa() | primop() | closure() %% Arg = [var()]%% Type = call_type()%% Continuation = [] | label_name()%% Fail = [] | label_name()%% InGuard = bool()%%%% @type enter(Fun, Arg, Type)%% Fun = mfa() | primop() | closure() %% Arg = [var()] %% Type = call_type()%%%% @type return (Vars) Vars = [var()]%%%% @type begin_try(Fail, Successor) %% Fail = label_name()%% Successor = label_name()%%%% @type end_try()%%%% @type begin_handler(Dst) %% Dst = [var()]%%%% @type fail(Args,Class,Label)%% Args = [var()]%% Class = exit_class()%% Label = label_name()%%%% @type comment(Text) Text = string()%% @type call_type() = 'local' | 'remote' | 'primop'%% @type exit_class() = 'exit' | 'throw' | 'error' | 'rethrow'%% @type cond() = gt | lt | geq | leq | eqeq | neq | exact_eqeq | exact_neq%% @type type_type() = %% list%% | nil%% | cons%% | tuple%% | {tuple, integer()}%% | atom%% | {atom, atom()}%% | constant%% | number%% | integer%% | {integer, integer()}%% | fixnum%% | bignum%% | float%% | pid%% | port%% | {record, atom(), integer()}%% | reference%% | binary%% | function%%%% @type mfa(Mod,Fun,Arity) = {atom(),atom(),byte()}%% @type arg() = var() | const()%% @type farg() = fvar() | float()%% @type var(Name) Name = integer()%% @type fvar(Name) Name = integer()%% @type label_name(Name) Name = integer()%% @type symbol(S) = atom() | number()%% @type const(C) C = const_fun() | immediate()%% @type const_fun(MFA,U,I,Args) = {MFA,U,I,Args}%% MFA = mfa()%% U = integer()%% I = integer()%% Args = [var()]%% @type immediate(I) = I%% I = term()%% @end%% ____________________________________________________________________%%%% Exports%%-export([mk_icode/7, %% mk_icode(Fun, Params, IsClosure, IsLeaf, %% Code, VarRange, LabelRange) mk_icode/8, %% mk_icode(Fun, Params, IsClosure, IsLeaf, %% Code, Data, VarRange, LabelRange) mk_typed_icode/8, icode_fun/1, icode_params/1, icode_params_update/2, icode_is_closure/1, icode_closure_arity/1, icode_closure_arity_update/2, icode_is_leaf/1, icode_code/1, icode_code_update/2, icode_data/1, %% icode_data_update/2, icode_var_range/1, icode_label_range/1, icode_info/1, icode_info_update/2]).-export([mk_if/4, %% mk_if(Op, Args, TrueLbl, FalseLbl) %% mk_if/5, %% mk_if(Op, Args, TrueLbl, FalseLbl, Prob) if_op/1, if_op_update/2, if_true_label/1, if_false_label/1, if_args/1, if_pred/1, %% is_if/1, mk_switch_val/4, %% mk_switch_val/5, switch_val_arg/1, switch_val_fail_label/1, %% switch_val_length/1, switch_val_cases/1, switch_val_cases_update/2, %% is_switch_val/1, mk_switch_tuple_arity/4, %% mk_switch_tuple_arityl/5, switch_tuple_arity_arg/1, switch_tuple_arity_fail_label/1, switch_tuple_arity_fail_label_update/2, %% switch_tuple_arity_length/1, switch_tuple_arity_cases/1, switch_tuple_arity_cases_update/2, %% is_switch_tuple_arity/1, mk_type/4, %% mk_type(Args, Type, TrueLbl, FalseLbl) mk_type/5, %% mk_type(Args, Type, TrueLbl, FalseLbl, P) type_args/1, %% type_args_update/2, type_type/1, type_true_label/1, type_false_label/1, type_pred/1, is_type/1, mk_guardop/5, %% mk_guardop(Dst, Fun, Args, Continuation, Fail) mk_primop/3, %% mk_primop(Dst, Fun, Args) mk_primop/5, %% mk_primop(Dst, Fun, Args, Cont, Fail) mk_typed_call/6, %% mk_call(Dst, Mod, Fun, Args, Type, DstType) mk_call/5, %% mk_call(Dst, Mod, Fun, Args, Type) %% mk_call/7, %% mk_call(Dst, Mod, Fun, Args, Type, %% Continuation, Fail) mk_call/8, %% mk_call(Dst, Mod, Fun, Args, Type, %% Continuation, Fail, Guard) call_dstlist/1, call_dstlist_update/2, call_dst_type/1, call_args/1, call_args_update/2, call_fun/1, call_fun_update/2, call_type/1, call_continuation/1, call_fail_label/1, call_set_fail_label/2, call_set_continuation/2, is_call/1, call_in_guard/1, mk_goto/1, %% mk_goto(Lbl) goto_label/1, mk_enter/4, %% mk_enter(Mod, Fun, Args, Type) mk_enter_primop/2, %% mk_enter_primop(Op, Type) enter_fun/1, enter_fun_update/2, enter_args/1, enter_args_update/2, enter_type/1, is_enter/1, mk_fmove/2, %% mk_fmove(Dst, Src) mk_return/1, %% mk_return(Vars) %% mk_fail/1, %% mk_fail(Args) class = exit mk_fail/2, %% mk_fail(Args, Class) %% mk_fail/3, %% mk_fail(Args, Class, Label) mk_move/2, %% mk_move(Dst, Src) mk_moves/2, %% mk_moves(DstList, SrcList) mk_begin_try/2, %% mk_begin_try(Label, Successor) mk_begin_handler/1, %% mk_begin_handler(ReasonDst) mk_end_try/0, %% mk_end_try() %% mk_elements/2, %% mk_elements(Tuple, Vars) mk_label/1, %% mk_label(Name) mk_new_label/0, %% mk_new_label() mk_comment/1, %% mk_comment(Text) mk_const/1, %% mk_const(Const) %% mk_const_fun/4, %% mk_const_fun(MFA, U, I, Args) mk_var/1, %% mk_var(Id) annotate_var/2, %% annotate_var(Var, Type) unannotate_var/1, %% unannotate_var(Var) mk_reg/1, %% mk_reg(Id) mk_fvar/1, %% mk_fvar(Id) mk_new_var/0, %% mk_new_var() mk_new_fvar/0, %% mk_new_fvar()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -