mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-17 14:57:03 +00:00
Estimated hours taken: 24
Branches: main
Introduce a mechanism for extending the det and nondet stacks when needed.
The mechanism takes the form of a new grade component, .exts ("extend stacks").
While the new mechanism may be useful in its own right, it is intended mainly
to support a new implementation of minimal model tabling, which will use a
separate Mercury context for each distinct subgoal. Each context has its own
det and nondet stack. Clearly, we can't have hundreds of contexts each with
megabyte sized det stacks. The intention is that the stacks of the subgoals
will start small, and be expanded when needed.
The runtime expansion of stacks doesn't work yet, but it is unnecessarily
hard to debug without an installed compiler that understands the new grade
component, which is why this diff will be committed before that is fixed.
compiler/handle_options.m:
compiler/options.m:
runtime/mercury_grade.h:
scripts/canonical_grade.sh-subr
scripts/init_grade_options.sh-subr
scripts/parse_grade_options.sh-subr
scripts/mgnuc.in
Handle the new grade component.
runtime/mercury_memory_zones.h:
Add MR_ prefixes to the names of the fields of the zone structure.
Record not just the actual size of each zone, which includes various
kinds of buffers, but also the desired size of the zone exclusive of
buffers.
Format the documentation of the zone structure fields more
comprehensibly.
runtime/mercury_memory_zones.c:
Instead of implementing memalign if it is not provided by the operating
system, implement a function that allows us to reallocate the returned
area of memory.
Provide a prototype implementation of memory zone extension. It doesn't
work yet.
Factor out the code for setting up redzones, since it is now needed
in more than place.
Convert to four space indentation.
Make the debugging functions a bit more flexible.
runtime/mercury_wrapper.c:
Conform to the improved interface of the debugging functions.
runtime/mercury_overflow.h:
runtime/mercury_std.h:
Move a generally useful macro from mercury_overflow.h to mercury_std.h.
runtime/mercury_stacks.c:
Add functions to extend the stacks.
runtime/mercury_stacks.h:
Add the tests required to invoke the functions that extend the stacks.
Add the macros needed by the change to compiler/llds.m.
Convert to four space indentation.
runtime/mercury_conf.h.in:
Prepare for the use of the posix_memalign function, which is the
current replacement of the obsolete memalign library function.
We don't yet use it.
runtime/mercury_context.h:
Format the documentation of the context structure fields more
comprehensibly.
Put MR_ prefixes on the names of the fields of some structures
that didn't previously have them.
Conform to the new names of the fields of the zone structure.
runtime/mercury_context.c:
runtime/mercury_debug.c:
runtime/mercury_deep_copy.c:
runtime/mercury_engine.c:
runtime/mercury_memory_handlers.c:
library/benchmarking.m:
library/exception.m:
Conform to the new names of the fields of the zone structure.
In some cases, add missing MR_ prefixes to function names
and/or convert to four space indentation.
runtime/mercury_engine.h:
Add a new low level debug flag for debugging stack extensions.
Format the documentation of the engine structure fields more
comprehensibly.
Convert to four space indentation.
runtime/mercury_conf_param.h:
Document a new low level debug flag for debugging stack extensions.
compiler/compile_target_code.m:
compiler/handle_options.m:
compiler/options.m:
Handle the new grade component.
compiler/llds.m:
Add two new kinds of LLDS instructions, save_maxfr and restore_maxfr.
These are needed because the nondet stack may be relocated between
saving and the restoring of maxfr, and the saved maxfr may point to
the old stack. In .exts grades, these instructions will save not a
pointer but the offset of maxfr from the start of the nondet stack,
since offsets are not affected by the movement of the nondet stack.
compiler/code_info.m:
Use the new instructions where relevant. (Some more work may be
needed on this score; the relevant places are marked with XXX.)
compiler/dupelim.m:
compiler/dupproc.m:
compiler/exprn_aux.m:
compiler/jumpopt.m:
compiler/livemap.m:
compiler/llds_out.m:
compiler/middle_rec.m:
compiler/opt_debug.m:
compiler/opt_util.m:
compiler/reassign.m:
compiler/use_local_vars.m:
Handle the new LLDS instructions.
tools/bootcheck:
Provide a mechanism for setting the initial stack sizes for a
bootcheck.
303 lines
11 KiB
C
303 lines
11 KiB
C
/*
|
|
** Copyright (C) 1993-1995, 1997-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.
|
|
*/
|
|
|
|
/*
|
|
** std.h - "standard" [sic] definitions for C:
|
|
** MR_bool, MR_TRUE, MR_FALSE, MR_min(), MR_max(), MR_streq(), etc.
|
|
*/
|
|
|
|
#ifndef MERCURY_STD_H
|
|
#define MERCURY_STD_H
|
|
|
|
/*
|
|
** We include mercury_regs.h to ensure we define any global register variables
|
|
** before any functions, even if the system libraries we include below it
|
|
** define any functions.
|
|
*/
|
|
|
|
#include "mercury_regs.h"
|
|
|
|
#include <stdlib.h> /* for size_t */
|
|
#include <assert.h> /* for assert() */
|
|
#include <errno.h> /* for EINTR */
|
|
#ifndef IN_GCC
|
|
#include <ctype.h> /* for isalnum(), etc. */
|
|
#else
|
|
/*
|
|
** When building compiler/gcc.m, we #include GCC back-end
|
|
** header files that include libiberty's "safe-ctype.h",
|
|
** and we can't include both safe-ctype.h and ctype.h,
|
|
** since they conflict, so include safe-ctype.h
|
|
** rather than ctype.h.
|
|
*/
|
|
#include "safe-ctype.h"
|
|
#endif
|
|
|
|
/*
|
|
** The boolean type, MR_bool, with constants MR_TRUE and MR_FALSE.
|
|
**
|
|
** We use `int' rather than `char' for MR_bool, because GCC has problems
|
|
** optimizing tail calls for functions that return types smaller than `int'.
|
|
** In most cases, `int' is more efficient anyway.
|
|
** The only exception is that in some cases it is more important to optimize
|
|
** space rather than time; in those (rare) cases, you can use `MR_small_bool'
|
|
** instead of `MR_bool'.
|
|
*/
|
|
typedef int MR_bool;
|
|
typedef char MR_small_bool;
|
|
|
|
/*
|
|
** The values of MR_TRUE and MR_FALSE should correspond with the representation
|
|
** of the Mercury standard library type bool.bool, so that they can be used as
|
|
** values for bool arguments of exported Mercury procs.
|
|
*/
|
|
|
|
#define MR_TRUE 1
|
|
#define MR_FALSE 0
|
|
|
|
#define MR_YES MR_TRUE
|
|
#define MR_NO MR_FALSE
|
|
|
|
#define MR_max(a, b) ((a) > (b) ? (a) : (b))
|
|
#define MR_min(a, b) ((a) < (b) ? (a) : (b))
|
|
|
|
/*
|
|
** The ANSI C isalnum(), etc. macros require that the argument be cast to
|
|
** `unsigned char'; if you pass a signed char, the behaviour is undefined.
|
|
** Hence we define `MR_' versions of these that do the cast -- you should
|
|
** make sure to always use the `MR_' versions rather than the standard ones.
|
|
*/
|
|
|
|
#define MR_isupper(c) isupper((unsigned char) (c))
|
|
#define MR_islower(c) islower((unsigned char) (c))
|
|
#define MR_isalpha(c) isalpha((unsigned char) (c))
|
|
#define MR_isalnum(c) isalnum((unsigned char) (c))
|
|
#define MR_isdigit(c) isdigit((unsigned char) (c))
|
|
#define MR_isspace(c) isspace((unsigned char) (c))
|
|
#define MR_isalnumunder(c) (isalnum((unsigned char) (c)) || (c) == '_')
|
|
|
|
#define MR_streq(s1, s2) (strcmp(s1, s2) == 0)
|
|
#define MR_strdiff(s1, s2) (strcmp(s1, s2) != 0)
|
|
#define MR_strtest(s1, s2) (strcmp(s1, s2))
|
|
#define MR_strneq(s1, s2, n) (strncmp(s1, s2, n) == 0)
|
|
#define MR_strndiff(s1, s2, n) (strncmp(s1, s2, n) != 0)
|
|
#define MR_strntest(s1, s2, n) (strncmp(s1, s2, n))
|
|
|
|
#define MR_ungetchar(c) ungetc(c, stdin)
|
|
|
|
/*
|
|
** For speed, turn assertions off,
|
|
** unless low-level debugging is enabled.
|
|
*/
|
|
#ifdef MR_LOWLEVEL_DEBUG
|
|
#define MR_assert(ASSERTION) assert(ASSERTION)
|
|
#else
|
|
#define MR_assert(ASSERTION) ((void)0)
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#ifdef EINTR
|
|
#define MR_is_eintr(x) ((x) == EINTR)
|
|
#else
|
|
#define MR_is_eintr(x) MR_FALSE
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** Macros for inlining.
|
|
**
|
|
** Inlining is treated differently by C++, C99, and GNU C.
|
|
** We also need to make it work for C89, which doesn't have
|
|
** any explicit support for inlining.
|
|
**
|
|
** To make a function inline, you should declare it as either
|
|
** `MR_INLINE', `MR_EXTERN_INLINE', or `MR_STATIC_INLINE'.
|
|
** You should not use `extern' or `static' in combination with these macros.
|
|
**
|
|
** `MR_STATIC_INLINE' should be used for functions that are defined and
|
|
** used only in a single translation unit (i.e. a single C source file).
|
|
**
|
|
** If the inline function is to be used from more than one translation unit,
|
|
** then the function definition (not just declaration) should go in
|
|
** a header file, and you should use either MR_INLINE or MR_EXTERN_INLINE;
|
|
** the difference between these two is explained below.
|
|
**
|
|
** MR_INLINE creates an inline definition of the function, and
|
|
** if needed it also creates an out-of-line definition of the function
|
|
** for the current translation unit, in case the function can't be inlined
|
|
** (e.g. because the function's address was taken, or because the
|
|
** file is compiled with the C compiler's optimizations turned off.)
|
|
** For C++, these definitions will be shared between different
|
|
** compilation units, but for C, each compilation unit that needs
|
|
** an out-of-line definition will gets its own definition.
|
|
** Generally that is not much of a problem, but if the C compiler
|
|
** doesn't optimize away such out-of-line definitions when they're
|
|
** not needed, this can get quite bad.
|
|
**
|
|
** MR_EXTERN_INLINE creates an inline definition of the function,
|
|
** but it does NOT guarantee to create an out-of-line definition,
|
|
** even if one might be needed. You need to explicitly provide
|
|
** an out-of-line definition for the function in one of the C files.
|
|
** This should be done using the MR_OUTLINE_DEFN(decl,body) macro,
|
|
** e.g. `MR_OUTLINE_DEFN(int foo(int x), { return x; })'.
|
|
**
|
|
** The advantage of MR_EXTERN_INLINE is that it is more code-space-efficient,
|
|
** especially in the case where you are compiling with C compiler optimizations
|
|
** turned off.
|
|
**
|
|
** It is OK to take the address of an inline function,
|
|
** but you should not assume that the address of a function declared
|
|
** MR_INLINE or MR_EXTERN_INLINE will be the same in all translation units.
|
|
*/
|
|
|
|
#if defined(__cplusplus)
|
|
/* C++ */
|
|
#define MR_STATIC_INLINE static inline
|
|
#define MR_INLINE inline
|
|
#define MR_EXTERN_INLINE inline
|
|
#define MR_OUTLINE_DEFN(DECL,BODY)
|
|
#elif defined(__GNUC__)
|
|
/* GNU C */
|
|
#define MR_STATIC_INLINE static __inline__
|
|
#define MR_INLINE static __inline__
|
|
#define MR_EXTERN_INLINE extern __inline__
|
|
#define MR_OUTLINE_DEFN(DECL,BODY) DECL BODY
|
|
#elif __STDC_VERSION__ >= 199901
|
|
/* C99 */
|
|
#define MR_STATIC_INLINE static inline
|
|
#define MR_INLINE static inline
|
|
#define MR_EXTERN_INLINE inline
|
|
#define MR_OUTLINE_DEFN(DECL,BODY) extern DECL;
|
|
#else
|
|
/* C89 */
|
|
#define MR_STATIC_INLINE static
|
|
#define MR_INLINE static
|
|
#define MR_EXTERN_INLINE static
|
|
#define MR_OUTLINE_DEFN(DECL,BODY)
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/* A macro for declaring functions that never return */
|
|
|
|
#if __GNUC__
|
|
#define MR_NO_RETURN __attribute__((noreturn))
|
|
#else
|
|
#define MR_NO_RETURN
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** MR_CALL:
|
|
** A macro for specifying the calling convention to use
|
|
** for C functions generated by the MLDS back-end
|
|
** (and for builtins such as unification which must use
|
|
** the same calling convention).
|
|
** This can expand to whatever implementation-specific magic
|
|
** is required to tell the C compiler to use a different
|
|
** calling convention.
|
|
**
|
|
** If MR_USE_REGPARM is defined, and we're using gcc on x86,
|
|
** then we use a non-standard but more efficient calling
|
|
** convention that passes parameters in registers.
|
|
** Otherwise we just use the default C calling convention.
|
|
**
|
|
** Any changes here (e.g. adding additional calling conventions,
|
|
** or adding support for other C compilers or other processors)
|
|
** should be reflected in the mangled grade name produced by
|
|
** runtime/mercury_grade.h.
|
|
**
|
|
** It might be slightly more efficient to use __regparm__(3) rather than
|
|
** __regparm__(2), but GCC won't do tail-call optimization for calls via
|
|
** function pointers if we use __regparm__(3), since there may be no spare
|
|
** caller-save registers to hold the function pointer. Tail call
|
|
** optimization is more likely to be important than squeezing the last 1%
|
|
** in performance.
|
|
*/
|
|
#if defined(MR_USE_REGPARM) && defined(__GNUC__) && defined(__i386__)
|
|
#define MR_CALL __attribute__((__stdcall__, __regparm__(2)))
|
|
#else
|
|
#define MR_CALL
|
|
#endif
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** C preprocessor tricks.
|
|
*/
|
|
|
|
/* convert a macro to a string */
|
|
#define MR_STRINGIFY(x) MR_STRINGIFY_2(x)
|
|
#define MR_STRINGIFY_2(x) #x
|
|
|
|
/* paste some macros together */
|
|
#define MR_PASTE2(a,b) MR_PASTE2_2(a,b)
|
|
#define MR_PASTE2_2(a,b) a##b
|
|
#define MR_PASTE3(a,b,c) MR_PASTE3_2(a,b,c)
|
|
#define MR_PASTE3_2(a,b,c) a##b##c
|
|
#define MR_PASTE4(a,b,c,d) MR_PASTE4_2(a,b,c,d)
|
|
#define MR_PASTE4_2(a,b,c,d) a##b##c##d
|
|
#define MR_PASTE5(a,b,c,d,e) MR_PASTE5_2(a,b,c,d,e)
|
|
#define MR_PASTE5_2(a,b,c,d,e) a##b##c##d##e
|
|
#define MR_PASTE6(a,b,c,d,e,f) MR_PASTE6_2(a,b,c,d,e,f)
|
|
#define MR_PASTE6_2(a,b,c,d,e,f) a##b##c##d##e##f
|
|
#define MR_PASTE7(a,b,c,d,e,f,g) MR_PASTE7_2(a,b,c,d,e,f,g)
|
|
#define MR_PASTE7_2(a,b,c,d,e,f,g) a##b##c##d##e##f##g
|
|
#define MR_PASTE8(a,b,c,d,e,f,g,h) MR_PASTE8_2(a,b,c,d,e,f,g,h)
|
|
#define MR_PASTE8_2(a,b,c,d,e,f,g,h) a##b##c##d##e##f##g##h
|
|
#define MR_PASTE9(a,b,c,d,e,f,g,h,i) MR_PASTE9_2(a,b,c,d,e,f,g,h,i)
|
|
#define MR_PASTE9_2(a,b,c,d,e,f,g,h,i) a##b##c##d##e##f##g##h##i
|
|
#define MR_PASTE10(a,b,c,d,e,f,g,h,i,j) MR_PASTE10_2(a,b,c,d,e,f,g,h,i,j)
|
|
#define MR_PASTE10_2(a,b,c,d,e,f,g,h,i,j) a##b##c##d##e##f##g##h##i##j
|
|
#define MR_PASTE11(a,b,c,d,e,f,g,h,i,j,k) \
|
|
MR_PASTE11_2(a,b,c,d,e,f,g,h,i,j,k)
|
|
#define MR_PASTE11_2(a,b,c,d,e,f,g,h,i,j,k) \
|
|
a##b##c##d##e##f##g##h##i##j##k
|
|
#define MR_PASTE12(a,b,c,d,e,f,g,h,i,j,k,l) \
|
|
MR_PASTE12_2(a,b,c,d,e,f,g,h,i,j,k,l)
|
|
#define MR_PASTE12_2(a,b,c,d,e,f,g,h,i,j,k,l) \
|
|
a##b##c##d##e##f##g##h##i##j##k##l
|
|
|
|
/*
|
|
** MR_CHECK_EXPR_TYPE(expr, type):
|
|
** This macro checks that the given expression has a type
|
|
** which is compatible with (assignable to) the specified type,
|
|
** forcing a compile error if it does not.
|
|
** It does not evaluate the expression.
|
|
** Note that the specified type must be a complete type,
|
|
** i.e. it must not be a pointer to a struct which has
|
|
** not been defined.
|
|
**
|
|
** This macro is useful for defining type-safe function-like macros.
|
|
**
|
|
** The implementation of this macro looks like it dereferences
|
|
** a null pointer, but because that code is inside sizeof(), it will
|
|
** not get executed; the compiler will instead just check that it is
|
|
** type-correct.
|
|
*/
|
|
#define MR_CHECK_EXPR_TYPE(expr, type) \
|
|
((void) sizeof(*(type *)NULL = (expr)))
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#define MR_SORRY(msg) MR_fatal_error("Sorry, not yet implemented: " msg);
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
/*
|
|
** MR_IF is for writing if-then-elses that must expand to expressions, not
|
|
** statements.
|
|
*/
|
|
|
|
#define MR_IF(cond, val) ((cond) ? ((val), (void)0) : (void)0)
|
|
|
|
/*---------------------------------------------------------------------------*/
|
|
|
|
#endif /* not MERCURY_STD_H */
|