%%=====================================================================
%%
%% Contains type and record definitions for all Icode data structures.
%%
%%=====================================================================

%%---------------------------------------------------------------------
%% THESE DO NOT REALLY BELONG HERE -- PLEASE REMOVE ASAP!
%%---------------------------------------------------------------------

-type set()	 :: tuple().
-type ordset(T)	 :: [T].
-type gb_set()	 :: tuple().
-type gb_tree()	 :: tuple().
-type erl_type() :: any().    %% XXX: belongs to 'erl_types'
%%-type erl_type() :: 'any' | 'none' | 'unit' | {'c',_,_,_}.

%%---------------------------------------------------------------------
%% 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' | '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' 
                      | 'suspend_msg_timeout'.

-type icode_type_test()	:: 'atom' | 'bignum' | 'binary' | 'bitrst' | 'boolean'
                         | 'cons' | 'constant' | 'fixnum' | 'float'
                         | 'function' | 'function2' | 'integer' | 'list' | 'nil'
                         | 'number' | 'pid' | 'port' | 'reference' | 'tuple'
                         | {'atom', atom()} | {'integer', integer()}
                         | {'record', atom(), byte()} | {'tuple', byte()}.
 
-type icode_primop()	:: atom() | tuple(). % XXX: temporarily, I hope

-type icode_var()	:: #icode_variable{kind::'var'}.
-type icode_reg()	:: #icode_variable{kind::'reg'}.
-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'.

%%---------------------------------------------------------------------
%% 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_primop() | mfa(),
		     args               :: [icode_argument()],
		     type               :: icode_call_type(),
		     continuation       :: [] | icode_lbl(),
		     fail_label = []    :: [] | icode_lbl(),
		     in_guard   = false :: bool()}).

-record(icode_enter, {'fun' :: icode_primop() | mfa(), 
		      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 :: atom() | string() | {atom(), any()}}).

%%---------------------------------------------------------------------
%% 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		:: [icode_var()],
		is_closure	:: bool(),
		closure_arity	:: byte(),
		is_leaf 	:: bool(),
		code = []	:: icode_instrs(),
		data		:: hipe_consttab(),
		var_range	:: {non_neg_integer(), non_neg_integer()},
		label_range	:: {icode_lbl(), icode_lbl()},
		info = []       :: [{arg_types, [erl_type()]}]}).

%%---------------------------------------------------------------------
