Files
mercury/runtime/mercury_std.h
Julien Fischer e14f918e63 Delete MR_HAVE_STDINT_H.
The configure script currently contains a check for the presence of the C99
header stdint.h. This is redundant since (1) *all* C compilers that are
currently capable of compiling Mercury support C99 and (2) most #includes of
stdint.h in the Mercury system are not, and have never been, protected by the
MR_HAVE_STDINT_H anyway.

configure.ac:
runtime/mercury_conf.h.in:
    Do not check for stdint.h.

runtime/mercury_std.h:
    Delete the one remaining use of the MR_HAVE_STDINT_H macro.
2023-12-03 00:19:48 +11:00

333 lines
14 KiB
C

// vim: ts=4 sw=4 expandtab ft=c
// Copyright (C) 1993-1995, 1997-2005, 2011-2012 The University of Melbourne.
// Copyright (C) 2014, 2016-2019, 2021-2023 The Mercury team.
// This file is distributed under the terms specified in COPYING.LIB.
// 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 FIRST in order to ensure that
// 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 <stdint.h>
// On Windows we need to define _CRT_RAND_S *before* stdlib.h is included,
// otherwise the declaration for rand_s() will not be visible.
//
#if defined(MR_WIN32) && !defined(_CRT_RAND_S)
#define _CRT_RAND_S
#endif
#include <stdlib.h> // for size_t
#include <assert.h> // for assert()
#include <errno.h> // for EINTR
#include <ctype.h> // for isalnum(), etc.
// 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 debugging of the runtime is enabled.
#ifdef MR_DEBUG_THE_RUNTIME
#define MR_assert(ASSERTION) assert(ASSERTION)
#elif defined(MR_MSVC)
// This marks an MR_assert(0) as an unreachable branch. This also silences
// warnings about unused variables, and also can improve optimization.
#define MR_assert(ASSERTION) __assume(ASSERTION)
#else
// Using sizeof ensures that the argument to MR_assert is valid, but does
// not actually execute any code. This helps prevent bitrot when code is
// not tested with assertions enabled.
#define MR_assert(ASSERTION) ((void) sizeof(ASSERTION))
#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)
#if __STDC_VERSION__ >= 199901
// 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
// C89: note that by default we use clang in C99 mode, so this alternative
// will only be used if user explicitly sets -std to use something prior
// to C99.
#define MR_STATIC_INLINE static
#define MR_INLINE static
#define MR_EXTERN_INLINE static
#define MR_OUTLINE_DEFN(DECL,BODY)
#endif
#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 was defined, and we were using gcc on x86,
// then we USED to use a non-standard but more efficient calling convention
// that passes parameters in registers. Otherwise we just used the default
// C calling convention.
//
// However, since 32-bit x86s are rare these days, and this non-standard
// calling convention is *slower* on x86/64 platforms than the standard one,
// we don't do this anymore.
#define MR_CALL
////////////////////////////////////////////////////////////////////////////
// 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)))
// MR_STATIC_ASSERT(module, expr):
// Assert at compile time that the given expression is true.
// A named bit-field may not have zero width.
#define MR_STATIC_ASSERT(module, expr) \
struct MR_PASTE4(static_assert_, module, _line_, __LINE__) \
{ unsigned int bf : !!(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)
////////////////////////////////////////////////////////////////////////////
// This macro is needed by both mercury_float.h and mercury_int.h.
#if defined(MR_DEBUG_DWORD_ALIGNMENT) && \
(defined(MR_GNUC) || defined(MR_CLANG))
#define MR_dword_ptr(ptr) \
({ \
MR_Word __addr = (MR_Word) (ptr); \
assert((__addr % 8) == 0); \
/* return */ (void *) __addr; \
})
#else
#define MR_dword_ptr(ptr) ((void *) (ptr))
#endif
////////////////////////////////////////////////////////////////////////////
#endif // not MERCURY_STD_H