mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-19 15:54:18 +00:00
Estimated hours taken: weeks Branches: main Implement a mechanism to generate the information required to determine the algorithmic complexity of selected procedures. The basis of the mechanism is a program transformation that wraps up the body of each selected procedure in code that detects top-level (non-recursive) calls, and for each top-level call, records the sizes of the input arguments and information about the cost of the call. For now, the cost information consists only of the number of cells and words allocated during the call, but there is provision for later adding information from a real-time clock. compiler/complexity.m: A new module containing the new transformation. compiler/transform_hlds.m: Add complexity.m to the list of submodules. compiler/mercury_compile.m: Invoke the new module. compiler/notes/compiler_design.html: Mention the new module. compiler/options.m: Add an option, --experimental-complexity. Its argument is a filename that specifies the list of procedures to transform. Add an option, --no-allow-inlining, to disallow all inlining. This is simpler to use than specifying several options to turn off each potential reason to inline procedures. doc/user_guide.texi: Document the new options. The documentation present now is only a shell; it will be expanded later. compiler/table_gen.m: compiler/goal_util.m: Move the predicate for creating renamings from table_gen.m to goal_util.m, since complexity.m also needs it now. In the process, make it more general by allowing outputs to have more complex modes than simply `out'. compiler/goal_util.m: Fix a bug exposed by the new transformation: when renaming goals (e.g. for quantification), rename the variables holding information about term sizes. compiler/handle_options.m: Disable inlining if experimental complexity analysis is enabled. compiler/compile_target_code.m: Pass the --experimental-complexity option on to the linker. library/term_size_prof_builtin.m: Add the Mercury predicates that serve as interfaces to the primitives needed by the experimental complexity transformation. runtime/mercury_term_size.[ch]: Add the implementations of the primitives needed by the experimental complexity transformation. runtime/mercury_wrapper.[ch]: Add global variables holding counters of the numbers of words and cells allocated so far. runtime/mercury_heap.h: Update these global variables when allocating memory. runtime/mercury_complexity.h: New file that contains the definition of the data structures holding the data collected by the experimental complexity transformation. This is separate from mercury_term_size.h, because it needs to be #included in mercury_init.h, the header file of the mkinit-generated <program>_init.c files. runtime/mercury_init.h: runtime/mercury_imp.h: #include mercury_complexity.h. util/mkinit.c: Define and initialize the data structures holding complexity information when given the -X option (mkinit doesn't have long options). Fix some deviations from our coding style. scripts/parse_ml_options.sh-subr.in: Accept the --experiment-complexity option. scripts/c2init.in: Pass the --experiment-complexity option on to mkinit.c. tools/bootcheck: Preserve the files containing the results of complexity analysis, if they exist. tools/makebatch: Allow the specification of EXTRA_MLFLAGS in the generated Mmake.stage.params files.
579 lines
19 KiB
C
579 lines
19 KiB
C
/*
|
|
** Copyright (C) 1995-2005 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_heap.h - definitions for manipulating the Mercury heap */
|
|
|
|
#ifndef MERCURY_HEAP_H
|
|
#define MERCURY_HEAP_H
|
|
|
|
#include "mercury_conf.h" /* for MR_CONSERVATIVE_GC */
|
|
#include "mercury_conf_param.h" /* for MR_RECORD_TERM_SIZES */
|
|
#include "mercury_types.h" /* for `MR_Word' */
|
|
#include "mercury_context.h" /* for min_heap_reclamation_point() */
|
|
#include "mercury_heap_profile.h" /* for MR_record_allocation() */
|
|
#include "mercury_deep_profiling.h" /* for MR_current_call_site_dynamic */
|
|
#include "mercury_std.h" /* for MR_EXTERN_INLINE */
|
|
#include "mercury_reg_workarounds.h" /* for MR_memcpy */
|
|
#include "mercury_debug.h" /* for MR_debugtagoffsetincrhp* */
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
#include "mercury.h" /* for MR_new_object() */
|
|
#endif
|
|
|
|
#ifdef MR_CONSERVATIVE_GC
|
|
#ifdef MR_MPS_GC
|
|
#include "mercury_mps.h"
|
|
#endif
|
|
#ifdef MR_BOEHM_GC
|
|
#define GC_I_HIDE_POINTERS
|
|
#include "gc.h"
|
|
#endif
|
|
#endif
|
|
|
|
/*
|
|
** Unfortunately, the following macros cannot expand to statements;
|
|
** they must be usable inside expressions. The ultimate reason for this is
|
|
** MR_float_to_word, which is used not just as an operand in expressions,
|
|
** but also as an initializer in static cells generated by the compiler.
|
|
*/
|
|
|
|
#ifdef MR_DEBUG_HEAP_ALLOC
|
|
|
|
#define MR_tag_offset_sanity_check(offset, count) \
|
|
( ((offset) >= (count)) \
|
|
? MR_fatal_error("MR_tag_offset_sanity_check failed") \
|
|
: ((void) 0) \
|
|
)
|
|
|
|
#else /* ! MR_DEBUG_HEAP_ALLOC */
|
|
|
|
#define MR_tag_offset_sanity_check(offset, count) ((void) 0)
|
|
|
|
#endif /* MR_DEBUG_HEAP_ALLOC */
|
|
|
|
#ifdef MR_CONSERVATIVE_GC
|
|
|
|
#define MR_tag_offset_incr_hp_base(dest, tag, offset, count, \
|
|
alloc, is_atomic) \
|
|
( \
|
|
MR_tag_offset_sanity_check((offset), (count)), \
|
|
(dest) = (MR_Word) MR_mkword((tag), (MR_Word) \
|
|
(((MR_Word *) alloc((count) * sizeof(MR_Word))) \
|
|
+ (offset))), \
|
|
MR_debug_tag_offset_incr_hp_base((dest), (tag), (offset), \
|
|
(count), (is_atomic)), \
|
|
/* return */ (dest) \
|
|
)
|
|
|
|
#define MR_tag_offset_incr_hp_n(dest, tag, offset, count) \
|
|
MR_tag_offset_incr_hp_base(dest, tag, offset, count, \
|
|
GC_MALLOC, 0)
|
|
#define MR_tag_offset_incr_hp_atomic(dest, tag, offset, count) \
|
|
MR_tag_offset_incr_hp_base(dest, tag, offset, count, \
|
|
GC_MALLOC_ATOMIC, 1)
|
|
|
|
#ifdef MR_INLINE_ALLOC
|
|
|
|
/*
|
|
** The following stuff uses the macros in the `gc_inl.h' header file in the
|
|
** Boehm garbage collector. They improve performance a little for
|
|
** highly allocation-intensive programs (e.g. the `nrev' benchmark).
|
|
** You'll probably need to fool around with the `-I' options to get this
|
|
** to work. Also, you must make sure that you compile with the same
|
|
** setting for -DSILENT that the boehm_gc directory was compiled with.
|
|
**
|
|
** We only want to inline allocations if the allocation size is a
|
|
** compile-time constant. This should be true for almost all the code that
|
|
** we generate, but with GCC we can use the `__builtin_constant_p()'
|
|
** extension to find out.
|
|
**
|
|
** The inline allocation macros are used only for allocating amounts
|
|
** of less than 16 words, to avoid fragmenting memory by creating too
|
|
** many distinct free lists. The garbage collector also requires that
|
|
** if we're allocating more than one word, we round up to an even number
|
|
** of words.
|
|
*/
|
|
|
|
#ifndef __GNUC__
|
|
/*
|
|
** Without the gcc extensions __builtin_constant_p() and ({...}),
|
|
** MR_INLINE_ALLOC would probably be a performance _loss_.
|
|
*/
|
|
#error "MR_INLINE_ALLOC requires the use of GCC"
|
|
#endif
|
|
|
|
#include "gc_inl.h"
|
|
#define MR_tag_offset_incr_hp(dest, tag, offset, count) \
|
|
( __builtin_constant_p(count) && (count) < 16 \
|
|
? ({ void * temp; \
|
|
/* if size > 1, round up to an even number of words */ \
|
|
MR_Word num_words = ((count) == 1 ? 1 : \
|
|
2 * (((count) + 1) / 2)); \
|
|
GC_MALLOC_WORDS(temp, num_words); \
|
|
temp = (void *) (((MR_Word *) temp) + (offset)); \
|
|
(dest) = (MR_Word) MR_mkword((tag), temp); \
|
|
}) \
|
|
: MR_tag_offset_incr_hp_n((dest), (tag), (offset), (count)) \
|
|
)
|
|
|
|
#else /* not MR_INLINE_ALLOC */
|
|
|
|
#define MR_tag_offset_incr_hp(dest, tag, offset, count) \
|
|
MR_tag_offset_incr_hp_n((dest), (tag), (offset), (count))
|
|
|
|
#endif /* not MR_INLINE_ALLOC */
|
|
|
|
#define MR_mark_hp(dest) ((void)0)
|
|
#define MR_restore_hp(src) ((void)0)
|
|
|
|
/* we use `MR_hp' as a convenient temporary here */
|
|
#define MR_hp_alloc(count) ( \
|
|
MR_offset_incr_hp(MR_hp_word, 0, (count)), \
|
|
MR_hp_word = (MR_Word) (MR_hp + (count)), \
|
|
(void) 0 \
|
|
)
|
|
#define MR_hp_alloc_atomic(count) ( \
|
|
MR_offset_incr_hp_atomic(MR_hp_word, 0, (count)), \
|
|
MR_hp_word = (MR_Word) (MR_hp + (count)), \
|
|
(void) 0 \
|
|
)
|
|
|
|
#define MR_free_heap(ptr) GC_FREE((ptr))
|
|
|
|
#else /* not MR_CONSERVATIVE_GC */
|
|
|
|
#define MR_tag_offset_incr_hp_base(dest, tag, offset, count, is_atomic) \
|
|
( \
|
|
MR_tag_offset_sanity_check((offset), (count)), \
|
|
(dest) = (MR_Word) MR_mkword(tag, (MR_Word) \
|
|
(((MR_Word *) MR_hp) + (offset))), \
|
|
MR_debug_tag_offset_incr_hp_base((dest), (tag), (offset), \
|
|
(count), (is_atomic)), \
|
|
MR_hp_word = (MR_Word) (MR_hp + (count)), \
|
|
MR_heap_overflow_check(), \
|
|
(void) 0 \
|
|
)
|
|
|
|
#define MR_tag_offset_incr_hp(dest, tag, offset, count) \
|
|
MR_tag_offset_incr_hp_base((dest), (tag), (offset), (count), 0)
|
|
#define MR_tag_offset_incr_hp_atomic(dest, tag, offset, count) \
|
|
MR_tag_offset_incr_hp_base((dest), (tag), (offset), (count), 1)
|
|
|
|
#define MR_mark_hp(dest) ((dest) = MR_hp_word)
|
|
|
|
/*
|
|
** When restoring MR_hp, we must make sure that we don't truncate the heap
|
|
** further than it is safe to. We can only truncate it as far as
|
|
** min_heap_reclamation_point. See the comments in mercury_context.h next to
|
|
** the set_min_heap_reclamation_point() macro.
|
|
*/
|
|
#define MR_restore_hp(src) \
|
|
( \
|
|
MR_hp_word = (MR_Word) (src), \
|
|
(void) 0 \
|
|
)
|
|
|
|
/*
|
|
#define MR_restore_hp(src) \
|
|
( \
|
|
MR_hp_word = (MR_Word)
|
|
( (MR_Word) MR_min_hp_rec < (src) ? \
|
|
(src) : (MR_Word) MR_min_hp_rec ), \
|
|
(void) 0 \
|
|
)
|
|
*/
|
|
|
|
#define MR_hp_alloc(count) MR_offset_incr_hp(MR_hp_word, \
|
|
0, (count))
|
|
#define MR_hp_alloc_atomic(count) MR_offset_incr_hp_atomic(MR_hp_word, \
|
|
0, (count))
|
|
|
|
#define MR_free_heap(ptr) ((void) 0)
|
|
|
|
#endif /* not MR_CONSERVATIVE_GC */
|
|
|
|
#ifdef MR_RECORD_TERM_SIZES
|
|
#define MR_maybe_increment_allocation_counters(count) \
|
|
( \
|
|
MR_complexity_word_counter += (count), \
|
|
MR_complexity_cell_counter += 1 \
|
|
)
|
|
#else
|
|
#define MR_maybe_increment_allocation_counters(count) \
|
|
((void) 0)
|
|
#endif
|
|
|
|
#if defined (MR_DEEP_PROFILING) && defined(MR_DEEP_PROFILING_MEMORY)
|
|
#define MR_prof_record_allocation(count, proclabel, type) \
|
|
( \
|
|
MR_current_call_site_dynamic->MR_csd_own.MR_own_allocs \
|
|
+= 1, \
|
|
MR_current_call_site_dynamic->MR_csd_own.MR_own_words \
|
|
+= (count) \
|
|
)
|
|
#elif defined(MR_MPROF_PROFILE_MEMORY)
|
|
#define MR_prof_record_allocation(count, proclabel, type) \
|
|
MR_record_allocation((count), MR_ENTRY(proclabel), \
|
|
MR_STRINGIFY(proclabel), (type))
|
|
#else
|
|
#define MR_prof_record_allocation(count, proclabel, type) \
|
|
((void) 0)
|
|
#endif
|
|
|
|
#define MR_maybe_record_allocation(count, proclabel, type) \
|
|
( \
|
|
MR_prof_record_allocation((count), proclabel, (type)), \
|
|
MR_maybe_increment_allocation_counters(count) \
|
|
)
|
|
|
|
#define MR_tag_offset_incr_hp_msg(dest, tag, offset, count, proclabel, type) \
|
|
( \
|
|
MR_maybe_record_allocation((count), proclabel, (type)), \
|
|
MR_tag_offset_incr_hp((dest), (tag), (offset), (count)) \
|
|
)
|
|
#define MR_tag_offset_incr_hp_atomic_msg(dest, tag, offset, count, proclabel, type) \
|
|
( \
|
|
MR_maybe_record_allocation((count), proclabel, (type)), \
|
|
MR_tag_offset_incr_hp_atomic((dest), (tag), (offset), (count)) \
|
|
)
|
|
|
|
#define MR_tag_incr_hp(dest, tag, count) \
|
|
MR_tag_offset_incr_hp((dest), (tag), 0, (count))
|
|
#define MR_tag_incr_hp_atomic(dest, tag, count) \
|
|
MR_tag_offset_incr_hp_atomic((dest), (tag), 0, (count))
|
|
#define MR_tag_incr_hp_msg(dest, tag, count, proclabel, type) \
|
|
MR_tag_offset_incr_hp_msg((dest), (tag), 0, (count), \
|
|
proclabel, (type))
|
|
#define MR_tag_incr_hp_atomic_msg(dest, tag, count, proclabel, type) \
|
|
MR_tag_offset_incr_hp_atomic_msg((dest), (tag), 0, (count), \
|
|
proclabel, (type))
|
|
|
|
/*
|
|
** The MR_offset_incr_hp*() macros are defined in terms of the
|
|
** MR_tag_offset_incr_hp*() macros. Note: the `proclabel' argument is not
|
|
** parenthesized, since it must be a label name; we may need to prefix
|
|
** `_entry_' in front of it, which wouldn't work if it was parenthesized.
|
|
*/
|
|
|
|
#define MR_offset_incr_hp(dest, offset, count) \
|
|
MR_tag_offset_incr_hp((dest), MR_mktag(0), (offset), (count))
|
|
#define MR_offset_incr_hp_msg(dest, offset, count, proclabel, type) \
|
|
MR_tag_offset_incr_hp_msg((dest), MR_mktag(0), \
|
|
(offset), (count), proclabel, (type))
|
|
#define MR_offset_incr_hp_atomic(dest, offset, count) \
|
|
MR_tag_offset_incr_hp_atomic((dest), MR_mktag(0), (offset), (count))
|
|
#define MR_offset_incr_hp_atomic_msg(dest, offset, count, proclabel, type) \
|
|
MR_tag_offset_incr_hp_atomic_msg((dest), MR_mktag(0), \
|
|
(offset), (count), proclabel, (type))
|
|
|
|
#ifndef MR_RECORD_TERM_SIZES
|
|
|
|
#define MR_incr_hp(dest, count) \
|
|
MR_offset_incr_hp((dest), 0, (count))
|
|
#define MR_incr_hp_msg(dest, count, proclabel, type) \
|
|
MR_offset_incr_hp_msg((dest), 0, (count), proclabel, (type))
|
|
#define MR_incr_hp_atomic(dest, count) \
|
|
MR_offset_incr_hp_atomic((dest), 0, (count))
|
|
#define MR_incr_hp_atomic_msg(dest, count, proclabel, type) \
|
|
MR_offset_incr_hp_atomic_msg((dest), 0, (count), proclabel, (type))
|
|
|
|
#endif
|
|
|
|
#define MR_incr_hp_type(dest, typename) \
|
|
do { \
|
|
MR_Word tmp; \
|
|
MR_tag_incr_hp(tmp, MR_mktag(0), \
|
|
(MR_bytes_to_words(sizeof(typename)))); \
|
|
(dest) = (typename *) tmp; \
|
|
} while (0)
|
|
#define MR_incr_hp_type_msg(dest, typename, proclabel, type) \
|
|
do { \
|
|
MR_Word tmp; \
|
|
MR_tag_incr_hp_msg(tmp, MR_mktag(0), \
|
|
(MR_bytes_to_words(sizeof(typename))), \
|
|
proclabel, (type)); \
|
|
(dest) = (typename *) tmp; \
|
|
} while (0)
|
|
|
|
#define MR_alloc_heap(dest, count) \
|
|
MR_tag_offset_incr_hp((dest), MR_mktag(0), 0, (count))
|
|
#define MR_tag_alloc_heap(dest, tag, count) \
|
|
MR_tag_offset_incr_hp((dest), MR_mktag(tag), 0, (count))
|
|
|
|
#ifdef MR_HIGHLEVEL_CODE
|
|
|
|
/*
|
|
** Note that this code is also duplicated in mercury.c.
|
|
*/
|
|
|
|
MR_EXTERN_INLINE MR_Word MR_create1_func(MR_Word w1);
|
|
MR_EXTERN_INLINE MR_Word MR_create2_func(MR_Word w1, MR_Word w2);
|
|
MR_EXTERN_INLINE MR_Word MR_create3_func(MR_Word w1, MR_Word w2, MR_Word w3);
|
|
|
|
MR_EXTERN_INLINE MR_Word
|
|
MR_create1_func(MR_Word w1)
|
|
{
|
|
MR_Word *p = (MR_Word *) MR_new_object(MR_Word, 1 * sizeof(MR_Word),
|
|
"create1");
|
|
p[0] = w1;
|
|
return (MR_Word) p;
|
|
}
|
|
|
|
MR_EXTERN_INLINE MR_Word
|
|
MR_create2_func(MR_Word w1, MR_Word w2)
|
|
{
|
|
MR_Word *p = (MR_Word *) MR_new_object(MR_Word, 2 * sizeof(MR_Word),
|
|
"create2");
|
|
p[0] = w1;
|
|
p[1] = w2;
|
|
return (MR_Word) p;
|
|
}
|
|
|
|
MR_EXTERN_INLINE MR_Word
|
|
MR_create3_func(MR_Word w1, MR_Word w2, MR_Word w3)
|
|
{
|
|
MR_Word *p = (MR_Word *) MR_new_object(MR_Word, 3 * sizeof(MR_Word),
|
|
"create3");
|
|
p[0] = w1;
|
|
p[1] = w2;
|
|
p[2] = w3;
|
|
return (MR_Word) p;
|
|
}
|
|
|
|
#define MR_create1(ti1, w1) \
|
|
MR_create1_func((w1))
|
|
#define MR_create2(ti1, w1, ti2, w2) \
|
|
MR_create2_func((w1), (w2))
|
|
#define MR_create3(ti1, w1, ti2, w2, ti3, w3) \
|
|
MR_create3_func((w1), (w2), (w3))
|
|
|
|
#define MR_create1_msg(ti1, w1, proclabel, type) \
|
|
MR_create1((ti1), (w1))
|
|
#define MR_create2_msg(ti1, w1, ti2, w2, proclabel, type) \
|
|
MR_create2((ti1), (w1), (ti2), (w2))
|
|
#define MR_create3_msg(ti1, w1, ti2, w2, ti3, w3, proclabel, type) \
|
|
MR_create3((ti1), (w1), (ti2), (w2), (ti3), (w3))
|
|
|
|
/* term size profiling is not supported with MR_HIGHLEVEL_CODE */
|
|
#define MR_SIZE_SLOT_SIZE 0
|
|
#define MR_cell_size(arity) 0
|
|
#define MR_define_size_slot(ptag, new, size) 0
|
|
#define MR_copy_size_slot(nptag, new, optag, old) 0
|
|
|
|
#else /* ! MR_HIGHLEVEL_CODE */
|
|
|
|
#ifdef MR_RECORD_TERM_SIZES
|
|
#define MR_SIZE_SLOT_SIZE 1
|
|
#ifdef MR_RECORD_TERM_SIZES_AS_CELLS
|
|
#define MR_cell_size(arity) 1
|
|
#else
|
|
#define MR_cell_size(arity) arity
|
|
#endif
|
|
|
|
#define MR_define_size_slot(ptag, new, size) \
|
|
do { \
|
|
MR_field(ptag, new, -1) = size; \
|
|
} while(0)
|
|
#define MR_copy_size_slot(nptag, new, optag, old) \
|
|
do { \
|
|
MR_field(nptag, new, -1) = MR_field(optag, old, -1); \
|
|
} while(0)
|
|
#define MR_fill_create1_size(hp, ti1, w1) \
|
|
( \
|
|
hp[-2] = MR_term_size(ti1, w1) + MR_cell_size(1) \
|
|
)
|
|
#define MR_fill_create2_size(hp, ti1, w1, ti2, w2) \
|
|
( \
|
|
hp[-3] = MR_term_size(ti1, w1) + MR_term_size(ti2, w2) \
|
|
+ MR_cell_size(2) \
|
|
)
|
|
#define MR_fill_create3_size(hp, ti1, w1, ti2, w2, ti3, w3) \
|
|
( \
|
|
hp[-4] = MR_term_size(ti1, w1) + MR_term_size(ti2, w2) \
|
|
+ MR_term_size(ti3, w3) + MR_cell_size(3) \
|
|
)
|
|
#else
|
|
#define MR_SIZE_SLOT_SIZE 0
|
|
#define MR_cell_size(arity) 0
|
|
#define MR_define_size_slot(ptag, new, size) 0
|
|
#define MR_copy_size_slot(nptag, new, optag, old) 0
|
|
#define MR_fill_create1_size(hp, ti1, w1) 0
|
|
#define MR_fill_create2_size(hp, ti1, w1, ti2, w2) 0
|
|
#define MR_fill_create3_size(hp, ti1, w1, ti2, w2, ti3, w3) 0
|
|
#endif
|
|
|
|
/*
|
|
** Note that gcc optimizes `hp += 2; return hp - 2;'
|
|
** to `tmp = hp; hp += 2; return tmp;', so we don't need to use
|
|
** gcc's expression statements in the code below.
|
|
*/
|
|
|
|
/* used only by hand-written code not by the automatically generated code */
|
|
#define MR_create1(ti1, w1) \
|
|
( \
|
|
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 1), \
|
|
MR_hp[-1] = (MR_Word) (w1), \
|
|
MR_fill_create1_size(MR_hp, ti1, w1), \
|
|
MR_debugcr1(MR_hp), \
|
|
/* return */ (MR_Word) (MR_hp - 1) \
|
|
)
|
|
|
|
/* used only by hand-written code not by the automatically generated code */
|
|
#define MR_create2(ti1, w1, ti2, w2) \
|
|
( \
|
|
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 2), \
|
|
MR_hp[-2] = (MR_Word) (w1), \
|
|
MR_hp[-1] = (MR_Word) (w2), \
|
|
MR_fill_create2_size(MR_hp, ti1, w1, ti2, w2), \
|
|
MR_debugcr2(MR_hp), \
|
|
/* return */ (MR_Word) (MR_hp - 2) \
|
|
)
|
|
|
|
/* used only by hand-written code not by the automatically generated code */
|
|
#define MR_create3(ti1, w1, ti2, w2, ti3, w3) \
|
|
( \
|
|
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 3), \
|
|
MR_hp[-3] = (MR_Word) (w1), \
|
|
MR_hp[-2] = (MR_Word) (w2), \
|
|
MR_hp[-1] = (MR_Word) (w3), \
|
|
MR_fill_create3_size(MR_hp, ti1, w1, ti2, w2, ti3, w3), \
|
|
MR_debugcr3(MR_hp), \
|
|
/* return */ (MR_Word) (MR_hp - 3) \
|
|
)
|
|
|
|
/* used only by hand-written code not by the automatically generated code */
|
|
#define MR_create1_msg(ti1, w1, proclabel, type) \
|
|
( \
|
|
MR_maybe_record_allocation(MR_SIZE_SLOT_SIZE + 1, \
|
|
proclabel, (type)), \
|
|
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 1), \
|
|
MR_hp[-1] = (MR_Word) (w1), \
|
|
MR_fill_create1_size(MR_hp, ti1, w1), \
|
|
MR_debugcr1(MR_hp), \
|
|
/* return */ (MR_Word) (MR_hp - 1) \
|
|
)
|
|
|
|
/* used only by hand-written code not by the automatically generated code */
|
|
#define MR_create2_msg(ti1, w1, ti2, w2, proclabel, type) \
|
|
( \
|
|
MR_maybe_record_allocation(MR_SIZE_SLOT_SIZE + 2, \
|
|
proclabel, (type)), \
|
|
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 2), \
|
|
MR_hp[-2] = (MR_Word) (w1), \
|
|
MR_hp[-1] = (MR_Word) (w2), \
|
|
MR_fill_create2_size(MR_hp, ti1, w1, ti2, w2), \
|
|
MR_debugcr2(MR_hp), \
|
|
/* return */ (MR_Word) (MR_hp - 2) \
|
|
)
|
|
|
|
/* used only by hand-written code not by the automatically generated code */
|
|
#define MR_create3_msg(ti1, w1, ti2, w2, ti3, w3, proclabel, type) \
|
|
( \
|
|
MR_maybe_record_allocation(MR_SIZE_SLOT_SIZE + 3, \
|
|
proclabel, (type)), \
|
|
MR_hp_alloc(MR_SIZE_SLOT_SIZE + 3), \
|
|
MR_hp[-3] = (MR_Word) (w1), \
|
|
MR_hp[-2] = (MR_Word) (w2), \
|
|
MR_hp[-1] = (MR_Word) (w3), \
|
|
MR_fill_create3_size(MR_hp, ti1, w1, ti2, w2, ti3, w3), \
|
|
MR_debugcr3(MR_hp), \
|
|
/* return */ (MR_Word) (MR_hp - 3) \
|
|
)
|
|
|
|
#endif /* ! MR_HIGHLEVEL_CODE */
|
|
|
|
/*
|
|
** Indended for use in handwritten C code where the Mercury registers
|
|
** may have been clobbered due to C function calls (eg, on the SPARC due
|
|
** to sliding register windows).
|
|
** Remember to MR_save_transient_hp() before calls to such code, and
|
|
** MR_restore_transient_hp() after.
|
|
**
|
|
** There are intentionally no versions that do not specify an offset;
|
|
** this is to force anyone who wants to allocate cells on the saved heap
|
|
** to think about the impliciations of their code for term size profiling.
|
|
*/
|
|
|
|
#define MR_offset_incr_saved_hp(dest, offset, count) \
|
|
do { \
|
|
MR_restore_transient_hp(); \
|
|
MR_offset_incr_hp((dest), (offset), (count)); \
|
|
MR_save_transient_hp(); \
|
|
} while (0)
|
|
|
|
#define MR_offset_incr_saved_hp_atomic(dest, offset, count) \
|
|
do { \
|
|
MR_restore_transient_hp(); \
|
|
MR_offset_incr_hp_atomic((dest), (offset), (count)); \
|
|
MR_save_transient_hp(); \
|
|
} while (0)
|
|
|
|
/*
|
|
** Code to box/unbox types declared with `pragma foreign_type'.
|
|
*/
|
|
|
|
/*
|
|
** void MR_MAYBE_BOX_FOREIGN_TYPE(type T, const T &value, MR_Box &box);
|
|
** Copy a value of type T from `value' to `box',
|
|
** boxing it if necessary (i.e. if type T won't fit in type MR_Box).
|
|
*/
|
|
#define MR_MAYBE_BOX_FOREIGN_TYPE(T, value, box) \
|
|
do { \
|
|
MR_CHECK_EXPR_TYPE((value), T); \
|
|
MR_CHECK_EXPR_TYPE((box), MR_Box); \
|
|
if (sizeof(T) > sizeof(MR_Box)) { \
|
|
MR_Word box_word; \
|
|
size_t size_in_words = \
|
|
(sizeof(T) + sizeof(MR_Word) - 1) \
|
|
/ sizeof(MR_Word); \
|
|
/* XXX this assumes that nothing requires */ \
|
|
/* stricter alignment than MR_Float */ \
|
|
MR_make_hp_float_aligned(); \
|
|
/* \
|
|
** This assumes that we don't keep term sizes \
|
|
** in grades that use boxes. \
|
|
*/ \
|
|
MR_offset_incr_hp(box_word, 0, size_in_words); \
|
|
box = (MR_Box) box_word; \
|
|
MR_assign_structure(*(T *)(box), (value)); \
|
|
MR_maybe_record_allocation(size_in_words, \
|
|
"", "foreign type: " MR_STRINGIFY(T)); \
|
|
} else { \
|
|
/* We can't take the address of `box' here, */ \
|
|
/* since it might be a global register. */ \
|
|
/* Hence we need to use a temporary copy. */ \
|
|
MR_Box box_copy; \
|
|
if (sizeof(T) < sizeof(MR_Box)) { \
|
|
/* make sure we don't leave any */ \
|
|
/* part of it uninitialized */ \
|
|
box_copy = 0; \
|
|
} \
|
|
MR_memcpy(&box_copy, &(value), sizeof(T)); \
|
|
(box) = box_copy; \
|
|
} \
|
|
} while (0)
|
|
|
|
/*
|
|
** void MR_MAYBE_UNBOX_FOREIGN_TYPE(type T, MR_Box box, T &value);
|
|
** Copy a value of type T from `box' to `value',
|
|
** unboxing it if necessary.
|
|
*/
|
|
#define MR_MAYBE_UNBOX_FOREIGN_TYPE(T, box, value) \
|
|
do { \
|
|
MR_CHECK_EXPR_TYPE((value), T); \
|
|
MR_CHECK_EXPR_TYPE((box), MR_Box); \
|
|
if (sizeof(T) > sizeof(MR_Word)) { \
|
|
MR_assign_structure((value), *(T *)(box)); \
|
|
} else { \
|
|
/* We can't take the address of `box' here, */ \
|
|
/* since it might be a global register. */ \
|
|
/* Hence we need to use a temporary copy. */ \
|
|
MR_Box box_copy = (box); \
|
|
MR_memcpy(&(value), &box_copy, sizeof(T)); \
|
|
} \
|
|
} while (0)
|
|
|
|
#endif /* not MERCURY_HEAP_H */
|