Files
mercury/runtime/mercury_deconstruct.c
Zoltan Somogyi 24b98fdafe Pack sub-word-sized ints and dummies in terms.
Previously, the only situation in which we could pack two or more arguments
of a term into a single word was when all those arguments are enums. This diff
changes that, so that the arguments can also be sub-word-sized integers
(signed or unsigned), or values of dummy types (which occupy zero bits).

This diff also records, for each argument of a function symbol, not just
whether, and if yes, how it is packed into a word, but also at *what offset*
that word is in the term's heap cell. It is more economical to compute this
once, when the representation of the type is being decided, than to compute
it over and over again when terms with that function symbol are being
constructed or deconstructed. However, for a transition period, we compute
these offsets at *both* times, to check the consistency of the new algorithm
for computing offsets that is run at "decide representation time" with
the old algorithms run at "generate code for a unification time".

compiler/du_type_layout.m:
    Make the changes described above: pack sub-word-sized integers and
    dummy values into argument words, if possible, and if the relevant
    new option allows it. These options are temporary. If we find no problems
    with the new packing algorithm in a few weeks, we should be able to
    delete them.

    Allow 64 bit ints and uints to be stored in unboxed in two words
    on 32 bit platforms, if the relevant new option allows it. Support
    for this is not yet complete, but it makes sense to implement the
    RTTI changes for both this change and one described in the above
    paragraph together.

    For each packed argument, record not just its width, its shift and
    the mask, but also the number of bits the argument takes. Previously,
    we computed this on demand from the mask, but there is no real need
    for that when simply storing this info is so cheap.

    For all arguments, packed or not, record its offset, relative to both
    the start of the arguments, and the start of the memory cell. (The two
    are different if the arguments are preceded by either a remote secondary
    tag, the typeinfos and/or typeclass_infos describing some existentially
    typed arguments, or both.) The reason for this is given at the top.

    Centralize the decision of the parameters of packing in one predicate.

    If the option --inform-suboptimal-packing is given, print an informational
    message whenever the code deciding type representations finds that
    reordering the arguments of a function symbol would allow it to pack
    the arguments of that function symbol into less space.

compiler/options.m:
    Add the option --allow-packing-ints which controls whether
    du_type_layout.m will attempt to pack {int,uint}{8,16,32} arguments
    alongside enum arguments.

    Add the option --allow-packing-dummies which controls whether
    du_type_layout.m will optimize away (in other words, represent in 0 bits)
    arguments of dummy types.

    Add the option --allow-double-word-ints which controls whether
    du_type_layout.m will store arguments of the types int64 and uint64
    unboxed in two words on 32 bit platforms, the way it currently stores
    double precision floats.

    All three those options are off by default, which preserves binary
    compatibility with existing code. However, the first two are ready
    to be switched on (the third is not).

    All three options are intended to be present in the compiler
    only until these changes are tested. Once we deem them sufficiently
    tested, I will modify the compiler to always do the packing they control,
    at which point we can delete these options. This is why they are not
    documented.

    Add the option --inform-suboptimal-packing, whose meaning is described
    above.

doc/user_guide.texi:
    Document --inform-suboptimal-packing.

compiler/prog_data.m:
    For each argument of a function symbol in a type definition, use
    a new type called arg_pos_width to record the extra information
    mentioned above in (offsets for all arguments, and number of bits
    for packed arguments).

    For each function symbol that has some existential type constraints,
    record the extra information mentioned for parse_type_defn.m below.

compiler/hlds_data.m:
    Include the position, as well as the width, in the representation
    of the arguments of function symbols.

    Previously, we used the integer 0 as a tag for dummies. Add a tag to
    represent dummy values, since this gives more information to any code
    that sees that tag.

compiler/ml_unify_gen.m:
compiler/unify_gen.m:
    Handle the packing of dummy values, and of sub-word-sized ints and uints.

    Compare the cell offset of each argument computed using existing
    algorithms here with the cell offset recorded in the argument's
    representation, and abort if they are different.

    In some cases, restructure code a bit to make it possible.
    For example, for tuples and closures, this means that instead of
    simply recording that each tuple argument or closure element
    is a full word, we must record its correct offset as well.

    Handle the new dummy_tag.

    Add prelim (not yet finished) support for double-word int64s/uint64s
    on 32 bit platforms.

    When packing the values of two or more variables (or constants) into a
    single word in a memory cell, optimize away operations that are no-ops,
    such as shifting anything by zero bits, shifting the constant zero
    by any number of bits, and ORing anything with zero. This makes the
    generated code easier to read. It is probably also faster for us
    to do it here than to write out a bigger expression, have the C compiler
    read in the bigger expression, and then later make the same optimization.

    In ml_unify_gen.m, avoid the unnecessary use of a list of the argument
    variables' types separate from the list of the argument variables
    themselves; just look up the type of each argument variable when it is
    processed.

compiler/add_special_pred.m:
    When creating special (unify and compare) predicates for tuples,
    include the offsets in the representation of their arguments.

    Delete an unused predicate.

compiler/llds.m:
    Add a new way to create an rval: a cast. We use it to implement
    the extraction of signed sub-word-sized integers from packed argument
    words in terms. Masking the right N bits out of the packed word
    leaves the other 32-N or 64-N bits as zeroes; a cast to int8_t,
    int16_t or int32_t will copy the sign bit to these bits.
    Likewise, when we pack signed int{8,16,32} values into words,
    we cast them to their unsigned versions to throw away any sign-extension
    bits in their original word-sized representations.

    No similar change is needed for the MLDS, since that already had
    a mechanism for casts.

compiler/mlds.m:
    Note a potential simplification in the MLDS.

compiler/builtin_lib_types.m:
    Add functions to return the Mercury representation of the int64
    and uint64 types.

compiler/foreign.m:
    Export a specialized version of an existing predicate, to allow
    ml_unify_gen.m to avoid the costs of the more general version.

compiler/hlds_out_module.m:
    Always print the representations of all arguments, since the
    inclusion of position information in those representation means that
    the representations of even all-full-word-argument terms are of potential
    interest when debugging term representations.

compiler/lco.m:
    Do not try to apply LCO to arguments of dummy types. (We could optimize
    them differently, by filling them in before they are "computed", but
    that is a separate optimization, which is of *very* low priority.)

compiler/liveness.m:
    Do not include variables of dummy types in resume points.

    The reason for this is that the code that establishes a resume point
    returns, for each such variable, a list of *lvals* where that variable
    can be found. The new code in unify_gen.m will optimize away assignments
    to values of dummy types, so there is *no* lval where they can be found.
    We could allocate one, but doing so would be a pessimization. Instead,
    we simply don't save and restore such values. When their value (which is
    always 0) is needed, we can create them out of thin air.

compiler/ml_global_data.m:
    Include the target language in the ml_global_data structure, to prevent
    some of its users having to look it up in the module_info.

    Add notes about the specializing the implementation of arrays of
    int64s/uint64s on 32 bit platforms.

compiler/check_typeclass.m:
compiler/ml_type_gen.m:
    Add sanity checks of the new precomputed fields of exist_constraints.

    Conform to the changes above.

compiler/mlds_to_c.m:
    Add prelim (not yet finished) support for double-word int64s/uint64s
    on 32 bit platforms.

    Add notes about possible optimizations.

compiler/parse_type_defn.m:
    When a function symbol in a type definition contains existential
    arguments, precompute and store the set of constrained and unconstrained
    type variables. The code in du_type_layout.m needs this information
    to compute the number of slots occupied by typeinfos and typeclass_infos
    in memory cells for this function symbol, and several other places
    in the compiler do too. It is easier and faster to compute this
    information just once, and this is the earliest time what that can be done.

compiler/type_ctor_info.m:
    Use the prerecorded information about existential types to simplify
    the code here

compiler/polymorphism.m:
    Add an XXX about possibly using the extra info we now record in
    exist_constraints to simplify the job of polymorphism.m.

compiler/pragma_c_gen.m:
compiler/var_locn.m:
    Create the values of dummy variables from scratch, if needed.

compiler/rtti.m:
    Replace a bool with a bespoke type.

compiler/rtti_out.m:
compiler/rtti_to_mlds.m:
    When generating RTTI information for the LLDS and MLDS backends
    respectively, record new kinds of arguments as needing special
    treatment. These are int64s and uint64s stored unboxed in two words
    on 32 bit platforms, {int,uint}{8,16,32} values packed into words,
    and dummy arguments. Each of these has a special code: its own negative
    negative value in the num_bits field of the argument.

    Generate slightly better formatted output.

compiler/type_util.m:
    Delete a predicate that isn't needed anymore.

compiler/opt_util.m:
    Delete a function that hasn't been needed for a while.

    Conform to the changes above.

compiler/arg_pack.m:
compiler/bytecode_gen.m:
compiler/call_gen.m:
compiler/code_util.m:
compiler/ctgc.selector.m:
compiler/dupelim.m:
compiler/dupproc.m:
compiler/equiv_type.m:
compiler/equiv_type_hlds.m:
compiler/erl_code_gen.m:
compiler/erl_rtti.m:
compiler/export.m:
compiler/exprn_aux.m:
compiler/global_data.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/llds_out_data.m:
compiler/middle_rec.m:
compiler/ml_closure_gen.m:
compiler/ml_switch_gen.m:
compiler/ml_top_gen.m:
compiler/module_qual.qualify_items.m:
compiler/opt_debug.m:
compiler/parse_tree_out.m:
compiler/peephole.m:
compiler/recompilation.usage.m:
compiler/resolve_unify_functor.m:
compiler/stack_layout.m:
compiler/structure_reuse.direct.choose_reuse.m:
compiler/switch_util.m:
compiler/typecheck.m:
compiler/unify_proc.m:
compiler/unused_imports.m:
compiler/xml_documentation.m:
    Conform to the changes above.

compiler/llds_out_util.m:
    Add a comment.

compiler/ml_code_util.m:
    Factor out some common code.

runtime/mercury_type_info.h:
    Allocate special values of the MR_arg_bits field of the MR_DuArgLocn type
    to designate arguments as two word int64/uint64s, as sub-word-sized
    arguments of types {int,uint}{8,16,32}, or as arguments of dummy types.
    (We already had a special value for two word float arguments.)

    Document the list of places that know about this code, so that they
    can be updated if and when it changes.

library/construct.m:
    Handle the construction of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

    Factor out the code common to the sectag-present and sectag-absent cases,
    to make it possible to do the above in just *one* place.

library/store.m:
    Add an XXX to a place that I don't think handles two word arguments
    correctly. (I think this is an old bug.)

runtime/mercury_deconstruct.c:
    Handle the deconstruction of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

runtime/mercury_deep_copy_body.h:
    Handle the copying of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

    Give a macro a more descriptive name.

runtime/mercury_type_info.c:
    Handle taking the size of terms with two-word int64/uint64 arguments,
    with packed {int,uint}{8,16,32} arguments, and with dummy arguments.

runtime/mercury.h:
    Put related definitions next to each other.

runtime/mercury_deconstruct.h:
runtime/mercury_ml_expand_body.h:
    Fix indentation.

tests/hard_coded/construct_test.{m,exp}:
    Add to this test case a test of the construction, via the library's
    construct.m module, of terms containing packed sub-word-sized integers,
    and packed dummies.

tests/hard_coded/deconstruct_arg.{m,exp}:
    Convert the source code of this test case to state variable notation,
    and update the line number references (in the names of predicates created
    from lambda expressions) accordingly.

tests/hard_coded/uint64_ground_term.{m,exp}:
    A new test case to check that uint64 values too large to be int64 values
    can be stored in static structures.

tests/hard_coded/Mmakefile:
    Enable the new test case.
2018-05-05 13:22:19 +02:00

438 lines
14 KiB
C

// vim: ts=4 sw=4 expandtab ft=c
// Copyright (C) 2002-2007, 2011 The University of Melbourne.
// This file may only be copied under the terms of the GNU Library General
// Public License - see the file COPYING.LIB in the Mercury distribution.
// mercury_deconstruct.c
//
// This file provides utility functions for deconstructing terms, for use by
// the standard library.
#include "mercury_imp.h"
#include "mercury_deconstruct.h"
#include "mercury_deconstruct_macros.h"
#include "mercury_type_desc.h"
#include "mercury_minimal_model.h"
// We reserve a buffer to hold the names we dynamically generate
// for "functors" of foreign types. This macro gives its size.
#define MR_FOREIGN_NAME_BUF_SIZE 256
static MR_ConstString MR_expand_type_name(MR_TypeCtorInfo tci, MR_bool);
#define EXPAND_FUNCTION_NAME MR_expand_functor_args
#define EXPAND_TYPE_NAME MR_ExpandFunctorArgsInfo
#define EXPAND_FUNCTOR_FIELD functor
#define EXPAND_ARGS_FIELD args
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_FUNCTOR_FIELD
#undef EXPAND_ARGS_FIELD
#define EXPAND_FUNCTION_NAME MR_expand_functor_args_limit
#define EXPAND_TYPE_NAME MR_ExpandFunctorArgsLimitInfo
#define EXPAND_FUNCTOR_FIELD functor
#define EXPAND_ARGS_FIELD args
#define EXPAND_APPLY_LIMIT
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_FUNCTOR_FIELD
#undef EXPAND_ARGS_FIELD
#undef EXPAND_APPLY_LIMIT
#define EXPAND_FUNCTION_NAME MR_expand_functor_only
#define EXPAND_TYPE_NAME MR_ExpandFunctorOnlyInfo
#define EXPAND_FUNCTOR_FIELD functor_only
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_FUNCTOR_FIELD
#define EXPAND_FUNCTION_NAME MR_expand_args_only
#define EXPAND_TYPE_NAME MR_ExpandArgsOnlyInfo
#define EXPAND_ARGS_FIELD args_only
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_ARGS_FIELD
#define EXPAND_FUNCTION_NAME MR_expand_chosen_arg_only
#define EXPAND_TYPE_NAME MR_ExpandChosenArgOnlyInfo
#define EXPAND_CHOSEN_ARG
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_CHOSEN_ARG
#define EXPAND_FUNCTION_NAME MR_expand_named_arg_only
#define EXPAND_TYPE_NAME MR_ExpandChosenArgOnlyInfo
#define EXPAND_NAMED_ARG
#include "mercury_ml_expand_body.h"
#undef EXPAND_FUNCTION_NAME
#undef EXPAND_TYPE_NAME
#undef EXPAND_NAMED_ARG
// N.B. any modifications to the signature of this function will require
// changes not only to library/deconstruct.m, but also to library/store.m
// and extras/trailed_update/tr_store.m.
MR_bool
MR_arg(MR_TypeInfo type_info, MR_Word *term_ptr, int arg_index,
MR_TypeInfo *arg_type_info_ptr, MR_Word **arg_ptr,
const MR_DuArgLocn **arg_locn_ptr, MR_noncanon_handling noncanon)
{
MR_ExpandChosenArgOnlyInfo expand_info;
MR_expand_chosen_arg_only(type_info, term_ptr, noncanon, arg_index,
&expand_info);
// Check range.
if (expand_info.chosen_index_exists) {
*arg_type_info_ptr = expand_info.chosen_type_info;
*arg_ptr = expand_info.chosen_value_ptr;
*arg_locn_ptr = expand_info.chosen_arg_locn;
return MR_TRUE;
}
return MR_FALSE;
}
MR_bool
MR_named_arg(MR_TypeInfo type_info, MR_Word *term_ptr, MR_ConstString arg_name,
MR_TypeInfo *arg_type_info_ptr, MR_Word **arg_ptr,
const MR_DuArgLocn **arg_locn_ptr, MR_noncanon_handling noncanon)
{
MR_ExpandChosenArgOnlyInfo expand_info;
MR_expand_named_arg_only(type_info, term_ptr, noncanon, arg_name,
&expand_info);
// Check range.
if (expand_info.chosen_index_exists) {
*arg_type_info_ptr = expand_info.chosen_type_info;
*arg_ptr = expand_info.chosen_value_ptr;
*arg_locn_ptr = expand_info.chosen_arg_locn;
return MR_TRUE;
}
return MR_FALSE;
}
MR_bool
MR_named_arg_num(MR_TypeInfo type_info, MR_Word *term_ptr,
const char *arg_name, int *arg_num_ptr)
{
MR_TypeCtorInfo type_ctor_info;
MR_DuTypeLayout du_type_layout;
const MR_DuPtagLayout *ptag_layout;
const MR_DuFunctorDesc *functor_desc;
const MR_NotagFunctorDesc *notag_functor_desc;
MR_Word data;
int ptag;
MR_Word sectag;
MR_TypeInfo eqv_type_info;
int i;
type_ctor_info = MR_TYPEINFO_GET_TYPE_CTOR_INFO(type_info);
if (! MR_type_ctor_has_valid_rep(type_ctor_info)) {
MR_fatal_error("MR_named_arg_num: term of unknown representation");
}
switch (MR_type_ctor_rep(type_ctor_info)) {
case MR_TYPECTOR_REP_DU_USEREQ:
case MR_TYPECTOR_REP_DU:
data = *term_ptr;
du_type_layout = MR_type_ctor_layout(type_ctor_info).MR_layout_du;
ptag = MR_tag(data);
ptag_layout = &du_type_layout[ptag];
switch (ptag_layout->MR_sectag_locn) {
case MR_SECTAG_NONE:
case MR_SECTAG_NONE_DIRECT_ARG:
functor_desc = ptag_layout->MR_sectag_alternatives[0];
break;
case MR_SECTAG_LOCAL:
sectag = MR_unmkbody(data);
functor_desc = ptag_layout->MR_sectag_alternatives[sectag];
break;
case MR_SECTAG_REMOTE:
sectag = MR_field(ptag, data, 0);
functor_desc = ptag_layout->MR_sectag_alternatives[sectag];
break;
case MR_SECTAG_VARIABLE:
MR_fatal_error("MR_named_arg_num(): unexpected variable");
default:
MR_fatal_error("MR_named_arg_num(): invalid sectag_locn");
}
if (functor_desc->MR_du_functor_arg_names == NULL) {
return MR_FALSE;
}
for (i = 0; i < functor_desc->MR_du_functor_orig_arity; i++) {
if (functor_desc->MR_du_functor_arg_names[i] != NULL
&& MR_streq(arg_name,
functor_desc->MR_du_functor_arg_names[i]))
{
*arg_num_ptr = i;
return MR_TRUE;
}
}
return MR_FALSE;
case MR_TYPECTOR_REP_EQUIV:
eqv_type_info = MR_create_type_info(
MR_TYPEINFO_GET_FIXED_ARITY_ARG_VECTOR(type_info),
MR_type_ctor_layout(type_ctor_info).MR_layout_equiv);
return MR_named_arg_num(eqv_type_info, term_ptr, arg_name,
arg_num_ptr);
case MR_TYPECTOR_REP_EQUIV_GROUND:
eqv_type_info = MR_pseudo_type_info_is_ground(
MR_type_ctor_layout(type_ctor_info).MR_layout_equiv);
return MR_named_arg_num(eqv_type_info, term_ptr, arg_name,
arg_num_ptr);
case MR_TYPECTOR_REP_NOTAG:
case MR_TYPECTOR_REP_NOTAG_USEREQ:
case MR_TYPECTOR_REP_NOTAG_GROUND:
case MR_TYPECTOR_REP_NOTAG_GROUND_USEREQ:
notag_functor_desc = MR_type_ctor_functors(type_ctor_info).
MR_functors_notag;
if (notag_functor_desc->MR_notag_functor_arg_name != NULL
&& MR_streq(arg_name,
notag_functor_desc->MR_notag_functor_arg_name))
{
*arg_num_ptr = 0;
return MR_TRUE;
}
return MR_FALSE;
case MR_TYPECTOR_REP_ENUM:
case MR_TYPECTOR_REP_ENUM_USEREQ:
case MR_TYPECTOR_REP_DUMMY:
case MR_TYPECTOR_REP_INT:
case MR_TYPECTOR_REP_UINT:
case MR_TYPECTOR_REP_INT8:
case MR_TYPECTOR_REP_UINT8:
case MR_TYPECTOR_REP_INT16:
case MR_TYPECTOR_REP_UINT16:
case MR_TYPECTOR_REP_INT32:
case MR_TYPECTOR_REP_UINT32:
case MR_TYPECTOR_REP_INT64:
case MR_TYPECTOR_REP_UINT64:
case MR_TYPECTOR_REP_FLOAT:
case MR_TYPECTOR_REP_CHAR:
case MR_TYPECTOR_REP_STRING:
case MR_TYPECTOR_REP_BITMAP:
case MR_TYPECTOR_REP_FUNC:
case MR_TYPECTOR_REP_PRED:
case MR_TYPECTOR_REP_SUBGOAL:
case MR_TYPECTOR_REP_VOID:
case MR_TYPECTOR_REP_C_POINTER:
case MR_TYPECTOR_REP_STABLE_C_POINTER:
case MR_TYPECTOR_REP_TYPEINFO:
case MR_TYPECTOR_REP_TYPECTORINFO:
case MR_TYPECTOR_REP_TYPEDESC:
case MR_TYPECTOR_REP_TYPECTORDESC:
case MR_TYPECTOR_REP_PSEUDOTYPEDESC:
case MR_TYPECTOR_REP_TYPECLASSINFO:
case MR_TYPECTOR_REP_BASETYPECLASSINFO:
case MR_TYPECTOR_REP_SUCCIP:
case MR_TYPECTOR_REP_HP:
case MR_TYPECTOR_REP_CURFR:
case MR_TYPECTOR_REP_MAXFR:
case MR_TYPECTOR_REP_REDOFR:
case MR_TYPECTOR_REP_REDOIP:
case MR_TYPECTOR_REP_TICKET:
case MR_TYPECTOR_REP_TRAIL_PTR:
case MR_TYPECTOR_REP_REFERENCE:
case MR_TYPECTOR_REP_TUPLE:
case MR_TYPECTOR_REP_ARRAY:
case MR_TYPECTOR_REP_FOREIGN:
case MR_TYPECTOR_REP_STABLE_FOREIGN:
case MR_TYPECTOR_REP_FOREIGN_ENUM:
case MR_TYPECTOR_REP_FOREIGN_ENUM_USEREQ:
case MR_TYPECTOR_REP_UNUSED1:
case MR_TYPECTOR_REP_UNUSED2:
case MR_TYPECTOR_REP_UNKNOWN:
return MR_FALSE;
}
MR_fatal_error("MR_named_arg_num: unexpected fallthrough");
}
static MR_ConstString
MR_expand_type_name(MR_TypeCtorInfo tci, MR_bool wrap)
{
MR_String str;
int len;
len = 0;
len += strlen(tci->MR_type_ctor_module_name);
len += 1; // '.'
len += strlen(tci->MR_type_ctor_name);
len += 1; // '/'
len += 4; // arity; we do not support arities above 1024
if (wrap) {
len += 4; // <<>>
}
len += 1; // NULL
if (tci->MR_type_ctor_arity > 9999) {
MR_fatal_error("MR_expand_type_name: arity > 9999");
}
MR_restore_transient_hp();
MR_allocate_aligned_string_msg(str, len, MR_ALLOC_SITE_STRING);
MR_save_transient_hp();
sprintf(str, wrap? "<<%s.%s/%d>>" : "%s.%s/%d",
tci->MR_type_ctor_module_name,
tci->MR_type_ctor_name,
(int) tci->MR_type_ctor_arity);
return (MR_ConstString) str;
}
MR_Word
MR_arg_value_uncommon(MR_Word *arg_ptr, const MR_DuArgLocn *arg_locn)
{
MR_Word val;
// The meanings of the various special values of MR_arg_bits
// are documented next to the definition of the MR_DuArgLocn type
// in mercury_type_info.h.
switch (arg_locn->MR_arg_bits) {
case -1:
// MR_arg_bits == -1 means the argument is a double-precision
// floating point value occupying two words.
#ifdef MR_BOXED_FLOAT
{
MR_Float flt;
flt = MR_float_from_dword(arg_ptr[0], arg_ptr[1]);
#ifdef MR_HIGHLEVEL_CODE
return (MR_Word) MR_box_float(flt);
#else
return MR_float_to_word(flt);
#endif
}
#else
MR_fatal_error("double-word floats should not exist in this grade");
#endif
case -2:
// MR_arg_bits == -2 means the argument is an int64 value
// occupying two words.
#if defined(MR_BOXED_INT64S)
{
int64_t i64;
i64 = MR_int64_from_dword(arg_ptr[0], arg_ptr[1]);
#ifdef MR_HIGHLEVEL_CODE
return (MR_Word) MR_box_int64(i64);
#else
return MR_int64_to_word(i64);
#endif
}
#else
MR_fatal_error("double-word int64s should not exist in this grade");
#endif
case -3:
// MR_arg_bits == -3 means the argument is a uint64 value
// occupying two words.
#if defined(MR_BOXED_INT64S)
{
uint64_t ui64;
ui64 = MR_uint64_from_dword(arg_ptr[0], arg_ptr[1]);
#ifdef MR_HIGHLEVEL_CODE
return (MR_Word) MR_box_uint64(ui64);
#else
return MR_uint64_to_word(ui64);
#endif
}
#else
MR_fatal_error("double-word uint64s should not exist in this grade");
#endif
case -4:
// MR_arg_bits == -4 means the argument is an int8 value
// occupying part of one word.
val = *arg_ptr;
val = (val >> arg_locn->MR_arg_shift) & ((MR_Word) 0xff);
val = (MR_Word) (int8_t) val;
return val;
case -5:
// MR_arg_bits == -5 means the argument is a uint8 value
// occupying part of one word.
val = *arg_ptr;
val = (val >> arg_locn->MR_arg_shift) & ((MR_Word) 0xff);
val = (MR_Word) (uint8_t) val;
return val;
case -6:
// MR_arg_bits == -6 means the argument is an int16 value
// occupying part of one word.
val = *arg_ptr;
val = (val >> arg_locn->MR_arg_shift) & ((MR_Word) 0xffff);
val = (MR_Word) (int16_t) val;
return val;
case -7:
// MR_arg_bits == -7 means the argument is a uint16 value
// occupying part of one word.
val = *arg_ptr;
val = (val >> arg_locn->MR_arg_shift) & ((MR_Word) 0xffff);
val = (MR_Word) (uint16_t) val;
return val;
case -8:
// MR_arg_bits == -8 means the argument is an int32 value
// occupying part of one word.
val = *arg_ptr;
val = (val >> arg_locn->MR_arg_shift) & ((MR_Word) 0xffffffff);
val = (MR_Word) (int32_t) val;
return val;
case -9:
// MR_arg_bits == -9 means the argument is a uint32 value
// occupying part of one word.
val = *arg_ptr;
val = (val >> arg_locn->MR_arg_shift) & ((MR_Word) 0xffffffff);
val = (MR_Word) (uint32_t) val;
return val;
case -10:
// MR_arg_bits == -10 means the argument is of a dummy type.
return 0;
default:
if (arg_locn->MR_arg_bits > 0) {
// The argument is a packed enumeration value.
val = *arg_ptr;
val = (val >> arg_locn->MR_arg_shift)
& ((MR_Word) (1 << arg_locn->MR_arg_bits) - 1);
return val;
} else {
// If MR_arg_bits is exactly zero, this function
// should not have been called at all (since that is
// the *common* case).
MR_fatal_error("unexpected value of MR_arg_bits");
}
}
}