mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-12 04:14:06 +00:00
Branches: main, 11.07 Fix a problem with the runtime when using GCC in C99 mode. runtime/mercury_std.h: GCC uses the C99 semantics for inline functions when it is in C99 mode, we need to too.
331 lines
12 KiB
C
331 lines
12 KiB
C
/*
|
|
** Copyright (C) 1993-1995, 1997-2005, 2011-2012 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(MR_CLANG)
|
|
/* clang: note that since clang also defines the macro __GNUC__
|
|
** we must handle it before we handle the GCC case.
|
|
** XXX why don't the C99 definitions work for clang?
|
|
*/
|
|
#define MR_STATIC_INLINE static
|
|
#define MR_INLINE static
|
|
#define MR_EXTERN_INLINE static
|
|
#define MR_OUTLINE_DEFN(DECL,BODY)
|
|
#elif defined(MR_GNUC)
|
|
/* GNU C: in (GNU) C99 or later mode GCC will use C99 style
|
|
** inline functions; otherwise GNU style inline functions will
|
|
** will be used.
|
|
*/
|
|
#if defined(__GNUC_STDC_INLINE__)
|
|
/* C99 style inlining. */
|
|
#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
|
|
/* GNU C90 style inlining. */
|
|
#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
|
|
#endif /* ! __GNUC_STDC_INLINE */
|
|
#elif defined(MR_MSVC)
|
|
#define MR_STATIC_INLINE static __inline
|
|
#define MR_INLINE static __inline
|
|
#define MR_EXTERN_INLINE extern __inline
|
|
#define MR_OUTLINE_DEFN(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 defined(MR_GNUC) || defined(MR_CLANG)
|
|
#define MR_NO_RETURN(x) x __attribute__((noreturn))
|
|
#elif defined(MR_MSVC)
|
|
#define MR_NO_RETURN(x) __declspec(noreturn) x
|
|
#else
|
|
#define MR_NO_RETURN(x) x
|
|
#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(MR_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 */
|