%-----------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et
%-----------------------------------------------------------------------------%
% Copyright (C) 2001-2009, 2011 The University of Melbourne.
% Copyright (C) 2014-2015, 2019, 2022 The Mercury team.
% This file may only be copied under the terms of the GNU General
% Public License - see the file COPYING in the Mercury distribution.
%-----------------------------------------------------------------------------%
%
% File: layout.m.
% Author: zs.
%
% Definitions of Mercury types for representing layout structures within
% the compiler. Layout structures are generated by the compiler, and are
% used by the parts of the runtime system that need to look at the stacks
% (and sometimes the registers) and make sense of their contents. The parts
% of the runtime system that need to do this include exception handling,
% the debugger, the deep profiler and (eventually) the accurate garbage
% collector.
%
% When output by layout_out.m, values of most these types will correspond
% to the C types defined in runtime/mercury_stack_layout.h or
% runtime/mercury_deep_profiling.h; the documentation of those types
% can be found there. The names of the C types are listed next to the
% function symbol whose arguments represent their contents.
%
% The code to generate values of these types is in stack_layout.m and
% deep_profiling.m.
%
% This module should be, but as yet isn't, independent of whether we are
% compiling to LLDS or MLDS.
%
%-----------------------------------------------------------------------------%

:- module ll_backend.layout.
:- interface.

:- import_module hlds.
:- import_module hlds.hlds_rtti.
:- import_module hlds.pred_name.
:- import_module libs.
:- import_module libs.trace_params.
:- import_module ll_backend.llds.
:- import_module mdbcomp.
:- import_module mdbcomp.prim_data.
:- import_module mdbcomp.sym_name.
:- import_module parse_tree.
:- import_module parse_tree.prog_data.
:- import_module parse_tree.prog_data_event.
:- import_module parse_tree.prog_data_pragma.

:- import_module assoc_list.
:- import_module bool.
:- import_module list.
:- import_module map.
:- import_module maybe.

%-----------------------------------------------------------------------------%
%
% Closure layouts.
%

:- type closure_proc_id_data
    --->    closure_proc_id_data(
                % defines MR_ClosureId
                caller_proc_label       :: proc_label,
                caller_closure_seq_no   :: int,
                closure_proc_label      :: proc_label,
                closure_module_name     :: module_name,
                closure_file_name       :: string,
                closure_line_number     :: int,
                closure_origin          :: pred_origin,
                closure_goal_path       :: string
            ).

%-----------------------------------------------------------------------------%
%
% Proc layouts and their components.
%

:- type user_event_data
    --->    user_event_data(
                user_event_number       :: int,
                user_event_locns        :: rval,
                user_event_var_nums     :: layout_slot_name
            ).

:- type basic_label_layout
    --->    basic_label_layout(
                proc_label              :: proc_label,
                label_num               :: int,
                proc_layout_name        :: layout_name,
                maybe_port              :: maybe(trace_port),
                maybe_is_hidden         :: maybe(bool),
                label_num_in_module     :: int,
                maybe_goal_path         :: maybe(int), % offset
                maybe_user_info         :: maybe(layout_slot_name)
            ).

:- type label_short_var_info
    --->    label_short_var_info(
                % part of MR_LabelLayout
                lsvi_encoded_var_count  :: int, % encodes #Long=0 and #Short
                lsvi_type_params        :: rval,
                lsvi_ptis               :: int, % -1 if none, otherwise slot#
                lsvi_hlds_var_nums      :: int, % -1 if none, otherwise slot#
                lsvi_short_locns        :: int  % -1 if none, otherwise slot#
            ).

:- type label_long_var_info
    --->    label_long_var_info(
                % part of MR_LabelLayout
                llvi_encoded_var_count  :: int, % encodes #Long>0 and #Short
                llvi_type_params        :: rval,
                llvi_ptis               :: int, % -1 if none, otherwise slot#
                llvi_hlds_var_nums      :: int, % -1 if none, otherwise slot#
                llvi_short_locns        :: int, % -1 if none, otherwise slot#
                llvi_long_locns         :: int  % -1 if none, otherwise slot#
            ).

:- type label_layout_no_vars
    --->    label_layout_no_vars(
                % defines MR_LabelLayoutNoVarInfo
                basic_label_layout
            ).

:- type label_layout_short_vars
    --->    label_layout_short_vars(
                % defines MR_LabelLayout
                basic_label_layout,
                label_short_var_info
            ).

:- type label_layout_long_vars
    --->    label_layout_long_vars(
                % defines MR_LabelLayout
                basic_label_layout,
                label_long_var_info
            ).

%-----------------------------------------------------------------------------%
%
% Proc layouts and their components.
%

:- type proc_layout_stack_traversal
    --->    proc_layout_stack_traversal(
                % defines MR_StackTraversal
                % The proc entry label will be `no' if we don't have
                % static code addresses.
                plst_entry_label        :: maybe(label),

                plst_succip_slot        :: maybe(int),
                plst_stack_slot_count   :: int,
                plst_detism             :: determinism
            ).

    % The deep_slot_info gives the stack slot numbers that hold
    % the values returned by the call port code, which are needed to let
    % exception.throw perform the work we need to do at the excp port.
    % The old_outermost slot is needed only with the save/restore approach;
    % the old_outermost field contain -1 otherwise. All fields will contain
    % -1 if the variables are never saved on the stack because the
    % predicate makes no calls (in which case it cannot throw exceptions,
    % because to do that it would need to call exception.throw, directly or
    % indirectly.)
:- type deep_excp_slots
    --->    deep_excp_slots(
                top_csd                 :: int,
                middle_csd              :: int,
                old_outermost           :: int
            ).

:- type proc_layout_proc_static
    --->    proc_layout_proc_static(
                plps_file_name          :: string,
                plps_line_number        :: int,
                plps_is_in_interface    :: bool,
                plps_excp_slots         :: deep_excp_slots,
                plps_call_site_statics  :: maybe({int, int}),
                plps_coverage_points    :: maybe({int, int})
            ).

:- type table_io_args_data
    --->    table_io_args_data(
                % The number of head variables that are stored in the answer
                % block. Besides the values of the output arguments,
                % which are needed to make the I/O action idempotent,
                % it also includes the values of the input arguments.
                % Some of these, the type_infos, mdb needs in order to
                % convert the type-specific representations of the outputs
                % to a term that the debugger's user can print or browse.
                % The other inputs are needed to allow the debugger's user
                % to judge whether the output are correct or not.
                tia_answerblock_arity   :: int,

                % This rval stores a vector of answerblock_arity pseudo-
                % typeinfos, one for each headvar stored in the answer block.
                tia_ptis                :: rval,

                % This rval represents a vector mapping each type variable
                % that occurs in the above pseudo-typeinfos to the location
                % of the type_info that is currently bound to that type
                % variable.
                tia_type_params         :: rval
            ).

:- type table_io_entry_data
    --->    table_io_entry_data(
                % defines MR_TableIoEntry
                tie_proc_ptr            :: layout_name,
                tie_maybe_args          :: maybe(table_io_args_data)
            ).

:- type data_or_slot_id
    --->    data_or_slot_is_data(data_id)
    ;       data_or_slot_is_slot(layout_slot_name).

:- type proc_layout_exec_trace
    --->    proc_layout_exec_trace(
                % defines MR_ExecTrace
                plet_maybe_call_label_slot  :: maybe(layout_slot_name),

                % The label layouts of the events in the predicate.
                plet_proc_event_layouts     :: layout_slot_name,
                plet_num_proc_event_layouts :: int,

                plet_maybe_table_info       :: maybe(data_or_slot_id),

                % The variable numbers of the head variables, including the
                % ones added by the compiler, in order. The length of the list
                % must be the same as the procedure's arity. The maybe will be
                % `no' if the procedure has no head variables.
                plet_head_var_nums          :: maybe(layout_slot_name),
                plet_num_head_var_nums      :: int,

                % Each variable name is an offset into the module's
                % string table. The maybe will be `no' if the procedure
                % has no variables.
                plet_var_names              :: maybe(layout_slot_name),

                plet_max_var_num            :: int,
                plet_max_reg_r_num          :: int,
                plet_max_reg_f_num          :: int,
                plet_maybe_from_full_slot   :: maybe(int),
                plet_maybe_io_seq_slot      :: maybe(int),
                plet_maybe_trail_slot       :: maybe(int),
                plet_maybe_maxfr_slot       :: maybe(int),
                plet_eval_method            :: eval_method,
                plet_maybe_call_table_slot  :: maybe(int),
                plet_maybe_tail_rec_slot    :: maybe(int),
                plet_eff_trace_level        :: eff_trace_level,
                plet_exec_trace_flags       :: int
            ).

:- type maybe_proc_id_and_more
    --->    no_proc_id_and_more
    ;       proc_id_and_more(
                maybe_proc_static       :: maybe(layout_slot_name),
                maybe_exec_trace        :: maybe(layout_slot_name),

                % The procedure body represented as a list of bytecodes.
                proc_body_bytes         :: maybe(layout_slot_name),

                % The name of the module_layout structure.
                proc_module_layout      :: layout_name
            ).

:- type proc_layout_data
    --->    proc_layout_data(
                % defines MR_ProcLayout
                proc_layout_label       :: rtti_proc_label,
                proc_layout_trav        :: proc_layout_stack_traversal,
                proc_layout_more        :: maybe_proc_id_and_more
            ).

%-----------------------------------------------------------------------------%
%
% Module layouts and their components.
%

    % This type is for strings which may contain embedded null characters.
    % When a string_with_0s is written, a null character will be written
    % in between each string in the list.
    %
:- type string_with_0s
    --->    string_with_0s(list(string)).

:- type event_set_layout_data
    --->    event_set_layout_data(
                event_set_data,

                % Maps each event number to an rval that gives the vector
                % of typeinfos for the arguments of that event.
                map(int, rval)
            ).

:- type file_layout_data
    --->    file_layout_data(
                file_name               :: string,
                line_no_label_list      :: assoc_list(int, layout_slot_name)
            ).

:- type module_layout_data
    --->    module_layout_data(
                % The part of MR_ModuleLayout that is needed for both
                % deep profiling and debugging.
                mld_module_name             :: module_name,
                mld_string_table_size       :: int,
                mld_string_table            :: string_with_0s,

                % The parts that are specific to deep profiling and to
                % debugging.
                mld_maybe_deep_prof         :: maybe(module_layout_deep_prof),
                mld_maybe_debug             :: maybe(module_layout_debug)
            ).

:- type module_layout_deep_prof
    --->    module_layout_deep_prof(
                % Defines part of MR_ModuleLayout.
                mldp_num_oisu_types         :: int,
                mldp_oisu_bytes             :: list(int),
                mldp_num_table_types        :: int,
                mldp_type_table_bytes       :: list(int)
            ).

:- type module_layout_debug
    --->    module_layout_debug(
                % Defines part of MR_ModuleLayout.
                mld_proc_layout_names       :: list(layout_name),
                mld_file_layouts            :: list(file_layout_data),
                mld_trace_level             :: trace_level,
                mld_suppressed_events       :: int,
                mld_num_label_exec_count    :: int,
                mld_maybe_event_specs       :: maybe(event_set_layout_data)
            ).

%-----------------------------------------------------------------------------%
%
% Allocation site information.
%

:- type alloc_site_info
    --->    alloc_site_info(
                % define MR_AllocSiteInfo
                as_proc_label       :: proc_label,
                as_context          :: prog_context,
                as_type             :: string,
                as_size             :: int
            ).

%-----------------------------------------------------------------------------%
%
% Global variables that hold arrays of layout structures.
%

:- type label_vars
    --->    label_has_no_var_info
    ;       label_has_short_var_info
    ;       label_has_long_var_info.

:- type layout_slot_name
    --->    layout_slot(layout_array_name, int).

:- type layout_array_name
    --->    pseudo_type_info_array
    ;       hlds_var_nums_array
    ;       short_locns_array
    ;       long_locns_array
    ;       user_event_layout_array
    ;       user_event_var_nums_array
    ;       label_layout_array(label_vars)

    ;       proc_static_call_sites_array
    ;       proc_static_cp_static_array
    ;       proc_static_cp_dynamic_array
    ;       proc_static_array
    ;       proc_head_var_nums_array
            % A vector of variable numbers, containing the numbers of the
            % procedure's head variables, including the ones generated by
            % the compiler.
    ;       proc_var_names_array
            % A vector of variable names (represented as offsets into
            % the string table) for a procedure layout structure.
    ;       proc_body_bytecodes_array
    ;       proc_table_io_entry_array
    ;       proc_event_layouts_array
    ;       proc_exec_trace_array
    ;       threadscope_string_table_array
    ;       alloc_site_array.

%-----------------------------------------------------------------------------%
%
% Global variables that hold individual layout structures.
%

:- type proc_layout_kind
    --->    proc_layout_traversal
    ;       proc_layout_proc_id(proc_layout_user_or_uci).

:- type proc_layout_user_or_uci
    --->    user
    ;       uci.

    % Each layout_name identifies a global variable holding one layout
    % structure. We prefer to put layout structures into arrays, because
    % one array holding all N layout structures of a given kind require
    % less space in the symbol table and relocation information sections
    % of object files than N separate global variables, and the reduction
    % in the number of symbols should also improve link times. In some arrays,
    % it is also possible to use an element or sequence of elements two or more
    % times, giving an element of compression.
    %
    % The layout structures we still put into global variables individually are
    %
    % - procedure layouts, which have to have a name derivable from the name of
    %   the procedure they represent, since in deep profiling grades call site
    %   static structures contain pointers to the proc layout structures of the
    %   callee procedures;
    % - layouts for closures, which are relatively few in number,
    %   so arrays would do little good; and
    % - module layouts and their components, of which each module will have
    %   just one, so arrays would do absolutely *no* good.
    %
:- type layout_name
    --->    proc_layout(rtti_proc_label, proc_layout_kind)
    ;       closure_proc_id(proc_label, int, proc_label)
    ;       file_layout(module_name, int)
    ;       file_layout_line_number_vector(module_name, int)
    ;       file_layout_label_layout_vector(module_name, int)
    ;       module_layout_string_table(module_name)
    ;       module_layout_file_vector(module_name)
    ;       module_layout_proc_vector(module_name)
    ;       module_layout_label_exec_count(module_name, int)
    ;       module_layout_event_set_desc(module_name)
    ;       module_layout_event_arg_names(module_name, int)
    ;       module_layout_event_synth_attrs(module_name, int)
    ;       module_layout_event_synth_attr_args(module_name, int, int)
    ;       module_layout_event_synth_attr_order(module_name, int, int)
    ;       module_layout_event_synth_order(module_name, int)
    ;       module_layout_event_specs(module_name)
    ;       module_layout_oisu_bytes(module_name)
    ;       module_layout_type_table_bytes(module_name)
    ;       module_layout(module_name).

%-----------------------------------------------------------------------------%
:- end_module ll_backend.layout.
%-----------------------------------------------------------------------------%
