%% 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.
%%
%%=====================================================================
%%
%% Contains type and record definitions for all Icode data structures.
%%
%%=====================================================================
%%---------------------------------------------------------------------
%% Include files needed for the compilation of this header file
%%---------------------------------------------------------------------
-include("../misc/hipe_consttab.hrl").
%%---------------------------------------------------------------------
%% Icode argument types
%%---------------------------------------------------------------------
-type simple_const() :: atom() | [] | integer() | float().
-type structured_const() :: list() | tuple().
-type icode_lbl() :: non_neg_integer().
%%---------------------------------------------------------------------
%% Icode records
%%---------------------------------------------------------------------
-record(flat, {value :: simple_const() | structured_const() | binary()}).
-record(icode_const, {value :: #flat{}}).
-type variable_annotation() :: {atom(), any(), fun((any()) -> string())}.
-record(icode_variable, {name :: non_neg_integer(),
kind :: 'var' | 'reg' | 'reg_gcsafe' | 'fvar',
annotation = [] :: [] | variable_annotation()}).
%%---------------------------------------------------------------------
%% Type declarations for Icode instructions
%%---------------------------------------------------------------------
-type icode_if_op() :: '>' | '<' | '>=' | '=<' | '=:=' | '=/=' | '==' | '/='
| 'fixnum_eq' | 'fixnum_neq' | 'fixnum_lt'
| 'fixnum_le' | 'fixnum_ge' | 'fixnum_gt'
| 'op_exact_eqeq_2' | 'suspend_msg_timeout'.
-type icode_type_test() :: 'atom' | 'bignum' | 'binary' | 'bitstr' | 'boolean'
| 'cons' | 'fixnum' | 'float' | 'function'
| 'function2' | 'integer' | 'list' | 'map' | 'nil'
| 'number' | 'pid' | 'port' | 'reference' | 'tuple'
| {'atom', atom()} | {'integer', integer()}
| {'record', atom(), non_neg_integer()}
| {'tuple', non_neg_integer()}.
-type icode_primop() :: atom() | tuple(). % XXX: temporarily, I hope
-type icode_funcall() :: mfa() | icode_primop().
-type icode_var() :: #icode_variable{kind::'var'}.
-type icode_reg() :: #icode_variable{kind::'reg'|'reg_gcsafe'}.
-type icode_fvar() :: #icode_variable{kind::'fvar'}.
-type icode_argument() :: #icode_const{} | #icode_variable{}.
-type icode_term_arg() :: icode_var() | #icode_const{}.
-type icode_switch_case() :: {#icode_const{}, icode_lbl()}.
-type icode_call_type() :: 'local' | 'primop' | 'remote'.
-type icode_exit_class() :: 'error' | 'exit' | 'rethrow' | 'throw'.
-type icode_comment_text() :: atom() | string().
-type icode_info() :: [{'arg_types', [erl_types:erl_type()]}].
%%---------------------------------------------------------------------
%% Icode instructions
%%---------------------------------------------------------------------
-record(icode_label, {name :: icode_lbl()}).
-record(icode_if, {op :: icode_if_op(),
args :: [icode_term_arg()],
true_label :: icode_lbl(),
false_label :: icode_lbl(),
p :: float()}).
-record(icode_switch_val, {term :: icode_var(),
fail_label :: icode_lbl(),
length :: non_neg_integer(),
cases :: [icode_switch_case()]}).
-record(icode_switch_tuple_arity, {term :: icode_var(),
fail_label :: icode_lbl(),
length :: non_neg_integer(),
cases :: [icode_switch_case()]}).
-record(icode_type, {test :: icode_type_test(),
args :: [icode_term_arg()],
true_label :: icode_lbl(),
false_label :: icode_lbl(),
p :: float()}).
-record(icode_goto, {label :: icode_lbl()}).
-record(icode_move, {dst :: #icode_variable{},
src :: #icode_variable{} | #icode_const{}}).
-record(icode_phi, {dst :: #icode_variable{},
id :: #icode_variable{},
arglist :: [{icode_lbl(), #icode_variable{}}]}).
-record(icode_call, {dstlist :: [#icode_variable{}],
'fun' :: icode_funcall(),
args :: [icode_argument()],
type :: icode_call_type(),
continuation :: [] | icode_lbl(),
fail_label = [] :: [] | icode_lbl(),
in_guard = false :: boolean()}).
-record(icode_enter, {'fun' :: icode_funcall(),
args :: [icode_term_arg()],
type :: icode_call_type()}).
-record(icode_return, {vars :: [icode_var()]}).
-record(icode_begin_try, {label :: icode_lbl(), successor :: icode_lbl()}).
-record(icode_end_try, {}).
-record(icode_begin_handler, {dstlist :: [icode_var()]}).
%% TODO: Remove [] from fail_label
-record(icode_fail, {class :: icode_exit_class(),
args :: [icode_term_arg()],
fail_label = [] :: [] | icode_lbl()}).
-record(icode_comment, {text :: icode_comment_text()}).
%%---------------------------------------------------------------------
%% Icode instructions
%%---------------------------------------------------------------------
-type icode_instr() :: #icode_begin_handler{} | #icode_begin_try{}
| #icode_call{} | #icode_comment{} | #icode_end_try{}
| #icode_enter{} | #icode_fail{}
| #icode_goto{} | #icode_if{} | #icode_label{}
| #icode_move{} | #icode_phi{} | #icode_return{}
| #icode_switch_tuple_arity{} | #icode_switch_val{}
| #icode_type{}.
-type icode_instrs() :: [icode_instr()].
%%---------------------------------------------------------------------
%% The Icode data structure
%%---------------------------------------------------------------------
-record(icode, {'fun' :: mfa(),
params :: hipe_icode:params(),
%% TODO: merge is_closure and closure_arity into one field
is_closure :: boolean(),
closure_arity = none :: 'none' | arity(),
is_leaf :: boolean(),
code = [] :: icode_instrs(),
data :: hipe_consttab(),
var_range :: {non_neg_integer(), non_neg_integer()},
label_range :: {icode_lbl(), icode_lbl()},
info = [] :: icode_info()}).
-type icode() :: #icode{}.
%%---------------------------------------------------------------------