// vim: ts=4 sw=4 expandtab ft=c

// Copyright (C) 1998-2012 The University of Melbourne.
// Copyright (C) 2014, 2016, 2018 The Mercury team.
// This file is distributed under the terms specified in COPYING.LIB.

#ifndef MERCURY_STACK_LAYOUT_H
#define MERCURY_STACK_LAYOUT_H

// mercury_stack_layout.h -
//
// Definitions for stack layout data structures. These 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, and (eventually) the accurate garbage
// collector.
//
// For a general description of the idea of stack layouts, see the paper
// "Run time type information in Mercury" by Tyson Dowd, Zoltan Somogyi,
// Fergus Henderson, Thomas Conway and David Jeffery, which is available from
// the Mercury web site. The relevant section is section 3.8, but be warned:
// while the general principles remain applicable, the details have changed
// since that paper was written.
//
// NOTE: The constants and data-structures used here need to be kept in
// sync with the ones generated in the compiler. If you change anything here,
// you may need to change stack_layout.m, layout.m, and/or layout_out.m in
// the compiler directory as well.

#include "mercury_types.h"
#include "mercury_std.h"                // for MR_VARIABLE_SIZED
#include "mercury_tags.h"
#include "mercury_type_info.h"          // for MR_PseudoTypeInfo
#include "mercury_proc_id.h"            // for MR_ProcId
#include "mercury_goto.h"               // for MR_PROC_LAYOUT etc
#include "mercury_tabling.h"            // for MR_TableTrieStep etc

////////////////////////////////////////////////////////////////////////////
// Definitions for MR_Determinism.

// The max_soln component of the determinism is encoded in the 1 and 2 bits.
// The can_fail component of the determinism is encoded in the 4 bit.
// The first_solution component of the determinism is encoded in the 8 bit.
//
// MR_DETISM_AT_MOST_MANY could also be defined as ((d) & 3) == 3),
// but this would be less efficient, since the C compiler does not know
// that we do not set the 1 bit unless we also set the 2 bit.
//
// NOTE: this must match the encoding specified by represent_determinism/1
// in mdbcomp/program_representation.m.

typedef MR_int_least16_t    MR_Determinism;

#define MR_DETISM_DET       6
#define MR_DETISM_SEMI      2
#define MR_DETISM_NON       3
#define MR_DETISM_MULTI     7
#define MR_DETISM_ERRONEOUS 4
#define MR_DETISM_FAILURE   0
#define MR_DETISM_CCNON     10
#define MR_DETISM_CCMULTI   14

#define MR_DETISM_MAX       14

#define MR_DETISM_AT_MOST_ZERO(d)   (((d) & 3) == 0)
#define MR_DETISM_AT_MOST_ONE(d)    (((d) & 3) == 2)
#define MR_DETISM_AT_MOST_MANY(d)   (((d) & 1) != 0)

#define MR_DETISM_CAN_FAIL(d)       (((d) & 4) == 0)

#define MR_DETISM_FIRST_SOLN(d)     (((d) & 8) != 0)

#define MR_DETISM_DET_STACK(d)      (!MR_DETISM_AT_MOST_MANY(d)         \
                                    || MR_DETISM_FIRST_SOLN(d))

////////////////////////////////////////////////////////////////////////////
// Definitions for MR_LongLval and MR_ShortLval.

// MR_LongLval is an MR_Unsigned which describes a location.
// This includes lvals such as stack slots, general registers, and special
// registers such as succip, hp, etc, as well as locations whose address is
// given as a typeinfo inside the type class info structure pointed to by an
// lval.
//
// What kind of location an MR_LongLval refers to is encoded using
// a low tag with MR_LONG_LVAL_TAGBITS bits; the type MR_LongLvalType
// describes the different tag values. The interpretation of the rest of
// the word depends on the location type:
//
// Locn                 Rest
//
// MR_r(Num)            Num (register number)
// MR_f(Num)            Num (register number)
// MR_stackvar(Num)     Num (stack slot number)
// MR_framevar(Num)     Num (stack slot number)
// MR_succip
// MR_maxfr
// MR_curfr
// MR_hp
// MR_sp
// constant             See below
// indirect(Base, N)    See below
// unknown              (The location is not known)
//
// For constants, the rest of the word is a pointer to static data. The
// pointer has only two low tag bits free, so we reserve every four-bit tag
// which has 00 as its bottom two bits for representing them.
//
// For indirect references, the word exclusive of the tag consists of
// (a) an integer with MR_LONG_LVAL_OFFSETBITS bits giving the index of
// the typeinfo inside a type class info (to be interpreted by
// MR_typeclass_info_type_info or the predicate
// private_builtin.type_info_from_typeclass_info, which calls it) and
// (b) a MR_LongLval value giving the location of the pointer to the
// type class info. This MR_LongLval value will *not* have an indirect tag.
//
// This data is generated in stack_layout.represent_locn_as_int,
// which must be kept in sync with the constants and macros defined here.

typedef MR_Unsigned MR_LongLval;

typedef enum {
    MR_LONG_LVAL_TYPE_CONS_0          = 0,
    MR_LONG_LVAL_TYPE_R               = 1,
    MR_LONG_LVAL_TYPE_F               = 2,
    MR_LONG_LVAL_TYPE_STACKVAR        = 3,
    MR_LONG_LVAL_TYPE_CONS_1          = 4,
    MR_LONG_LVAL_TYPE_FRAMEVAR        = 5,
    MR_LONG_LVAL_TYPE_SUCCIP          = 6,
    MR_LONG_LVAL_TYPE_MAXFR           = 7,
    MR_LONG_LVAL_TYPE_CONS_2          = 8,
    MR_LONG_LVAL_TYPE_CURFR           = 9,
    MR_LONG_LVAL_TYPE_HP              = 10,
    MR_LONG_LVAL_TYPE_SP              = 11,
    MR_LONG_LVAL_TYPE_CONS_3          = 12,
    MR_LONG_LVAL_TYPE_DOUBLE_STACKVAR = 13,
    MR_LONG_LVAL_TYPE_DOUBLE_FRAMEVAR = 14,
    MR_LONG_LVAL_TYPE_INDIRECT        = 15,
    MR_LONG_LVAL_TYPE_CONS_4          = 16,
    MR_LONG_LVAL_TYPE_UNKNOWN         = 17,
    MR_LONG_LVAL_TYPE_CONS_5          = 20,
    MR_LONG_LVAL_TYPE_CONS_6          = 24,
    MR_LONG_LVAL_TYPE_CONS_7          = 28
} MR_LongLvalType;

// This must be in sync with stack_layout.long_lval_tag_bits.
#define MR_LONG_LVAL_TAGBITS        5

#define MR_LONG_LVAL_CONST_TAGBITS  2

#define MR_LONG_LVAL_TYPE(Locn)                                             \
    ((MR_LongLvalType) ((Locn) & ((1 << MR_LONG_LVAL_TAGBITS) - 1)))

#define MR_LONG_LVAL_NUMBER(Locn)                                           \
    ((int) ((Locn) >> MR_LONG_LVAL_TAGBITS))

#define MR_LONG_LVAL_CONST(Locn)                                            \
    (* (MR_Word *) ((Locn) & ~ ((1 << MR_LONG_LVAL_CONST_TAGBITS) - 1)))

// This must be in sync with stack_layout.offset_bits.
#define MR_LONG_LVAL_OFFSETBITS 6

#define MR_LONG_LVAL_INDIRECT_OFFSET(LocnNumber)                            \
    ((int) ((LocnNumber) & ((1 << MR_LONG_LVAL_OFFSETBITS) - 1)))

#define MR_LONG_LVAL_INDIRECT_BASE_LVAL_INT(LocnNumber)                     \
    (((MR_uint_least32_t) (LocnNumber)) >> MR_LONG_LVAL_OFFSETBITS)

#define MR_LONG_LVAL_STACKVAR_INT(n)                                        \
    (((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_STACKVAR)

#define MR_LONG_LVAL_FRAMEVAR_INT(n)                                        \
    (((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_FRAMEVAR)

#define MR_LONG_LVAL_R_REG_INT(n)                                           \
    (((n) << MR_LONG_LVAL_TAGBITS) + MR_LONG_LVAL_TYPE_R)

// MR_ShortLval is a MR_uint_least8_t which describes an location. This
// includes lvals such as stack slots and general registers that have small
// numbers, and special registers such as succip, hp, etc.
//
// What kind of location an MR_LongLval refers to is encoded using
// a low tag with 2 bits; the type MR_ShortLval_Type describes
// the different tag values. The interpretation of the rest of the word
// depends on the location type:
//
// Locn             Tag Rest
// MR_r(Num)         0  Num (register number)
// MR_stackvar(Num)  1  Num (stack slot number)
// MR_framevar(Num)  2  Num (stack slot number)
// special reg       3  MR_LongLvalType
//
// This data is generated in stack_layout.represent_locn_as_byte,
// which must be kept in sync with the constants and macros defined here.

typedef MR_uint_least8_t    MR_ShortLval;

typedef enum {
    MR_SHORT_LVAL_TYPE_R,
    MR_SHORT_LVAL_TYPE_STACKVAR,
    MR_SHORT_LVAL_TYPE_FRAMEVAR,
    MR_SHORT_LVAL_TYPE_SPECIAL
} MR_ShortLval_Type;

// This must be in sync with stack_layout.short_lval_tag_bits.
#define MR_SHORT_LVAL_TAGBITS   2

#define MR_SHORT_LVAL_TYPE(Locn)                                            \
    ((MR_ShortLval_Type)                                                    \
        (((MR_Word) Locn) & ((1 << MR_SHORT_LVAL_TAGBITS) - 1)))

#define MR_SHORT_LVAL_NUMBER(Locn)                                          \
    ((int) (((MR_Word) Locn) >> MR_SHORT_LVAL_TAGBITS))

#define MR_SHORT_LVAL_STACKVAR(n)                                           \
    ((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS)                         \
        + MR_SHORT_LVAL_TYPE_STACKVAR))

#define MR_SHORT_LVAL_FRAMEVAR(n)                                           \
    ((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS)                         \
        + MR_SHORT_LVAL_TYPE_FRAMEVAR))

#define MR_SHORT_LVAL_R_REG(n)                                              \
    ((MR_ShortLval) (((n) << MR_SHORT_LVAL_TAGBITS)                         \
        + MR_SHORT_LVAL_TYPE_R))

////////////////////////////////////////////////////////////////////////////
// Definitions for MR_UserEvent and MR_UserEventSpec.

// Our layout structures link to information about user events from two places:
// the label layout structures of labels that correspond to user events,
// and the module layout structures of modules that contain user events.
// Label layout structures link to MR_UserEvent structures; module layout
// structures link to MR_UserEventSpec structures. Most of the information
// is in the MR_UserEventSpec structures; MR_UserEvent structures contain
// only information that may differ between two instances of the same event.

// The fields of MR_UserEvent:
//
// The event_number field contains the ordinal number of the event in the
// event set the module was compiled with: it gives the identity of the event.
// (Event numbers start at zero.) This field is also the link to the rest of
// the information about the event, contained in the MR_UserEventSpec structure
// linked to by the module layout structure. The MR_user_event_spec macro
// follows this link.
//
// The next two fields all point to arrays whose length is the number of
// attributes (which is available in the MR_UserEventSpec structure).
//
// attr_locns[i] gives the location where we can find the value of the
// i'th attribute (the first attribute is attribute zero). This is
// meaningful only if the attribute is not a synthesized attribute.
//
// attr_var_nums[i] gives the variable number of the i'th attribute;
// if it contains zero, that means the attribute is synthesized. This field
// is used by the debugger to display the associated value just once
// (not twice, as both attribute and variable value) with "print *". (Note
// that we don't delete the variables that are also attributes from the set of
// live variables in layout structures, because that would require any native
// garbage collector to look at the list of attributes as well as the list of
// other variables, slowing it down.)

typedef MR_uint_least16_t       MR_HLDSVarNum;

struct MR_UserEvent_Struct {
    MR_uint_least16_t           MR_ue_event_number;
    MR_LongLval                 *MR_ue_attr_locns;
    const MR_HLDSVarNum         *MR_ue_attr_var_nums;
};

// The fields of MR_UserEventSpec:
//
// The event_name field contains the name of the event.
//
// The num_attrs field gives the number of attributes.
//
// The next three fields (attr_names, attr_types and synth_attrs) all point
// to arrays whose length is the number of attributes.
//
// attr_names[i] gives the name of the i'th attribute.
//
// attr_types[i] is the typeinfo giving the type of the i'th attribute.
//
// If the i'th attribute is synthesized, synth_attrs[i] points to the
// information required to synthesize it: the number of the attribute
// containing the synthesis function, the number of arguments of the synthesis
// function, and an array of attribute numbers (of length num_arg_attrs)
// giving the list of those arguments. The depend_attrs field will point to
// a list of numbers of the synthesized attributes whose values must be
// materialized before this attribute can be evaluated. (This list will include
// the argument attributes, and will be in a feasible evaluation order.)
// If the i'th attribute is not synthesized, synth_attrs[i] and depend_attrs[i]
// will both be NULL. (For now, depend_attrs[i] will not be filled in for
// synthesized attributes either.)
//
// The synth_attr_order field points to an array of attribute numbers that
// gives the order in which the values of the synthesized attributes should be
// evaluated. The array is ended by -1 as a sentinel.
//
// The synth_attrs and synth_attr_order fields will both be NULL for events
// that have no synthesized attributes.

struct MR_SynthAttr_Struct {
    MR_int_least16_t        MR_sa_func_attr;
    MR_int_least16_t        MR_sa_num_arg_attrs;
    MR_uint_least16_t       *MR_sa_arg_attrs;
    MR_int_least16_t        *MR_sa_depend_attrs;
};

struct MR_UserEventSpec_Struct {
    const char              *MR_ues_event_name;
    MR_uint_least16_t       MR_ues_num_attrs;
    const char              **MR_ues_attr_names;
    MR_TypeInfo             *MR_ues_attr_types;
    MR_SynthAttr            *MR_ues_synth_attrs;
    MR_int_least16_t        *MR_ues_synth_attr_order;
};

#define MR_user_event_spec(label_layout)                                    \
    label_layout->MR_sll_entry->MR_sle_module_layout->                      \
    MR_ml_user_event_specs[label_layout->MR_sll_user_event->                \
        MR_ue_event_number]

#define MR_user_event_set_name(label_layout)                                \
    label_layout->MR_sll_entry->MR_sle_module_layout->                      \
    MR_ml_user_event_set_name

////////////////////////////////////////////////////////////////////////////
// Definitions for MR_LabelLayout.

// An MR_LabelLayout structure describes the debugging and accurate gc
// information available at a given label.
//
// The MR_sll_entry field points to the proc layout structure of the procedure
// in which the label occurs.
//
// The MR_sll_port field will contain a negative number if there is no
// execution tracing port associated with the label. If there is, the
// field will contain a value of type MR_TracePort. For labels associated
// with events, this will be the port of the event. For return labels,
// this port will be exception (since exception events are associated with
// the return from the call that raised the exception).
//
// The MR_sll_hidden field contains a boolean which is meaningful only if the
// label corresponds to an execution tracing event. It will be MR_HIDDEN if the
// event should have no effects that the user can see (no message printed, no
// increment of the event number etc), and MR_NOT_HIDDEN otherwise. Hidden
// events are sometimes needed by the declarative debugger to provide the
// proper context for other events.
//
// The MR_sll_goal_path field contains an offset into the module-wide string
// table, leading to a string that gives the goal path associated with the
// label. If there is no meaningful goal path associated with the label,
// the offset will be zero, leading to the empty string. You can use the macro
// MR_label_goal_path to convert the value in the MR_sll_goal_path field to a
// string.
//
// A possible alternative would be to represent goal paths using statically
// allocated terms of the reverse_goal_path type. An almost-complete diff
// making that change was posted to the mercury-reviews mailing list on
// 30 Sep 2011, but it was not committed, since it lead to a 4% *increase*
// in the size of asm_fast.gc.debug executables. Even though different goal
// paths share a tail (the part of the path near the root) with the
// static reverse_goal_path term representation but not with the string
// representation, the string representation is so much more compact
// (usually taking 4 to 6 bytes for most steps) than the Mercury term
// representation (1 to 4 words for a step, plus 2 words for the rgp_cons,
// totalling at least 24 bytes per step on 64 bit systems), that the string
// representation is significantly more compact overall. The Mercury term
// representation does have the potential to speed up the implementation of
// the operations in the declarative debugger that need to test whether
// two goal paths represent two different direct components of the same parent
// goal. If the two different goal paths are represented as reverse_goal_paths,
// then doing this test on RGPA and RGPB simply requires the test
//
//      RGPA = rgp_cons(ParentRGPA, StepA),
//      RGPB = rgp_cons(ParentRGPB, StepB),
//      ParentRGPA = ParentRGPB
//
// and the last step can be done by a pointer comparison. This test can be done
// in constant time, whereas the current implementation of the same test
// (the function MR_trace_same_construct in trace/mercury_trace_declarative.c)
// works in linear time.
//
// If the label is the label of a user-defined event, then the
// MR_sll_user_event field will point to information about the user event;
// otherwise, the field will be NULL.
//
// The remaining fields give information about the values live at the given
// label, if this information is available. If it is available, the
// MR_has_valid_var_count macro will return true and the fields after the count
// are meaningful; if it is not available, the macro will return false and
// those fields are not meaningful (i.e. you are looking at an
// MR_LabelLayoutNoVarInfo structure).
//
// The format in which we store information about the values live at the label
// is somewhat complicated, due to our desire to make this information compact.
// We can represent a location in one of two ways, as an 8-bit MR_ShortLval
// or as a 32-bit MR_LongLval. We prefer representing a location as an
// MR_ShortLval, but of course not all locations can be represented in
// this way, so those other locations are represented as MR_LongLvals.
//
// The MR_sll_var_count field, if it is valid, is encoded by the formula
// (#Long << MR_SHORT_COUNT_BITS + #Short), where #Short is the number
// data items whose descriptions fit into an MR_ShortLval and #Long is the
// number of data items whose descriptions do not. (The number of distinct
// values that fit into 8 bits also fits into 8 bits, but since some
// locations hold the value of more than one variable at a time, not all
// the values need to be distinct; this is why MR_SHORT_COUNT_BITS is
// more than 8.)
//
// The MR_sll_types field points to an array of #Long + #Short
// MR_PseudoTypeInfos each giving the type of a live data item, with
// a small integer instead of a pointer representing a special kind of
// live data item (e.g. a saved succip or hp). This field will be null if
// #Long + #Short is zero.
//
// The MR_sll_long_locns field points to an array of #Long MR_LongLvals,
// while the MR_sll_short_locns field points to an array of #Short
// MR_ShortLvals. The element at index i in the MR_sll_long_locns vector
// will have its type described by the element at index i in the MR_sll_types
// vector, while the element at index i in the MR_sll_short_locns vector
// will have its type described by the element at index #Long + i in the
// MR_sll_types vector. MR_sll_long_locns will be NULL if #Long is zero,
// and similarly MR_sll_short_locns will be NULL if #Short is zero.
//
// The MR_sll_var_nums field may be NULL, which means that there is no
// information about the variable numbers of the live values. If the field
// is not NULL, it points to a vector of variable numbers, which has an element
// for each live data item. This is either the live data item's HLDS variable
// number, or one of two special values. Zero means that the live data item
// is not a variable (e.g. it is a saved copy of succip). The largest possible
// 16-bit number on the other hand means "the number of this variable does not
// fit into 16 bits". With the exception of these special values, the value
// in this slot uniquely identifies the live data item. (Not being able to
// uniquely identify nonvariable data items is never a problem. Not being able
// to uniquely identify variables is a problem, at the moment, only to the
// extent that the debugger cannot print their names.)
//
// The types of the live variables may or may not have type variables in them.
// If they do not, the MR_sll_tvars field will be NULL. If they do, it will
// point to an MR_TypeParamLocns structure that gives the locations of the
// typeinfos for those type variables. This structure gives the number of type
// variables and their locations, so that the code that needs the type
// parameters can materialize all the type parameters from their location
// descriptions in one go. This is an optimization, since the type parameter
// vector could simply be indexed on demand by the type variable's variable
// number stored within the MR_PseudoTypeInfos stored inside the vector
// pointed to by the MR_sll_types field.
//
// Since we allocate type variable numbers sequentially, the MR_tp_param_locns
// vector will usually be dense. However, after all variables whose types
// include e.g. type variable 2 have gone out of scope, variables whose
// types include type variable 3 may still be around. In cases like this,
// the entry for type variable 2 will be zero; this signals to the code
// in the internal debugger that materializes typeinfo structures that
// this typeinfo structure need not be materialized. Note that the array
// element MR_tp_param_locns[i] describes the location of the typeinfo
// structure for type variable i+1, since array offsets start at zero
// but type variable numbers start at one.
//
// The MR_sll_label_num_in_module is used for counting the number of times
// the event of this label is executed. It gives the label's index in the
// array pointed to by the module layout's MR_ml_label_exec_count field;
// whenever the event of this label is executed, the element in that array
// indicated by this index will be incremented (when MR_trace_count_enabled
// is set). The array element at index zero is ignored. A label layout will
// have zero in its MR_sll_label_num_in_module field if the label doesn't
// correspond to an event.
//
// XXX: Presently, inst information is ignored; we assume that all live values
// are ground.

#define MR_HIDDEN       1
#define MR_NOT_HIDDEN   0

struct MR_TypeParamLocns_Struct {
    // Since the compiler generates a single array of values to hold
    // *both* the count and the encoded parameter locations, the count
    // field must have the same size as MR_LongLval.
    //
    // XXX Since MR_LongLval is a typedef for MR_Unsigned, the count
    // should be unsigned as well. However, neither the code in the compiler
    // that emits values of these structures nor the code in the trace
    // and runtime directories handling these structures use unsigned
    // values yet.
    MR_Integer              MR_tp_param_count;
    MR_LongLval             MR_tp_param_locns[MR_VARIABLE_SIZED];
};

struct MR_LabelLayout_Struct {
    const MR_ProcLayout     *MR_sll_entry;
    MR_int_least8_t         MR_sll_port;
    MR_int_least8_t         MR_sll_hidden;
    MR_uint_least16_t       MR_sll_label_num_in_module;
    MR_uint_least32_t       MR_sll_goal_path;
    const MR_UserEvent      *MR_sll_user_event;
    MR_Integer              MR_sll_var_count; // >= 0, encoding Long > 0
    const MR_TypeParamLocns *MR_sll_tvars;
    const MR_PseudoTypeInfo *MR_sll_types;
    const MR_HLDSVarNum     *MR_sll_var_nums;
    const MR_ShortLval      *MR_sll_short_locns;
    const MR_LongLval       *MR_sll_long_locns;
};

typedef struct MR_LabelLayoutShort_Struct {
    const MR_ProcLayout     *MR_sll_entry;
    MR_int_least8_t         MR_sll_port;
    MR_int_least8_t         MR_sll_hidden;
    MR_uint_least16_t       MR_sll_label_num_in_module;
    MR_uint_least32_t       MR_sll_goal_path;
    const MR_UserEvent      *MR_sll_user_event;
    MR_Integer              MR_sll_var_count; // >= 0 , encoding Long == 0
    const MR_TypeParamLocns *MR_sll_tvars;
    const MR_PseudoTypeInfo *MR_sll_types;
    const MR_HLDSVarNum     *MR_sll_var_nums;
    const MR_ShortLval      *MR_sll_short_locns;
} MR_LabelLayoutShort;

typedef struct MR_LabelLayoutNoVarInfo_Struct {
    const MR_ProcLayout     *MR_sll_entry;
    MR_int_least8_t         MR_sll_port;
    MR_int_least8_t         MR_sll_hidden;
    MR_uint_least16_t       MR_sll_label_num_in_module;
    MR_uint_least32_t       MR_sll_goal_path;
    const MR_UserEvent      *MR_sll_user_event;
    MR_Integer              MR_sll_var_count; // < 0
} MR_LabelLayoutNoVarInfo;

#define MR_label_goal_path(layout)                                          \
    ((MR_PROC_LAYOUT_HAS_EXEC_TRACE((layout)->MR_sll_entry)) ?              \
        ((layout)->MR_sll_entry->MR_sle_module_layout                       \
            ->MR_ml_string_table                                            \
        + ((layout)->MR_sll_goal_path >> 1))                                \
    : "")

#define MR_SHORT_COUNT_BITS 10
#define MR_SHORT_COUNT_MASK ((1 << MR_SHORT_COUNT_BITS) - 1)

#define MR_has_valid_var_count(sll)                                         \
        (((sll)->MR_sll_var_count) >= 0)
#define MR_has_valid_var_info(sll)                                          \
        (((sll)->MR_sll_var_count) > 0)
#define MR_short_desc_var_count(sll)                                        \
        (((sll)->MR_sll_var_count) & MR_SHORT_COUNT_MASK)
#define MR_long_desc_var_count(sll)                                         \
        (((sll)->MR_sll_var_count) >> MR_SHORT_COUNT_BITS)
#define MR_all_desc_var_count(sll)                                          \
        (MR_long_desc_var_count(sll) + MR_short_desc_var_count(sll))

#define MR_var_pti(sll, i)                                                  \
        ((sll)->MR_sll_types[(i)])
#define MR_short_desc_var_locn(sll, i)                                      \
        ((sll)->MR_sll_short_locns[(i)])
#define MR_long_desc_var_locn(sll, i)                                       \
        ((sll)->MR_sll_long_locns[(i)])

// Define a stack layout for an internal label.
//
// The only useful information in the structures created by this macro
// is the reference to the procedure layout, which allows you to find the
// stack frame size and the succip location, thereby enabling stack tracing.
//
// For the native garbage collector, we will need to add meaningful
// live value information as well to these macros.

#define MR_LAYOUT_FROM_LABEL(label)                                         \
    MR_PASTE2(mercury_data__label_layout__, label)

#define MR_LABEL_LAYOUT_REF(label)                                          \
    ((const MR_LabelLayout *) &MR_LAYOUT_FROM_LABEL(MR_add_prefix(label)))

#define MR_MAKE_USER_INTERNAL_LAYOUT(module, name, arity, mode, label)      \
    MR_LabelLayoutNoVarInfo                                                 \
    MR_label_layout_user_name(module, name, arity, mode, label) = {         \
        (MR_ProcLayout *) &                                                 \
            MR_proc_layout_user_name(module, name, arity, mode),            \
        0,                                                                  \
        -1,                                                                 \
        MR_FALSE,                                                           \
        0,                                                                  \
        0,                                                                  \
        -1      /* No info about live values. */                            \
    }

////////////////////////////////////////////////////////////////////////////

// These macros are used as shorthands in generated C source files
// for some fields of MR_LabelLayouts.
//
// We need to cast the addresses of proc layout structures because there
// are several kinds of proc layouts, of different (though compatible) types.

#define MR_LL(e, port, num, path)                                           \
        MR_PROC_LAYOUT(MR_add_prefix(e)),                                   \
        MR_PASTE2(MR_PORT_, port),                                          \
        MR_NOT_HIDDEN, (num), (path), NULL

#define MR_LL_H(e, port, num, path)                                         \
        MR_PROC_LAYOUT(MR_add_prefix(e)),                                   \
        MR_PASTE2(MR_PORT_, port),                                          \
        MR_HIDDEN, (num), (path), NULL

#define MR_LL_U(e, port, num, path, ue)                                     \
        MR_PROC_LAYOUT(MR_add_prefix(e)),                                   \
        MR_PASTE2(MR_PORT_, port),                                          \
        MR_NOT_HIDDEN, (num), (path), (ue)

#define MR_LL_H_U(e, port, num, path, ue)                                   \
        MR_PROC_LAYOUT(MR_add_prefix(e)),                                   \
        MR_PASTE2(MR_PORT_, port),                                          \
        MR_HIDDEN, (num), (path), (ue)

#define MR_LLVS(m, p, h, s)                                                 \
        &MR_pseudo_type_infos(m)[p],                                        \
        &MR_hlds_var_nums(m)[h],                                            \
        &MR_short_locns(m)[s]

#define MR_LLVL(m, p, h, s, l)                                              \
        &MR_pseudo_type_infos(m)[p],                                        \
        &MR_hlds_var_nums(m)[h],                                            \
        &MR_short_locns(m)[s],                                              \
        &MR_long_locns(m)[l]

#define MR_LLVS0(m, p, h, s)                                                \
        0,                                                                  \
        MR_LLVS(m, p, h, s)

#define MR_LLVL0(m, p, h, s, l)                                             \
        0,                                                                  \
        MR_LLVL(m, p, h, s, l)

#define MR_LLVSC(m, tpt, tpc, p, h, s)                                      \
        (const MR_TypeParamLocns *) MR_COMMON(tpt, tpc),                    \
        MR_LLVS(m, p, h, s)

#define MR_LLVLC(m, tpt, tpc, p, h, s, l)                                   \
        (const MR_TypeParamLocns *) MR_COMMON(tpt, tpc),                    \
        MR_LLVL(m, p, h, s, l)

#define MR_cast_to_pti1(r1)                                                 \
        (MR_PseudoTypeInfo) (r1),

#define MR_cast_to_pti2(r1, r2)                                             \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),

#define MR_cast_to_pti3(r1, r2, r3)                                         \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3)

#define MR_cast_to_pti4(r1, r2, r3, r4)                                     \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3),                                           \
        (MR_PseudoTypeInfo) (r4),

#define MR_cast_to_pti5(r1, r2, r3, r4, r5)                                 \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3),                                           \
        (MR_PseudoTypeInfo) (r4),                                           \
        (MR_PseudoTypeInfo) (r5),

#define MR_cast_to_pti6(r1, r2, r3, r4, r5, r6)                             \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3),                                           \
        (MR_PseudoTypeInfo) (r4),                                           \
        (MR_PseudoTypeInfo) (r5),                                           \
        (MR_PseudoTypeInfo) (r6),

#define MR_cast_to_pti7(r1, r2, r3, r4, r5, r6, r7)                         \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3),                                           \
        (MR_PseudoTypeInfo) (r4),                                           \
        (MR_PseudoTypeInfo) (r5),                                           \
        (MR_PseudoTypeInfo) (r6),                                           \
        (MR_PseudoTypeInfo) (r7),

#define MR_cast_to_pti8(r1, r2, r3, r4, r5, r6, r7, r8)                     \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3),                                           \
        (MR_PseudoTypeInfo) (r4),                                           \
        (MR_PseudoTypeInfo) (r5),                                           \
        (MR_PseudoTypeInfo) (r6),                                           \
        (MR_PseudoTypeInfo) (r7),                                           \
        (MR_PseudoTypeInfo) (r8),

#define MR_cast_to_pti9(r1, r2, r3, r4, r5, r6, r7, r8, r9)                 \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3),                                           \
        (MR_PseudoTypeInfo) (r4),                                           \
        (MR_PseudoTypeInfo) (r5),                                           \
        (MR_PseudoTypeInfo) (r6),                                           \
        (MR_PseudoTypeInfo) (r7),                                           \
        (MR_PseudoTypeInfo) (r8),                                           \
        (MR_PseudoTypeInfo) (r9),

#define MR_cast_to_pti10(r1, r2, r3, r4, r5, r6, r7, r8, r9, r10)           \
        (MR_PseudoTypeInfo) (r1),                                           \
        (MR_PseudoTypeInfo) (r2),                                           \
        (MR_PseudoTypeInfo) (r3),                                           \
        (MR_PseudoTypeInfo) (r4),                                           \
        (MR_PseudoTypeInfo) (r5),                                           \
        (MR_PseudoTypeInfo) (r6),                                           \
        (MR_PseudoTypeInfo) (r7),                                           \
        (MR_PseudoTypeInfo) (r8),                                           \
        (MR_PseudoTypeInfo) (r9),                                           \
        (MR_PseudoTypeInfo) (r10),

////////////////////////////////////////////////////////////////////////////
// Definitions for MR_ProcLayout.

// The MR_TableIoEntry structure.
//
// To enable printing and declarative debugging of I/O actions, the compiler
// generates one of these structures for each I/O primitive. The compiler
// transforms the bodies of those primitives to create a block of memory
// (the answerblock, the action's entry in the I/O table), and fill it in with
//
// - a pointer to the primitive's MR_TableIoEntry structure, and
// - the values of some of the primitive's arguments (excluding the
//   I/O states, which are dummies).
//
// The arguments in the answerblock will always include the output arguments,
// since I/O tabling needs these to make the primitive idempotent.
// If the primitive does not have type class constraints, it will include
// the values of the input arguments as well, for two reasons:
//
// - to present them to the user on request, either via mdb's browsing
//   commands, or via the declarative debugger
//
// - the input typeinfo arguments are needed to present the value of other
//   arguments, both inputs and outputs, to the user.
//
// In the presence of typeclass constraints on the predicate, we cannot
// guarantee that we can encode the locations of the typeinfos (which may be
// arbitrarily deep inside typeclass_infos) in our fixed size location
// descriptions. We therefore set the have_arg_infos field to false,
// indicating that none of the following fields contain meaningful information.
//
// In the absence of typeclass constraints on the predicate, we set the
// have_arg_infos field to true. In that case, num_ptis will contain the
// number of arguments in the answer block, the ptis field will point to
// a vector of num_ptis pseudo-typeinfos (one for each argument in the answer
// block), and the type_params field maps the type variables that occur
// in the pseudo-typeinfos to the locations of the typeinfos describing
// the types bound to them.
//
// The entry_proc field, which is always meaningful, identifies the procedure
// that created the I/O table entry.

typedef struct MR_TableIoEntry_Struct {
    const MR_ProcLayout         *MR_table_io_entry_proc;
    MR_bool                     MR_table_io_entry_have_arg_infos;
    MR_Integer                  MR_table_io_entry_num_ptis;
    const MR_PseudoTypeInfo     *MR_table_io_entry_ptis;
    const MR_TypeParamLocns     *MR_table_io_entry_type_params;
} MR_TableIoEntry;

// MR_TableInfo: compiler generated information describing the tabling
// data structures used by a procedure.
//
// For I/O tabled procedures, the information is in the io_decl field.
// For other kinds of tabled procedures, it is in the gen field.
// The init field is used for initialization only.
//
// The MR_table_proc field is not const because the structure it points to
// has fields containing statistics, which are updated at runtime.

typedef union {
    const void                  *MR_table_init;
    const MR_TableIoEntry       *MR_table_io_entry;
    const MR_Table_Gen          *MR_table_gen;
    MR_ProcTableInfo            *MR_table_proc;
} MR_TableInfo;

// The MR_StackTraversal structure contains the following fields:
//
// The code_addr field points to the start of the procedure's code.
// This allows the profiler to figure out which procedure a sampled program
// counter belongs to, and allows the debugger to implement retry.
//
// The succip_locn field encodes the location of the saved succip if it is
// saved in a general purpose stack slot. If the succip is saved in a special
// purpose stack slot (as it is for model_non procedures) or if the procedure
// never saves the succip (as in leaf procedures), this field will contain -1.
//
// The stack_slots field gives the number of general purpose stack slots
// in the procedure.
//
// The detism field encodes the determinism of the procedure.

typedef struct MR_StackTraversal_Struct {
    MR_Code                     *MR_trav_code_addr;
    MR_LongLval                 MR_trav_succip_locn;
    MR_int_least16_t            MR_trav_stack_slots;
    MR_Determinism              MR_trav_detism;
} MR_StackTraversal;

#define MR_PROC_LAYOUT_IS_UCI(entry)                                    \
    MR_PROC_ID_IS_UCI(entry->MR_sle_proc_id)

// The MR_ExecTrace structure contains the following fields.
//
// The call_label field points to the label layout structure for the label
// associated with the call event at the entry to the procedure. The purpose
// of this field is to allow the debugger to find out which variables
// are where on entry, so it can reexecute the procedure if asked to do so
// and if the values of the required variables are still available.
//
// The labels field contains a pointer to an array of pointers to label layout
// structures; the size of the array is given by the num_labels field. The
// initial part of the array will contain a pointer to the label layout
// structure of every interface event in the procedure; the later parts will
// contain a pointer to the label layout structure of every internal event.
// There is no ordering on the events beyond interface first, internal second.
//
// The used_var_names field points to an array that contains offsets
// into the string table, with the offset at index i-1 giving the name of
// variable i (since variable numbers start at one). If a variable has no name
// or cannot be referred to from an event, the offset will be zero, at which
// offset the string table will contain an empty string.
//
// The max_named_var_num field gives the number of elements in the
// used_var_names table, which is also the number of the highest numbered
// named variable. Note that unnamed variables may have numbers higher than
// this.
//
// The max_r_num field tells the debugger which Mercury abstract machine
// registers need saving in MR_trace: besides the special registers, it is
// the general-purpose registers rN for values of N up to and including the
// value of this field. Note that this field contains an upper bound; in
// general, there will be calls to MR_trace at which the number of the highest
// numbered general purpose (i.e. rN) registers is less than this. However,
// storing the upper bound gets us almost all the benefit (of not saving and
// restoring all the thousand rN registers) for a small fraction of the static
// space cost of storing the actual number in label layout structures.
//
// If the procedure is compiled with deep tracing, the maybe_from_full field
// will contain a negative number. If it is compiled with shallow tracing,
// it will contain the number of the stack slot that holds the flag that says
// whether this incarnation of the procedure was called from deeply traced code
// or not. (The determinism of the procedure decides whether the stack slot
// refers to a stackvar or a framevar.)
//
// If tabling of I/O actions is enabled, the maybe_io_seq field will contain
// the number of the stack slot that holds the value the I/O action counter
// had on entry to this procedure. Even procedures that do not have I/O state
// arguments will have such a slot, since they or their descendants may call
// unsafe_perform_io.
//
// If trailing is not enabled, the maybe_trail field will contain a negative
// number. If it is enabled, it will contain number of the first of two stack
// slots used for checkpointing the state of the trail on entry to the
// procedure. The first contains the trail pointer, the second the ticket.
//
// If the procedure lives on the nondet stack, or if it cannot create any
// temporary nondet stack frames, the maybe_maxfr field will contain a negative
// number. If it lives on the det stack, and can create temporary nondet stack
// frames, it will contain the number of the stack slot that contains the
// value of maxfr on entry, for use in executing the retry debugger command
// from the middle of the procedure.
//
// The eval_method field contains a representation of the evaluation method
// used by the procedure. The retry command needs this information if it is
// to reset the call tables of the procedure invocations being retried.
//
// We cannot put enums into structures as bit fields. To avoid wasting space,
// we put MR_EvalMethodInts into structures instead of MR_EvalMethods
// themselves.
//
// If the procedure is compiled with some form of tabling, the maybe_call_table
// field contains the number of the stack slot through which we can reach the
// call table entry for this call. In forms of tabling which associate a C
// structure (MR_Subgoal, MR_MemoNonRecord) with a call table entry, the slot
// will point to that structure; in other forms of tabling, it will point
// to the call's MR_TableNode.
//
// The flags field encodes boolean properties of the procedure. For now,
// the only property is whether the procedure has a pair of I/O state
// arguments.
//
// If the procedure lives on the nondet stack, or if it cannot create any
// temporary nondet stack frames, the maybe_maxfr field will contain a negative
// number. If it lives on the det stack, and can create temporary nondet stack
// frames, it will contain the number of the stack slot that contains the
// value of maxfr on entry, for use in executing the retry debugger command
// from the middle of the procedure.

#define MR_EVAL_METHOD_MEMO_STRICT  MR_EVAL_METHOD_MEMO
#define MR_EVAL_METHOD_MEMO_FAST_LOOSE  MR_EVAL_METHOD_MEMO
#define MR_EVAL_METHOD_MEMO_SPECIFIED   MR_EVAL_METHOD_MEMO

typedef enum {
    MR_EVAL_METHOD_NORMAL,
    MR_EVAL_METHOD_LOOP_CHECK,
    MR_EVAL_METHOD_MEMO,
    MR_EVAL_METHOD_MINIMAL_STACK_COPY,
    MR_EVAL_METHOD_MINIMAL_OWN_STACKS_CONSUMER,
    MR_EVAL_METHOD_MINIMAL_OWN_STACKS_GENERATOR,
    MR_EVAL_METHOD_TABLE_IO,
    MR_EVAL_METHOD_TABLE_IO_DECL,
    MR_EVAL_METHOD_TABLE_IO_UNITIZE,
    MR_EVAL_METHOD_TABLE_IO_UNITIZE_DECL
} MR_EvalMethod;

typedef MR_int_least8_t     MR_EvalMethodInt;

typedef enum {
    MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_NONE),
    MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_BASIC),
    MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_BASIC_USER),
    MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_SHALLOW),
    MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_DEEP),
    MR_DEFINE_MERCURY_ENUM_CONST(MR_TRACE_LEVEL_DECL_REP)
} MR_TraceLevel;

typedef MR_int_least8_t     MR_TraceLevelInt;

typedef struct MR_ExecTrace_Struct {
    const MR_LabelLayout        *MR_exec_call_label;
    const MR_ModuleLayout       *MR_exec_module_layout;
    const MR_LabelLayout        **MR_exec_labels;
    MR_uint_least32_t           MR_exec_num_labels;
    MR_TableInfo                MR_exec_table_info;
    const MR_uint_least16_t     *MR_exec_head_var_nums;
    const MR_uint_least32_t     *MR_exec_used_var_names;
    MR_uint_least16_t           MR_exec_num_head_vars;
    MR_uint_least16_t           MR_exec_max_named_var_num;
    MR_uint_least16_t           MR_exec_max_r_num;
    MR_uint_least16_t           MR_exec_max_f_num;
    MR_int_least8_t             MR_exec_maybe_from_full;
    MR_int_least8_t             MR_exec_maybe_io_seq;
    MR_int_least8_t             MR_exec_maybe_trail;
    MR_int_least8_t             MR_exec_maybe_maxfr;
    MR_EvalMethodInt            MR_exec_eval_method_CAST_ME;
    MR_int_least8_t             MR_exec_maybe_call_table;
    MR_TraceLevelInt            MR_exec_trace_level_CAST_ME;
    MR_uint_least8_t            MR_exec_flags;
    MR_int_least8_t             MR_exec_maybe_tail_rec;
} MR_ExecTrace;

#define MR_compute_max_mr_num(max_mr_num, layout)                           \
    do {                                                                    \
        int max_r_num;                                                      \
                                                                            \
        max_r_num = (layout)->MR_sll_entry->MR_sle_max_r_num +              \
            MR_NUM_SPECIAL_REG;                                             \
        max_mr_num = MR_max(max_r_num, MR_FIRST_UNREAL_R_SLOT);             \
    } while (0)

// The code in the compiler that creates the flag field is
// encode_exec_trace_flags in stack_layout.m.

#define MR_PROC_LAYOUT_FLAG_HAS_IO_STATE_PAIR       0x1
#define MR_PROC_LAYOUT_FLAG_HAS_HIGHER_ORDER_ARG    0x2

#define MR_trace_find_reused_frames(proc_layout, sp, reused_frames)         \
    do {                                                                    \
        const MR_ExecTrace  *exec_trace;                                    \
        int                 tailrec_slot;                                   \
                                                                            \
        exec_trace = proc_layout->MR_sle_exec_trace;                        \
        if (exec_trace == NULL) {                                           \
            (reused_frames) = 0;                                            \
        } else {                                                            \
            tailrec_slot = proc_layout->MR_sle_maybe_tailrec;               \
            if (tailrec_slot <= 0) {                                        \
                (reused_frames) = 0;                                        \
            } else {                                                        \
                if (MR_DETISM_DET_STACK(proc_layout->MR_sle_detism)) {      \
                    (reused_frames) = MR_based_stackvar((sp), tailrec_slot);\
                } else {                                                    \
                    MR_fatal_error("tailrec reuses nondet stack frames");   \
                }                                                           \
            }                                                               \
        }                                                                   \
    } while (0)

// Proc layout structures contain one, two or three substructures.
//
// - The first substructure is the MR_StackTraversal structure, which contains
//   information that enables the stack to be traversed, e.g. for accurate gc.
//   It is always present if proc layouts are present at all.
//
// - The second group is the MR_ProcId union, which identifies the
//   procedure in terms that are meaningful to both humans and machines.
//   It will be generated only if the module is compiled with stack tracing,
//   execution tracing or profiling. The MR_ProcId union has two alternatives,
//   one for user-defined procedures and one for procedures of the compiler
//   generated Unify, Index and Compare predicates.
//
// - The third group is everything else. Currently, this consists of
//   information that is of interest to the debugger, to the deep profiler,
//   or both.
//
//   The information that is of interest to the debugger only is stored in
//   the MR_ExecTrace structure, which will be generated only if the module
//   is compiled with execution tracing. The information that is of interest to
//   the deep profiler is stored in the MR_ProcStatic structure, which will be
//   generated only if the module is compiled in a deep profiling grade. The
//   other fields in the group are of interest to both the debugger and the
//   deep profiler, and will be generated if either execution tracing or deep
//   profiling is enabled.
//
//   If the body_bytes field is NULL, it means that no representation of the
//   procedure body is available. If non-NULL, it contains a pointer to an
//   array of bytecodes that represents the body of the procedure. The
//   bytecode array should be interpreted by the read_proc_rep predicate in
//   mdbcomp/program_representation.m (it starts with an encoded form of the
//   array's length). Its contents are generated by compiler/prog_rep.m.
//
//   The module_common_layout field points to the part of the module layout
//   structure of the module containing the procedure that is common to the
//   debugger and the deep profiler. Amongst other things, it gives access to
//   the string table that the body_bytes fields refers to.
//
// The runtime system considers all proc layout structures to be of type
// MR_ProcLayout, but must use the macros defined below to check for the
// existence of each substructure before accessing the fields of that
// substructure. The macros are MR_PROC_LAYOUT_HAS_PROC_ID to check for the
// MR_ProcId substructure, MR_PROC_LAYOUT_HAS_EXEC_TRACE to check for the
// MR_ExecTrace substructure, and MR_PROC_LAYOUT_HAS_PROC_STATIC to check for
// the MR_ProcStatic substructure.
//
// The reason why some substructures may be missing is to save space.
// If the options with which a module is compiled do not require execution
// tracing, then the MR_ExecTrace substructure will not present, and if the
// options do not require procedure identification, then the MR_ProcId
// substructure will not be present either. The body_bytes and module_layout
// fields cannot be non-NULL unless at least one of exec trace and proc static
// substructures is present, but they are otherwise independent of those
// substructures.
//
// The compiler itself generates proc layout structures using the following
// three types.
//
// - When generating only stack traversal information, the compiler will
//   generate proc layout structures of type MR_ProcLayout_Traversal.
//
// - When generating stack traversal and procedure id information, plus
//   possibly others, the compiler will generate proc layout structures of
//   types MR_ProcLayoutUser and MR_ProcLayoutUCI.

struct MR_ProcLayout_Struct {
    MR_StackTraversal                   MR_sle_traversal;
    MR_ProcId                           MR_sle_proc_id;
    MR_STATIC_CODE_CONST MR_ExecTrace   *MR_sle_exec_trace;
    MR_ProcStatic                       *MR_sle_proc_static;
    const MR_uint_least8_t              *MR_sle_body_bytes;
    const MR_ModuleLayout               *MR_sle_module_layout;
};

typedef struct MR_ProcLayoutUser_Struct {
    MR_StackTraversal                   MR_user_traversal;
    MR_UserProcId                       MR_user_id;
    MR_STATIC_CODE_CONST MR_ExecTrace   *MR_sle_exec_trace;
    MR_ProcStatic                       *MR_sle_proc_static;
    const MR_uint_least8_t              *MR_sle_body_bytes;
    const MR_ModuleLayout               *MR_sle_module_layout;
} MR_ProcLayoutUser;

typedef struct MR_ProcLayoutUCI_Struct {
    MR_StackTraversal                   MR_uci_traversal;
    MR_UCIProcId                        MR_uci_id;
    MR_STATIC_CODE_CONST MR_ExecTrace   *MR_sle_exec_trace;
    MR_ProcStatic                       *MR_sle_proc_static;
    const MR_uint_least8_t              *MR_sle_body_bytes;
    const MR_ModuleLayout               *MR_sle_module_layout;
} MR_ProcLayoutUCI;

typedef struct MR_ProcLayout_Traversal_Struct {
    MR_StackTraversal                   MR_trav_traversal;
    MR_Word                             MR_trav_no_proc_id; // will be -1
} MR_ProcLayout_Traversal;

#define MR_PROC_LAYOUT_HAS_PROC_ID(entry)                                   \
        (MR_PROC_ID_EXISTS(entry->MR_sle_proc_id))

#define MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry)                                \
        (MR_PROC_LAYOUT_HAS_PROC_ID(entry) &&                               \
        entry->MR_sle_exec_trace != NULL)

#define MR_PROC_LAYOUT_HAS_PROC_STATIC(entry)                               \
        (MR_PROC_LAYOUT_HAS_PROC_ID(entry) &&                               \
        entry->MR_sle_proc_static != NULL)

#define MR_PROC_LAYOUT_HAS_THIRD_GROUP(entry)                               \
        (MR_PROC_LAYOUT_HAS_PROC_ID(entry) &&                               \
        ( entry->MR_sle_exec_trace != NULL                                  \
        || entry->MR_sle_proc_static != NULL))

#define MR_sle_code_addr        MR_sle_traversal.MR_trav_code_addr
#define MR_sle_succip_locn      MR_sle_traversal.MR_trav_succip_locn
#define MR_sle_stack_slots      MR_sle_traversal.MR_trav_stack_slots
#define MR_sle_detism           MR_sle_traversal.MR_trav_detism

#define MR_sle_user             MR_sle_proc_id.MR_proc_user
#define MR_sle_uci              MR_sle_proc_id.MR_proc_uci

#define MR_sle_call_label       MR_sle_exec_trace->MR_exec_call_label
#define MR_sle_module_layout    MR_sle_exec_trace->MR_exec_module_layout
#define MR_sle_labels           MR_sle_exec_trace->MR_exec_labels
#define MR_sle_num_labels       MR_sle_exec_trace->MR_exec_num_labels
#define MR_sle_tabling_pointer  MR_sle_exec_trace->MR_exec_tabling_pointer
#define MR_sle_table_info       MR_sle_exec_trace->MR_exec_table_info
#define MR_sle_head_var_nums    MR_sle_exec_trace->MR_exec_head_var_nums
#define MR_sle_num_head_vars    MR_sle_exec_trace->MR_exec_num_head_vars
#define MR_sle_used_var_names   MR_sle_exec_trace->MR_exec_used_var_names
#define MR_sle_max_named_var_num MR_sle_exec_trace->MR_exec_max_named_var_num
#define MR_sle_max_r_num        MR_sle_exec_trace->MR_exec_max_r_num
#define MR_sle_max_f_num        MR_sle_exec_trace->MR_exec_max_f_num
#define MR_sle_maybe_from_full  MR_sle_exec_trace->MR_exec_maybe_from_full
#define MR_sle_maybe_io_seq     MR_sle_exec_trace->MR_exec_maybe_io_seq
#define MR_sle_maybe_trail      MR_sle_exec_trace->MR_exec_maybe_trail
#define MR_sle_maybe_maxfr      MR_sle_exec_trace->MR_exec_maybe_maxfr
#define MR_sle_maybe_call_table MR_sle_exec_trace->MR_exec_maybe_call_table
#define MR_sle_maybe_decl_debug MR_sle_exec_trace->MR_exec_maybe_decl_debug
#define MR_sle_maybe_tailrec    MR_sle_exec_trace->MR_exec_maybe_tail_rec

#define MR_sle_eval_method(proc_layout_ptr)                                 \
    ((MR_EvalMethod) (proc_layout_ptr)->                                    \
        MR_sle_exec_trace->MR_exec_eval_method_CAST_ME)

#define MR_sle_trace_level(proc_layout_ptr)                                 \
    ((MR_TraceLevel) (proc_layout_ptr)->                                    \
        MR_sle_exec_trace->MR_exec_trace_level_CAST_ME)

#define MR_proc_has_io_state_pair(proc_layout_ptr)                          \
    ((proc_layout_ptr)->MR_sle_exec_trace->MR_exec_flags                    \
        & MR_PROC_LAYOUT_FLAG_HAS_IO_STATE_PAIR)

#define MR_proc_has_higher_order_arg(proc_layout_ptr)                       \
    ((proc_layout_ptr)->MR_sle_exec_trace->MR_exec_flags                    \
        & MR_PROC_LAYOUT_FLAG_HAS_HIGHER_ORDER_ARG)

// Adjust the arity of functions for printing.
#define MR_sle_user_adjusted_arity(entry)                                   \
    ((entry)->MR_sle_user.MR_user_pred_form_arity -                         \
        (((entry)->MR_sle_user.MR_user_pred_or_func == MR_FUNCTION) ? 1 : 0))

#define MR_MAX_VARNAME_SIZE 160

// Return the name (if any) of the variable with the given HLDS variable number
// in the procedure indicated by the first argument.
//
// The name will actually be found by MR_name_in_string_table, so the
// comments there about name size and should_copy apply here as well.

extern  MR_ConstString  MR_hlds_var_name(const MR_ProcLayout *entry,
                            int hlds_var_num, int *should_copy);

// Return the name (if any) of the variable with the given name code
// in the given string table.
//
// Sometimes, the returned name will point to static, const storage,
// whose contents are valid until the end of the program's execution,
// while at other times, it will point to a buffer whose contents
// will be valid only until the next call to MR_name_in_string_table.
//
// Callers that want to know which is the case should pass a non-NULL
// value for should_copy. The returned name will point to the buffer
// if and only if *should_copy is true. The size of the buffer is
// MR_MAX_VARNAME_SIZE bytes.

extern  MR_ConstString  MR_name_in_string_table(const char *string_table,
                            MR_Integer string_table_size,
                            MR_uint_least32_t name_code, int *should_copy);

// Given a string, see whether its end consists a sequence of digits.
// If yes, return the offset of the first digit in this sequence relative
// to the start of the string. Otherwise, return a negative number.

extern  int             MR_find_start_of_num_suffix(const char *str);

// Define a layout structure for a procedure, containing information
// for stack traversal and procedure identification.
//
// The slot count and the succip location parameters do not have to be
// supplied for procedures that live on the nondet stack, since for such
// procedures the size of the frame can be deduced from the prevfr field
// and the location of the succip is fixed.
//
// An unknown slot count should be signalled by MR_PROC_NO_SLOT_COUNT.
// An unknown succip location should be signalled by MR_LONG_LVAL_TYPE_UNKNOWN.
//
// For the procedure identification, we always use the same module name
// for the defining and declaring modules, since procedures whose code
// is hand-written as C modules cannot be inlined in other Mercury modules.
//
// Due to the possibility that code addresses are not static, any use of
// the MR_MAKE_PROC_ID_PROC_LAYOUT macro has to be accompanied by a call to the
// MR_INIT_PROC_LAYOUT_ADDR macro in the initialization code of the C module
// that defines the entry. (The cast in the body of MR_INIT_PROC_LAYOUT_ADDR
// is needed because compiler-generated layout structures may use any of the
// variant types listed above.)

#define MR_PROC_NO_SLOT_COUNT       -1

#ifdef  MR_STATIC_CODE_ADDRESSES
 #define    MR_MAKE_PROC_LAYOUT_ADDR(entry)     MR_ENTRY(entry)
 #define    MR_INIT_PROC_LAYOUT_ADDR(entry)     do { } while (0)
#else
 #define    MR_MAKE_PROC_LAYOUT_ADDR(entry)     ((MR_Code *) NULL)
 #define    MR_INIT_PROC_LAYOUT_ADDR(entry)                                 \
        do {                                                                \
            ((MR_ProcLayout *) &                                            \
            MR_PASTE2(mercury_data__proc_layout__, entry))                  \
                ->MR_sle_code_addr = MR_ENTRY(entry);                       \
        } while (0)
#endif

#define MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(sc, detism, slots, succip_locn, \
        pf, module, name, arity, mode, proc_static)                          \
    MR_declare_entry(MR_proc_entry_user_name(module, name,                   \
        arity, mode));                                                       \
    sc const MR_ProcLayoutUser                                               \
    MR_proc_layout_user_name(module, name, arity, mode) = {                  \
        {                                                                    \
            MR_MAKE_PROC_LAYOUT_ADDR(                                        \
                MR_proc_entry_user_name(module, name,                        \
                    arity, mode)),                                           \
            succip_locn,                                                     \
            slots,                                                           \
            detism                                                           \
        },                                                                   \
        {                                                                    \
            pf,                                                              \
            MR_STRINGIFY(module),                                            \
            MR_STRINGIFY(module),                                            \
            MR_STRINGIFY(name),                                              \
            arity,                                                           \
            mode                                                             \
        },                                                                   \
        NULL,                                                                \
        (MR_ProcStatic *) proc_static                                        \
    }

#define MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(sc, detism, slots, succip_locn, \
        module, name, type, arity, mode, proc_static)                       \
    MR_declare_entry(MR_proc_entry_uci_name(module, name,                   \
        type, arity, mode));                                                \
    sc const MR_ProcLayoutUCI                                               \
    MR_proc_layout_uci_name(module, name, type, arity, mode) = {            \
        {                                                                   \
            MR_MAKE_PROC_LAYOUT_ADDR(                                       \
                MR_proc_entry_uci_name(module, name,                        \
                    type, arity, mode)),                                    \
            succip_locn,                                                    \
            slots,                                                          \
            detism                                                          \
        },                                                                  \
        {                                                                   \
            MR_STRINGIFY(type),                                             \
            MR_STRINGIFY(module),                                           \
            MR_STRINGIFY(module),                                           \
            MR_STRINGIFY(name),                                             \
            arity,                                                          \
            mode                                                            \
        },                                                                  \
        NULL,                                                               \
        (MR_ProcStatic *) proc_static                                       \
    }

#define MR_NO_EXTERN_DECL

#define MR_STATIC_USER_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn,  \
        pf, module, name, arity, mode)                                      \
    MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(static, detism, slots,             \
        succip_locn, pf, module, name, arity, mode,                         \
        &MR_proc_static_user_name(module, name, arity, mode))
#define MR_EXTERN_USER_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn,  \
        pf, module, name, arity, mode)                                      \
    MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots,  \
        succip_locn, pf, module, name, arity, mode,                         \
        &MR_proc_static_user_name(module, name, arity, mode))

#define MR_STATIC_UCI_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn,   \
        module, name, type, arity, mode)                                    \
    MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(static, detism, slots,              \
        succip_locn, module, name, type, arity, mode,                       \
        &MR_proc_static_uci_name(module, name, type, arity, mode))
#define MR_EXTERN_UCI_PROC_STATIC_PROC_LAYOUT(detism, slots, succip_locn,   \
        module, name, type, arity, mode)                                    \
    MR_MAKE_UCI_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots,   \
        succip_locn, module, name, type, arity, mode,                       \
        &MR_proc_static_uci_name(module, name, type, arity, mode))

#define MR_STATIC_USER_PROC_ID_PROC_LAYOUT(detism, slots, succip_locn,      \
        pf, module, name, arity, mode)                                      \
    MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(static, detism, slots,             \
        succip_locn, pf, module, name, arity, mode, NULL)
#define MR_EXTERN_USER_PROC_ID_PROC_LAYOUT(detism, slots, succip_locn,      \
        pf, module, name, arity, mode)                                      \
    MR_MAKE_USER_PROC_STATIC_PROC_LAYOUT(MR_NO_EXTERN_DECL, detism, slots,  \
        succip_locn, pf, module, name, arity, mode, NULL)

#define MR_DECLARE_UCI_PROC_STATIC_LAYOUTS(mod, n, a)                       \
    extern const MR_ProcLayoutUCI                                           \
        MR_proc_layout_uci_name(mod, __Unify__, n, a, 0);                   \
    extern const MR_ProcLayoutUCI                                           \
        MR_proc_layout_uci_name(mod, __Compare__, n, a, 0);                 \
    extern const MR_ProcLayoutUCI                                           \
        MR_proc_layout_uci_name(mod, __CompareRep__, n, a, 0);

// In procedures compiled with execution tracing, three items are stored
// in stack slots with fixed numbers. They are:
//
//  the event number of the last event before the call event,
//  the call number, and
//  the call depth.
//
// Note that the first slot does not store the number of the call event
// itself, but rather the number of the call event minus one. The reason
// for this is that (a) incrementing the number stored in this slot would
// increase executable size, and (b) if the procedure is shallow traced,
// MR_trace may not be called for the call event, so we cannot shift the
// burden of initializing fields to the MR_trace of the call event either.
//
// The following macros will access the fixed slots. They can be used whenever
// MR_PROC_LAYOUT_HAS_EXEC_TRACE(entry) is true; which set you should use
// depends on the determinism of the procedure.
//
// These macros have to be kept in sync with compiler/trace.m.

#define MR_event_num_framevar(base_curfr)    MR_based_framevar(base_curfr, 1)
#define MR_call_num_framevar(base_curfr)     MR_based_framevar(base_curfr, 2)
#define MR_call_depth_framevar(base_curfr)   MR_based_framevar(base_curfr, 3)

#define MR_event_num_stackvar(base_sp)       MR_based_stackvar(base_sp, 1)
#define MR_call_num_stackvar(base_sp)        MR_based_stackvar(base_sp, 2)
#define MR_call_depth_stackvar(base_sp)      MR_based_stackvar(base_sp, 3)

// In model_non procedures compiled with --trace-redo, one or two other items
// are stored in fixed stack slots. These are
//
//  the address of the layout structure for the redo event
//  the saved copy of the from-full flag (only if trace level is shallow)
//
// The following macros will access these slots. They should be used only from
// within the code that calls MR_trace for the REDO event.
//
// This macros have to be kept in sync with compiler/trace.m.

#define MR_redo_layout_framevar(base_curfr)   MR_based_framevar(base_curfr, 4)
#define MR_redo_fromfull_framevar(base_curfr) MR_based_framevar(base_curfr, 5)

////////////////////////////////////////////////////////////////////////////
// Definitions for MR_ModuleLayout.
//
// The layout structure for a module contains the following fields.
//
// The MR_ml_name field contains the name of the module.
//
// The MR_ml_string_table field contains the module's string table, which
// contains strings referred to by other layout structures in the module
// (initially only the tables containing variables names, referred to from
// label layout structures). The MR_ml_string_table_size field gives the size
// of the table in bytes.
//
// The MR_ml_procs field points to an array containing pointers to the proc
// layout structures of all the procedures in the module; the MR_ml_proc_count
// field gives the number of entries in the array.
//
// The MR_ml_module_file_layout field points to an array of N file layout
// pointers if the module has labels corresponding to contexts that refer
// to the names of N files. For each file, the table gives its name, the
// number of labels in that file in this module, and for each such label,
// it gives its line number and a pointer to its label layout struct.
// The corresponding elements of the label_lineno and label_layout arrays
// refer to the same label. (The reason why they are not stored together
// is space efficiency; adding a 16 bit field to a label layout structure would
// require padding.) The labels are sorted on line number.
//
// The MR_ml_trace_level field gives the trace level that the module was
// compiled with. If the MR_TraceLevel enum is modified, then the
// corresponding function in compiler/trace_params.m must also be updated.
//
// The MR_ml_suppressed_events events field encodes the set of event types
// (ports) that were suppressed when generating code for this module. The bit
// given by the expression (1 << MR_PORT_<PORTTYPE>) will be set in this
// integer iff trace port MR_PORT_<PORTTYPE> is suppressed.
//
// The MR_ml_label_exec_count field points to an array of integers, with each
// integer holding the number of times execution has reached a given label.
// Each label's layout structure records the index of that label in this array.
// The most direct way to go the other way, to find out which label owns a
// particular slot in this array, is to search the label arrays in the file
// layout structures, and test their MR_sll_label_num_in_module fields.
// (If we needed faster access, we could add another array with elements
// corresponding to MR_ml_label_exec_count's pointing to the labels' layout
// structures.)
//
// The MR_ml_num_label_exec_counts field contains the number of elements
// in the MR_ml_label_exec_count array.

typedef struct MR_ModuleFileLayout_Struct {
    MR_ConstString                  MR_mfl_filename;
    MR_Integer                      MR_mfl_label_count;
    // The following fields point to arrays of size MR_mfl_label_count.
    const MR_int_least16_t          *MR_mfl_label_lineno;
    const MR_LabelLayout            **MR_mfl_label_layout;
} MR_ModuleFileLayout;

// The version of the data structures in this file -- useful for bootstrapping.
// If you write runtime code that checks this version number and can at least
// handle the previous version of the data structure, it makes it easier to
// bootstrap changes to these data structures.
//
// This number should be kept in sync with layout_version_number in
// compiler/layout_out.m.

#define MR_LAYOUT_VERSION                   MR_LAYOUT_VERSION__OISU
#define MR_LAYOUT_VERSION__USER_DEFINED     1
#define MR_LAYOUT_VERSION__EVENTSETNAME     2
#define MR_LAYOUT_VERSION__SYNTH_ATTR       3
#define MR_LAYOUT_VERSION__COMMON           4
#define MR_LAYOUT_VERSION__OISU             5

struct MR_ModuleLayout_Struct {
    // The fields that are of interest to both deep profiling and debugging.
    MR_uint_least8_t                MR_ml_version_number;
    MR_ConstString                  MR_ml_name;
    MR_Integer                      MR_ml_string_table_size;
    const char                      *MR_ml_string_table;

    // The fields that are of interest only to deep profiling.
    MR_Integer                      MR_ml_num_oisu_types;
    const MR_uint_least8_t          *MR_ml_oisu_bytes;
    MR_Integer                      MR_ml_num_table_types;
    const MR_uint_least8_t          *MR_ml_type_table_bytes;

    // The fields that are of interest only to debugging.
    MR_Integer                      MR_ml_proc_count;
    const MR_ProcLayout             **MR_ml_procs;
    MR_Integer                      MR_ml_filename_count;
    const MR_ModuleFileLayout       **MR_ml_module_file_layout;
    MR_TraceLevel                   MR_ml_trace_level;
    MR_int_least32_t                MR_ml_suppressed_events;
    MR_int_least32_t                MR_ml_num_label_exec_counts;
    MR_Unsigned                     *MR_ml_label_exec_count;
    const char                      *MR_ml_user_event_set_name;
    const char                      *MR_ml_user_event_set_desc;
    MR_int_least16_t                MR_ml_user_event_max_num_attr;
    MR_int_least16_t                MR_ml_num_user_event_specs;
    MR_UserEventSpec                *MR_ml_user_event_specs;
};

////////////////////////////////////////////////////////////////////////////
// Definitions for MR_ClosureId.
//
// Each closure contains an MR_ClosureId structure. The proc_id field
// identifies the procedure called by the closure. The other fields identify
// the context where the closure was created.
//
// The compiler generates closure id structures as either MR_UserClosureId
// or MR_UCIClosureId structures in order to avoid initializing the
// MR_ProcId union through an inappropriate member.

struct MR_ClosureId_Struct {
    MR_ProcId                       MR_closure_proc_id;
    MR_ConstString                  MR_closure_module_name;
    MR_ConstString                  MR_closure_file_name;
    MR_Integer                      MR_closure_line_number;
    MR_ConstString                  MR_closure_goal_path;
};

struct MR_UserClosureId_Struct {
    MR_UserProcId                   MR_user_closure_proc_id;
    MR_ConstString                  MR_user_closure_module_name;
    MR_ConstString                  MR_user_closure_file_name;
    MR_Integer                      MR_user_closure_line_number;
    MR_ConstString                  MR_user_closure_goal_path;
};

struct MR_UCIClosureId_Struct {
    MR_UCIProcId                    MR_uci_closure_proc_id;
    MR_ConstString                  MR_uci_closure_module_name;
    MR_ConstString                  MR_uci_closure_file_name;
    MR_Integer                      MR_uci_closure_line_number;
    MR_ConstString                  MR_uci_closure_goal_path;
};

#endif // not MERCURY_STACK_LAYOUT_H
